mirror of
https://github.com/correl/mage.git
synced 2024-12-24 11:50:45 +00:00
* Added getProducableManaTypes method for mana effects to handle Squandered Resources or Reflecting Pool like abilities.
* Fixes to Soldevi Adnate, Skirge Familiar, Mana Web.
This commit is contained in:
parent
121e1043ab
commit
67dd45c1c7
25 changed files with 420 additions and 404 deletions
|
@ -3,7 +3,6 @@ package mage.cards.k;
|
|||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||
import mage.abilities.effects.RestrictionEffect;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
|
@ -119,14 +118,12 @@ class KatabaticWindsRuleModifyingEffect extends ContinuousRuleModifyingEffectImp
|
|||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
MageObject object = game.getObject(event.getSourceId());
|
||||
Optional<Ability> ability = game.getAbility(event.getTargetId(), event.getSourceId());
|
||||
if (ability.isPresent()
|
||||
return ability.isPresent()
|
||||
&& object != null
|
||||
&& object.isCreature()
|
||||
&& object.getAbilities().contains(FlyingAbility.getInstance())
|
||||
&& game.getState().getPlayersInRange(source.getControllerId(), game).contains(event.getPlayerId())) {
|
||||
return ability.get().getCosts().stream().anyMatch((cost) -> (cost instanceof TapSourceCost));
|
||||
}
|
||||
return false;
|
||||
&& game.getState().getPlayersInRange(source.getControllerId(), game).contains(event.getPlayerId())
|
||||
&& ability.get().hasTapCost();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -66,10 +66,8 @@ class HasAbilityWithTapSymbolPredicate implements Predicate<MageObject> {
|
|||
|
||||
for (Ability ability : abilities) {
|
||||
if ((ability.getAbilityType() == AbilityType.ACTIVATED || ability.getAbilityType() == AbilityType.MANA) && !ability.getCosts().isEmpty()) {
|
||||
for (Cost cost : ability.getCosts()) {
|
||||
if (cost instanceof TapSourceCost) {
|
||||
if (ability.hasTapCost()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,15 +2,18 @@
|
|||
package mage.cards.m;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
||||
import mage.abilities.mana.AnyColorLandsProduceManaAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.ManaType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterLandPermanent;
|
||||
|
@ -61,6 +64,9 @@ class ManaWebTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (game.inCheckPlayableState()) {
|
||||
return false;
|
||||
}
|
||||
if (game.getOpponents(controllerId).contains(event.getPlayerId())) {
|
||||
Permanent permanent = game.getPermanent(event.getSourceId());
|
||||
|
||||
|
@ -103,35 +109,19 @@ class ManaWebeffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = null;
|
||||
|
||||
if (game != null && source != null) {
|
||||
permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||
}
|
||||
|
||||
if (permanent != null && game != null) {
|
||||
Mana mana = new Mana();
|
||||
|
||||
for (ActivatedManaAbilityImpl ability : permanent.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD)) {
|
||||
for (Mana netMana : ability.getNetMana(game)) {
|
||||
mana.add(netMana);
|
||||
}
|
||||
}
|
||||
|
||||
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||
if (permanent != null) {
|
||||
Set<ManaType> manaTypesSource = AnyColorLandsProduceManaAbility.getManaTypesFromPermanent(permanent, game);
|
||||
boolean tappedLands = false;
|
||||
for (Permanent opponentPermanent : game.getBattlefield().getActivePermanents(filter, permanent.getControllerId(), game)) {
|
||||
if (Objects.equals(opponentPermanent.getControllerId(), permanent.getControllerId())) {
|
||||
Mana opponentLandMana = new Mana();
|
||||
|
||||
for (ActivatedManaAbilityImpl ability : opponentPermanent.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, game)) {
|
||||
for (Mana netMana : ability.getNetMana(game)) {
|
||||
opponentLandMana.add(netMana);
|
||||
Set<ManaType> manaTypes = AnyColorLandsProduceManaAbility.getManaTypesFromPermanent(opponentPermanent, game);
|
||||
for (ManaType manaType : manaTypes) {
|
||||
if (manaTypesSource.contains(manaType)) {
|
||||
tappedLands = opponentPermanent.tap(game) || tappedLands;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mana.containsAny(opponentLandMana, true)) {
|
||||
tappedLands = opponentPermanent.tap(game) || tappedLands;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tappedLands;
|
||||
|
|
|
@ -3,8 +3,6 @@ package mage.cards.p;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.effects.common.GainLifeEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
@ -25,7 +23,7 @@ public final class Powerleech extends CardImpl {
|
|||
public Powerleech(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}{G}");
|
||||
|
||||
// Whenever an artifact an opponent controls becomes tapped or an opponent activates an artifact's ability without {tap} in its activation cost, you gain 1 life.
|
||||
// Whenever an artifact an opponent controls becomes tapped or an opponent activates an artifact's ability without {T} in its activation cost, you gain 1 life.
|
||||
this.addAbility(new PowerleechTriggeredAbility());
|
||||
}
|
||||
|
||||
|
@ -75,17 +73,8 @@ class PowerleechTriggeredAbility extends TriggeredAbilityImpl {
|
|||
if (stackAbility == null) {
|
||||
return false;
|
||||
}
|
||||
boolean triggerable = true;
|
||||
for (Cost cost : stackAbility.getCosts()) {
|
||||
if (cost instanceof TapSourceCost) {
|
||||
triggerable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!triggerable) {
|
||||
return false;
|
||||
}
|
||||
return player.hasOpponent(permanent.getControllerId(), game);
|
||||
return !stackAbility.hasTapCost()
|
||||
&& player.hasOpponent(permanent.getControllerId(), game);
|
||||
}
|
||||
if (event.getType() == GameEvent.EventType.TAPPED) {
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId());
|
||||
|
|
|
@ -7,7 +7,6 @@ import mage.MageObject;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
|
@ -104,16 +103,12 @@ class SerraBestiaryRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl
|
|||
}
|
||||
MageObject object = game.getObject(event.getSourceId());
|
||||
Optional<Ability> ability = game.getAbility(event.getTargetId(), event.getSourceId());
|
||||
if (ability.isPresent()
|
||||
return ability.isPresent()
|
||||
&& object != null
|
||||
&& object.isCreature()
|
||||
&& object.getId().equals(enchantedCreature.getId())
|
||||
&& game.getState().getPlayersInRange(source.getControllerId(), game).contains(event.getPlayerId())) {
|
||||
if (ability.get().getCosts().stream().anyMatch((cost) -> (cost instanceof TapSourceCost))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
&& game.getState().getPlayersInRange(source.getControllerId(), game).contains(event.getPlayerId())
|
||||
&& ability.get().hasTapCost();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -5,6 +5,8 @@ import java.util.UUID;
|
|||
import mage.MageInt;
|
||||
import mage.Mana;
|
||||
import mage.abilities.costs.common.DiscardCardCost;
|
||||
import mage.abilities.dynamicvalue.IntPlusDynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.CardsInControllerHandCount;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.abilities.mana.SimpleManaAbility;
|
||||
import mage.cards.CardImpl;
|
||||
|
@ -29,7 +31,13 @@ public final class SkirgeFamiliar extends CardImpl {
|
|||
this.addAbility(FlyingAbility.getInstance());
|
||||
|
||||
// Discard a card: Add {B}.
|
||||
this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.BlackMana(1), new DiscardCardCost(false)));
|
||||
// public SimpleManaAbility(Zone zone, Mana mana, Cost cost, DynamicValue netAmount) {
|
||||
this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.BlackMana(1),
|
||||
new DiscardCardCost(false),
|
||||
// not perfect but for hand cards correct, activated abilities on Battlefield will miss one possible available mana
|
||||
// to solve this we have to do possible mana calculation per pell/ability to use.
|
||||
new IntPlusDynamicValue(-1, CardsInControllerHandCount.instance)
|
||||
));
|
||||
}
|
||||
|
||||
public SkirgeFamiliar(final SkirgeFamiliar card) {
|
||||
|
|
|
@ -7,6 +7,8 @@ import mage.Mana;
|
|||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.common.SacrificeTargetCost;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.dynamicvalue.common.HighestCMCOfPermanentValue;
|
||||
import mage.abilities.dynamicvalue.common.SacrificeCostConvertedMana;
|
||||
import mage.abilities.mana.DynamicManaAbility;
|
||||
import mage.cards.CardImpl;
|
||||
|
@ -38,8 +40,9 @@ public final class SoldeviAdnate extends CardImpl {
|
|||
this.toughness = new MageInt(2);
|
||||
|
||||
// {T}, Sacrifice a black or artifact creature: Add an amount of {B} equal to the sacrificed creature's converted mana cost.
|
||||
Ability ability = new DynamicManaAbility(Mana.BlackMana(1), new SacrificeCostConvertedMana("creature"),
|
||||
"add an amount of {B} equal to the sacrificed creature's converted mana cost");
|
||||
Ability ability = new DynamicManaAbility(Mana.BlackMana(1), new SacrificeCostConvertedMana("creature"), new TapSourceCost(),
|
||||
"add an amount of {B} equal to the sacrificed creature's converted mana cost" , false,
|
||||
new HighestCMCOfPermanentValue(filter, true));
|
||||
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter)));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ import mage.cards.CardSetInfo;
|
|||
import mage.choices.Choice;
|
||||
import mage.choices.ChoiceColor;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.ColoredManaSymbol;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterControlledLandPermanent;
|
||||
import mage.filter.common.FilterControlledPermanent;
|
||||
|
@ -23,8 +22,13 @@ import mage.players.Player;
|
|||
import mage.target.common.TargetControlledPermanent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.mana.AnyColorLandsProduceManaAbility;
|
||||
import mage.constants.ManaType;
|
||||
import mage.filter.StaticFilters;
|
||||
|
||||
/**
|
||||
* @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
|
||||
|
@ -64,24 +68,35 @@ class SquanderedResourcesEffect extends ManaEffect {
|
|||
@Override
|
||||
public List<Mana> getNetMana(Game game, Ability source) {
|
||||
List<Mana> netManas = new ArrayList<>();
|
||||
Mana types = getManaTypes(game, source);
|
||||
if (types.getBlack() > 0) {
|
||||
netManas.add(new Mana(ColoredManaSymbol.B));
|
||||
Set<ManaType> manaTypes = new HashSet<>();
|
||||
if (game != null && game.inCheckPlayableState()) {
|
||||
for (Permanent land : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), game)) {
|
||||
manaTypes.addAll(AnyColorLandsProduceManaAbility.getManaTypesFromPermanent(land, game));
|
||||
}
|
||||
} else {
|
||||
manaTypes = getManaTypesFromSacrificedPermanent(game, source);
|
||||
}
|
||||
if (types.getRed() > 0) {
|
||||
netManas.add(new Mana(ColoredManaSymbol.R));
|
||||
}
|
||||
if (types.getBlue() > 0) {
|
||||
netManas.add(new Mana(ColoredManaSymbol.U));
|
||||
}
|
||||
if (types.getGreen() > 0) {
|
||||
netManas.add(new Mana(ColoredManaSymbol.G));
|
||||
}
|
||||
if (types.getWhite() > 0) {
|
||||
netManas.add(new Mana(ColoredManaSymbol.W));
|
||||
}
|
||||
if (types.getGeneric() > 0) {
|
||||
netManas.add(Mana.ColorlessMana(1));
|
||||
if (manaTypes.size() == 5 && !manaTypes.contains(ManaType.COLORLESS) && !manaTypes.contains(ManaType.GENERIC)) {
|
||||
netManas.add(Mana.AnyMana(1));
|
||||
} else {
|
||||
if (manaTypes.contains(ManaType.BLACK)) {
|
||||
netManas.add(Mana.BlackMana(1));
|
||||
}
|
||||
if (manaTypes.contains(ManaType.RED)) {
|
||||
netManas.add(Mana.RedMana(1));
|
||||
}
|
||||
if (manaTypes.contains(ManaType.BLUE)) {
|
||||
netManas.add(Mana.BlueMana(1));
|
||||
}
|
||||
if (manaTypes.contains(ManaType.GREEN)) {
|
||||
netManas.add(Mana.GreenMana(1));
|
||||
}
|
||||
if (manaTypes.contains(ManaType.WHITE)) {
|
||||
netManas.add(Mana.WhiteMana(1));
|
||||
}
|
||||
if (manaTypes.contains(ManaType.COLORLESS)) {
|
||||
netManas.add(Mana.ColorlessMana(1));
|
||||
}
|
||||
}
|
||||
return netManas;
|
||||
}
|
||||
|
@ -92,34 +107,26 @@ class SquanderedResourcesEffect extends ManaEffect {
|
|||
if (game == null) {
|
||||
return mana;
|
||||
}
|
||||
Mana types = getManaTypes(game, source);
|
||||
Set<ManaType> manaTypes = getManaTypesFromSacrificedPermanent(game, source);
|
||||
Choice choice = new ChoiceColor(true);
|
||||
choice.getChoices().clear();
|
||||
choice.setMessage("Pick a mana color");
|
||||
if (types.getBlack() > 0) {
|
||||
if (manaTypes.contains(ManaType.BLACK)) {
|
||||
choice.getChoices().add("Black");
|
||||
}
|
||||
if (types.getRed() > 0) {
|
||||
if (manaTypes.contains(ManaType.RED)) {
|
||||
choice.getChoices().add("Red");
|
||||
}
|
||||
if (types.getBlue() > 0) {
|
||||
if (manaTypes.contains(ManaType.BLUE)) {
|
||||
choice.getChoices().add("Blue");
|
||||
}
|
||||
if (types.getGreen() > 0) {
|
||||
if (manaTypes.contains(ManaType.GREEN)) {
|
||||
choice.getChoices().add("Green");
|
||||
}
|
||||
if (types.getWhite() > 0) {
|
||||
if (manaTypes.contains(ManaType.WHITE)) {
|
||||
choice.getChoices().add("White");
|
||||
}
|
||||
if (types.getColorless() > 0) {
|
||||
choice.getChoices().add("Colorless");
|
||||
}
|
||||
if (types.getAny() > 0) {
|
||||
choice.getChoices().add("Black");
|
||||
choice.getChoices().add("Red");
|
||||
choice.getChoices().add("Blue");
|
||||
choice.getChoices().add("Green");
|
||||
choice.getChoices().add("White");
|
||||
if (manaTypes.contains(ManaType.COLORLESS)) {
|
||||
choice.getChoices().add("Colorless");
|
||||
}
|
||||
if (!choice.getChoices().isEmpty()) {
|
||||
|
@ -158,20 +165,14 @@ class SquanderedResourcesEffect extends ManaEffect {
|
|||
return mana;
|
||||
}
|
||||
|
||||
private Mana getManaTypes(Game game, Ability source) {
|
||||
Mana types = new Mana();
|
||||
private Set<ManaType> getManaTypesFromSacrificedPermanent(Game game, Ability source) {
|
||||
Set<ManaType> types = new HashSet<>();
|
||||
for (Cost cost : source.getCosts()) {
|
||||
if (cost instanceof SacrificeTargetCost && !((SacrificeTargetCost) cost).getPermanents().isEmpty()) {
|
||||
Permanent land = ((SacrificeTargetCost) cost).getPermanents().get(0);
|
||||
if (land != null) {
|
||||
Abilities<ActivatedManaAbilityImpl> manaAbilities = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD);
|
||||
for (ActivatedManaAbilityImpl ability : manaAbilities) {
|
||||
if (!ability.equals(source) && ability.definesMana(game)) {
|
||||
for (Mana netMana : ability.getNetMana(game)) {
|
||||
types.add(netMana);
|
||||
}
|
||||
}
|
||||
}
|
||||
types.addAll(AnyColorLandsProduceManaAbility.getManaTypesFromPermanent(land, game));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,43 +1,34 @@
|
|||
package mage.cards.s;
|
||||
|
||||
import mage.Mana;
|
||||
import mage.abilities.Abilities;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldTappedAbility;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.effects.common.ManaEffect;
|
||||
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
||||
import mage.abilities.mana.SimpleManaAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.choices.Choice;
|
||||
import mage.choices.ChoiceColor;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.ColoredManaSymbol;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterControlledLandPermanent;
|
||||
import mage.filter.common.FilterControlledPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.mana.AnyColorLandsProduceManaAbility;
|
||||
import mage.constants.TargetController;
|
||||
|
||||
/**
|
||||
* @author anonymous
|
||||
*/
|
||||
public final class StarCompass extends CardImpl {
|
||||
|
||||
private static final FilterControlledPermanent filter = new FilterControlledLandPermanent();
|
||||
|
||||
static {
|
||||
filter.add(SuperType.BASIC.getPredicate());
|
||||
}
|
||||
|
||||
public StarCompass(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
|
||||
|
||||
// Star Compass enters the battlefield tapped.
|
||||
this.addAbility(new EntersBattlefieldTappedAbility());
|
||||
// {tap}: Add one mana of any color that a basic land you control could produce.
|
||||
this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new StarCompassManaEffect(), new TapSourceCost()));
|
||||
// {T}: Add one mana of any color that a basic land you control could produce.
|
||||
this.addAbility(new AnyColorLandsProduceManaAbility(TargetController.YOU, true, filter));
|
||||
}
|
||||
|
||||
public StarCompass(final StarCompass card) {
|
||||
|
@ -48,144 +39,4 @@ public final class StarCompass extends CardImpl {
|
|||
public StarCompass copy() {
|
||||
return new StarCompass(this);
|
||||
}
|
||||
}
|
||||
|
||||
class StarCompassManaEffect extends ManaEffect {
|
||||
|
||||
private static final FilterControlledPermanent filter = new FilterControlledLandPermanent();
|
||||
|
||||
static {
|
||||
filter.add(SuperType.BASIC.getPredicate());
|
||||
}
|
||||
|
||||
public StarCompassManaEffect() {
|
||||
super();
|
||||
staticText = "Add one mana of any type that a basic land you control could produce";
|
||||
}
|
||||
|
||||
public StarCompassManaEffect(final StarCompassManaEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Mana> getNetMana(Game game, Ability source) {
|
||||
List<Mana> netManas = new ArrayList<>();
|
||||
Mana types = getManaTypes(game, source);
|
||||
if (types.getBlack() > 0) {
|
||||
netManas.add(new Mana(ColoredManaSymbol.B));
|
||||
}
|
||||
if (types.getRed() > 0) {
|
||||
netManas.add(new Mana(ColoredManaSymbol.R));
|
||||
}
|
||||
if (types.getBlue() > 0) {
|
||||
netManas.add(new Mana(ColoredManaSymbol.U));
|
||||
}
|
||||
if (types.getGreen() > 0) {
|
||||
netManas.add(new Mana(ColoredManaSymbol.G));
|
||||
}
|
||||
if (types.getWhite() > 0) {
|
||||
netManas.add(new Mana(ColoredManaSymbol.W));
|
||||
}
|
||||
if (types.getGeneric() > 0) {
|
||||
netManas.add(Mana.ColorlessMana(1));
|
||||
}
|
||||
return netManas;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mana produceMana(Game game, Ability source) {
|
||||
Mana mana = new Mana();
|
||||
if (game == null) {
|
||||
return mana;
|
||||
}
|
||||
Mana types = getManaTypes(game, source);
|
||||
Choice choice = new ChoiceColor(true);
|
||||
choice.getChoices().clear();
|
||||
choice.setMessage("Pick a mana color");
|
||||
if (types.getBlack() > 0) {
|
||||
choice.getChoices().add("Black");
|
||||
}
|
||||
if (types.getRed() > 0) {
|
||||
choice.getChoices().add("Red");
|
||||
}
|
||||
if (types.getBlue() > 0) {
|
||||
choice.getChoices().add("Blue");
|
||||
}
|
||||
if (types.getGreen() > 0) {
|
||||
choice.getChoices().add("Green");
|
||||
}
|
||||
if (types.getWhite() > 0) {
|
||||
choice.getChoices().add("White");
|
||||
}
|
||||
if (types.getColorless() > 0) {
|
||||
choice.getChoices().add("Colorless");
|
||||
}
|
||||
if (types.getAny() > 0) {
|
||||
choice.getChoices().add("Black");
|
||||
choice.getChoices().add("Red");
|
||||
choice.getChoices().add("Blue");
|
||||
choice.getChoices().add("Green");
|
||||
choice.getChoices().add("White");
|
||||
choice.getChoices().add("Colorless");
|
||||
}
|
||||
if (!choice.getChoices().isEmpty()) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player == null) {
|
||||
return null;
|
||||
}
|
||||
if (choice.getChoices().size() == 1) {
|
||||
choice.setChoice(choice.getChoices().iterator().next());
|
||||
} else {
|
||||
if (!player.choose(outcome, choice, game)) {
|
||||
return mana;
|
||||
}
|
||||
}
|
||||
if (choice.getChoice() != null) {
|
||||
switch (choice.getChoice()) {
|
||||
case "Black":
|
||||
mana.setBlack(1);
|
||||
break;
|
||||
case "Blue":
|
||||
mana.setBlue(1);
|
||||
break;
|
||||
case "Red":
|
||||
mana.setRed(1);
|
||||
break;
|
||||
case "Green":
|
||||
mana.setGreen(1);
|
||||
break;
|
||||
case "White":
|
||||
mana.setWhite(1);
|
||||
break;
|
||||
case "Colorless":
|
||||
mana.setColorless(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return mana;
|
||||
}
|
||||
|
||||
private Mana getManaTypes(Game game, Ability source) {
|
||||
Mana types = new Mana();
|
||||
if (game != null) {
|
||||
List<Permanent> lands = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game);
|
||||
for (Permanent land : lands) {
|
||||
Abilities<ActivatedManaAbilityImpl> manaAbilities = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD);
|
||||
for (ActivatedManaAbilityImpl ability : manaAbilities) {
|
||||
if (!ability.equals(source) && ability.definesMana(game)) {
|
||||
for (Mana netMana : ability.getNetMana(game)) {
|
||||
types.add(netMana);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StarCompassManaEffect copy() {
|
||||
return new StarCompassManaEffect(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -201,4 +201,58 @@ public class NonTappingManaAbilitiesTest extends CardTestPlayerBase {
|
|||
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
|
||||
assertManaOptions("{R}{R}{R}", manaOptions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestSquanderedResources() {
|
||||
setStrictChooseMode(true);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Taiga", 1); // ({T}: Add {R} or {G}.)
|
||||
// {T}: Add {C}.
|
||||
// {1}, {T}: Put a storage counter on Calciform Pools.
|
||||
// {1}, Remove X storage counters from Calciform Pools: Add X mana in any combination of {W} and/or {U}.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Calciform Pools", 1);
|
||||
// {T}: Add {U}. If you played a land this turn, add {B} instead.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "River of Tears", 1);
|
||||
|
||||
|
||||
// Sacrifice a land: Add one mana of any type the sacrificed land could produce.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Squandered Resources", 1);
|
||||
|
||||
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertAllCommandsUsed();
|
||||
|
||||
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
|
||||
Assert.assertEquals("mana variations don't fit", 9, manaOptions.size());
|
||||
assertManaOptions("{C}{U}{R}{R}{G}", manaOptions);
|
||||
assertManaOptions("{C}{U}{U}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{U}{U}{R}{G}", manaOptions);
|
||||
assertManaOptions("{C}{U}{G}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{U}{R}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{W}{U}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{W}{U}{R}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{U}{G}{G}", manaOptions);
|
||||
assertManaOptions("{C}{C}{U}{R}{G}", manaOptions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestSquanderedResourcesWithManaConfluence() {
|
||||
setStrictChooseMode(true);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||
// {T}, Pay 1 life: Add one mana of any color.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mana Confluence", 1);
|
||||
|
||||
// Sacrifice a land: Add one mana of any type the sacrificed land could produce.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Squandered Resources", 1);
|
||||
|
||||
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertAllCommandsUsed();
|
||||
|
||||
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
|
||||
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
|
||||
assertManaOptions("{G}{Any}{Any}", manaOptions);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -288,8 +288,27 @@ public class ReflectingPoolTest extends CardTestPlayerBase {
|
|||
execute();
|
||||
|
||||
ManaOptions options = playerA.getAvailableManaTest(currentGame);
|
||||
Assert.assertEquals("Player A should be able to create only 3 different mana options", 2, options.size());
|
||||
Assert.assertEquals("Player A should be able to create only 2 different mana options", 2, options.size());
|
||||
assertManaOptions("{C}{C}{Any}", options);
|
||||
assertManaOptions("{C}{Any}{Any}", options);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithCalciformPools() {
|
||||
// {T}: Add {C}.
|
||||
// {1}, {T}: Put a storage counter on Calciform Pools.
|
||||
// {1}, Remove X storage counters from Calciform Pools: Add X mana in any combination of {W} and/or {U}.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Calciform Pools", 1);
|
||||
// {T}: Add one mana of any type that a land you control could produce.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Reflecting Pool", 1);
|
||||
|
||||
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
ManaOptions options = playerA.getAvailableManaTest(currentGame);
|
||||
Assert.assertEquals("Player A should be able to create only 3 different mana options", 3, options.size());
|
||||
assertManaOptions("{C}{C}", options);
|
||||
assertManaOptions("{C}{W}", options);
|
||||
assertManaOptions("{C}{U}", options);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -321,9 +321,11 @@ public class ManaOptionsTest extends CardTestPlayerBase {
|
|||
execute();
|
||||
|
||||
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
|
||||
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
|
||||
Assert.assertEquals("mana variations don't fit", 3, manaOptions.size());
|
||||
assertDuplicatedManaOptions(manaOptions);
|
||||
assertManaOptions("{C}{C}", manaOptions);
|
||||
assertManaOptions("{Any}{Any}", manaOptions);
|
||||
assertManaOptions("{C}{Any}", manaOptions);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -170,39 +170,22 @@ public abstract class MageObjectImpl implements MageObject {
|
|||
// its frame colors.
|
||||
if (this.isLand()) {
|
||||
ObjectColor cl = frameColor.copy();
|
||||
Set<ManaType> manaTypes = EnumSet.noneOf(ManaType.class);
|
||||
for (Ability ab : getAbilities()) {
|
||||
if (ab instanceof ActivatedManaAbilityImpl) {
|
||||
ActivatedManaAbilityImpl mana = (ActivatedManaAbilityImpl) ab;
|
||||
try {
|
||||
List<Mana> manaAdded = mana.getNetMana(game);
|
||||
for (Mana m : manaAdded) {
|
||||
if (m.getAny() > 0) {
|
||||
return new ObjectColor("WUBRG");
|
||||
}
|
||||
if (m.getWhite() > 0) {
|
||||
cl.setWhite(true);
|
||||
}
|
||||
if (m.getBlue() > 0) {
|
||||
cl.setBlue(true);
|
||||
}
|
||||
if (m.getBlack() > 0) {
|
||||
cl.setBlack(true);
|
||||
}
|
||||
if (m.getRed() > 0) {
|
||||
cl.setRed(true);
|
||||
}
|
||||
if (m.getGreen() > 0) {
|
||||
cl.setGreen(true);
|
||||
}
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
// Ability depends on game
|
||||
// but no game passed
|
||||
// All such abilities are 5-color ones
|
||||
return new ObjectColor("WUBRG");
|
||||
}
|
||||
manaTypes.addAll(((ActivatedManaAbilityImpl) ab).getProducableManaTypes(game));
|
||||
}
|
||||
}
|
||||
cl.setWhite(manaTypes.contains(ManaType.WHITE));
|
||||
cl.setBlue(manaTypes.contains(ManaType.BLUE));
|
||||
cl.setBlack(manaTypes.contains(ManaType.BLACK));
|
||||
cl.setRed(manaTypes.contains(ManaType.RED));
|
||||
cl.setGreen(manaTypes.contains(ManaType.GREEN));
|
||||
|
||||
// // Ability depends on game
|
||||
// // but no game passed
|
||||
// // All such abilities are 5-color ones
|
||||
// return new ObjectColor("WUBRG");
|
||||
return cl;
|
||||
} else {
|
||||
// For everything else, just return the frame colors
|
||||
|
|
|
@ -1152,10 +1152,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
}
|
||||
}
|
||||
if (lessMana.getColorless() > moreMana.getColorless()) {
|
||||
anyDiff -= lessMana.getColorless() - moreMana.getColorless();
|
||||
if (anyDiff < 0) {
|
||||
return null;
|
||||
}
|
||||
return null; // Any (color) can't produce colorless mana
|
||||
}
|
||||
if (lessMana.getAny() > moreMana.getAny()) {
|
||||
return null;
|
||||
|
|
|
@ -23,6 +23,7 @@ import mage.watchers.Watcher;
|
|||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
|
||||
/**
|
||||
* Practically everything in the game is started from an Ability. This interface
|
||||
|
@ -366,6 +367,19 @@ public interface Ability extends Controllable, Serializable {
|
|||
* @return
|
||||
*/
|
||||
boolean hasSourceObjectAbility(Game game, MageObject source, GameEvent event);
|
||||
|
||||
/**
|
||||
* Returns true if the ability has a tap itself in their costs
|
||||
* @return
|
||||
*/
|
||||
default boolean hasTapCost() {
|
||||
for (Cost cost : this.getCosts()) {
|
||||
if (cost instanceof TapSourceCost) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this ability has to be shown as topmost of all the rules
|
||||
|
|
|
@ -35,6 +35,7 @@ import java.util.ArrayList;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
|
|
@ -13,24 +13,23 @@ import mage.game.events.ManaEvent;
|
|||
import mage.players.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import mage.abilities.TriggeredAbility;
|
||||
import mage.constants.ManaType;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public abstract class ManaEffect extends OneShotEffect {
|
||||
|
||||
protected Mana createdMana;
|
||||
|
||||
public ManaEffect() {
|
||||
super(Outcome.PutManaInPool);
|
||||
createdMana = null;
|
||||
}
|
||||
|
||||
public ManaEffect(final ManaEffect effect) {
|
||||
super(effect);
|
||||
this.createdMana = effect.createdMana == null ? null : effect.createdMana.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -81,6 +80,53 @@ public abstract class ManaEffect extends OneShotEffect {
|
|||
return netMana;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of mana a permanent "could produce" is the type of mana that any
|
||||
* ability of that permanent can generate, taking into account any
|
||||
* applicable replacement effects. If the type of mana can’t be defined,
|
||||
* there’s no type of mana that that permanent could produce. The "type" of
|
||||
* mana is its color, or lack thereof (for colorless mana).
|
||||
*
|
||||
* @param game
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
public Set<ManaType> getProducableManaTypes(Game game, Ability source) {
|
||||
return getManaTypesFromManaList(getNetMana(game, source));
|
||||
}
|
||||
|
||||
public static Set<ManaType> getManaTypesFromManaList(List<Mana> manaList) {
|
||||
Set<ManaType> manaTypes = new HashSet<>();
|
||||
for (Mana mana : manaList) {
|
||||
if (mana.getAny() > 0) {
|
||||
manaTypes.add(ManaType.BLACK);
|
||||
manaTypes.add(ManaType.BLUE);
|
||||
manaTypes.add(ManaType.GREEN);
|
||||
manaTypes.add(ManaType.WHITE);
|
||||
manaTypes.add(ManaType.RED);
|
||||
}
|
||||
if (mana.getBlack() > 0) {
|
||||
manaTypes.add(ManaType.BLACK);
|
||||
}
|
||||
if (mana.getBlue() > 0) {
|
||||
manaTypes.add(ManaType.BLUE);
|
||||
}
|
||||
if (mana.getGreen() > 0) {
|
||||
manaTypes.add(ManaType.GREEN);
|
||||
}
|
||||
if (mana.getWhite() > 0) {
|
||||
manaTypes.add(ManaType.WHITE);
|
||||
}
|
||||
if (mana.getRed() > 0) {
|
||||
manaTypes.add(ManaType.RED);
|
||||
}
|
||||
if (mana.getColorless() > 0) {
|
||||
manaTypes.add(ManaType.COLORLESS);
|
||||
}
|
||||
}
|
||||
return manaTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produced the mana the effect can produce (DO NOT add it to mana pool --
|
||||
* return all added as mana object to process by replace events)
|
||||
|
@ -105,14 +151,10 @@ public abstract class ManaEffect extends OneShotEffect {
|
|||
* @param source
|
||||
*/
|
||||
public void checkToFirePossibleEvents(Mana mana, Game game, Ability source) {
|
||||
if (source.getAbilityType() == AbilityType.MANA) {
|
||||
for (Cost cost : source.getCosts()) {
|
||||
if (cost instanceof TapSourceCost) {
|
||||
ManaEvent event = new ManaEvent(GameEvent.EventType.TAPPED_FOR_MANA, source.getSourceId(), source.getSourceId(), source.getControllerId(), mana);
|
||||
if (!game.replaceEvent(event)) {
|
||||
game.fireEvent(event);
|
||||
}
|
||||
}
|
||||
if (source.getAbilityType() == AbilityType.MANA && source.hasTapCost()) {
|
||||
ManaEvent event = new ManaEvent(GameEvent.EventType.TAPPED_FOR_MANA, source.getSourceId(), source.getSourceId(), source.getControllerId(), mana);
|
||||
if (!game.replaceEvent(event)) {
|
||||
game.fireEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,9 @@ package mage.abilities.effects.mana;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
|
@ -11,6 +13,7 @@ import mage.abilities.dynamicvalue.common.StaticValue;
|
|||
import mage.abilities.effects.common.ManaEffect;
|
||||
import mage.abilities.mana.ManaOptions;
|
||||
import mage.constants.ColoredManaSymbol;
|
||||
import mage.constants.ManaType;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
@ -101,8 +104,7 @@ public class AddManaInAnyCombinationEffect extends ManaEffect {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Mana produceMana(Game game, Ability source
|
||||
) {
|
||||
public Mana produceMana(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player != null) {
|
||||
Mana mana = new Mana();
|
||||
|
@ -130,6 +132,29 @@ public class AddManaInAnyCombinationEffect extends ManaEffect {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ManaType> getProducableManaTypes(Game game, Ability source) {
|
||||
Set<ManaType> manaTypes = new HashSet<>();
|
||||
for(ColoredManaSymbol coloredManaSymbol: manaSymbols) {
|
||||
if (coloredManaSymbol.equals(ColoredManaSymbol.B)) {
|
||||
manaTypes.add(ManaType.BLACK);
|
||||
}
|
||||
if (coloredManaSymbol.equals(ColoredManaSymbol.R)) {
|
||||
manaTypes.add(ManaType.RED);
|
||||
}
|
||||
if (coloredManaSymbol.equals(ColoredManaSymbol.G)) {
|
||||
manaTypes.add(ManaType.GREEN);
|
||||
}
|
||||
if (coloredManaSymbol.equals(ColoredManaSymbol.U)) {
|
||||
manaTypes.add(ManaType.BLUE);
|
||||
}
|
||||
if (coloredManaSymbol.equals(ColoredManaSymbol.W)) {
|
||||
manaTypes.add(ManaType.WHITE);
|
||||
}
|
||||
}
|
||||
return manaTypes;
|
||||
}
|
||||
|
||||
private String setText() {
|
||||
StringBuilder sb = new StringBuilder("Add ");
|
||||
sb.append(CardUtil.numberToText(amount.toString()));
|
||||
|
|
|
@ -47,29 +47,31 @@ public class BasicManaEffect extends ManaEffect {
|
|||
// calculate the maximum available mana
|
||||
int count = netAmount.calculate(game, source, this);
|
||||
Mana computedMana = new Mana();
|
||||
if (manaTemplate.getBlack() > 0) {
|
||||
computedMana.setBlack(count * manaTemplate.getBlack());
|
||||
}
|
||||
if (manaTemplate.getBlue() > 0) {
|
||||
computedMana.setBlue(count * manaTemplate.getBlue());
|
||||
}
|
||||
if (manaTemplate.getGreen() > 0) {
|
||||
computedMana.setGreen(count * manaTemplate.getGreen());
|
||||
}
|
||||
if (manaTemplate.getRed() > 0) {
|
||||
computedMana.setRed(count * manaTemplate.getRed());
|
||||
}
|
||||
if (manaTemplate.getWhite() > 0) {
|
||||
computedMana.setWhite(count * manaTemplate.getWhite());
|
||||
}
|
||||
if (manaTemplate.getColorless() > 0) {
|
||||
computedMana.setColorless(count * manaTemplate.getColorless());
|
||||
}
|
||||
if (manaTemplate.getAny() > 0) {
|
||||
throw new IllegalArgumentException("BasicManaEffect does not support {Any} mana!");
|
||||
}
|
||||
if (manaTemplate.getGeneric() > 0) {
|
||||
computedMana.setGeneric(count * manaTemplate.getGeneric());
|
||||
if (count > 0) {
|
||||
if (manaTemplate.getBlack() > 0) {
|
||||
computedMana.setBlack(count * manaTemplate.getBlack());
|
||||
}
|
||||
if (manaTemplate.getBlue() > 0) {
|
||||
computedMana.setBlue(count * manaTemplate.getBlue());
|
||||
}
|
||||
if (manaTemplate.getGreen() > 0) {
|
||||
computedMana.setGreen(count * manaTemplate.getGreen());
|
||||
}
|
||||
if (manaTemplate.getRed() > 0) {
|
||||
computedMana.setRed(count * manaTemplate.getRed());
|
||||
}
|
||||
if (manaTemplate.getWhite() > 0) {
|
||||
computedMana.setWhite(count * manaTemplate.getWhite());
|
||||
}
|
||||
if (manaTemplate.getColorless() > 0) {
|
||||
computedMana.setColorless(count * manaTemplate.getColorless());
|
||||
}
|
||||
if (manaTemplate.getAny() > 0) {
|
||||
throw new IllegalArgumentException("BasicManaEffect does not support {Any} mana!");
|
||||
}
|
||||
if (manaTemplate.getGeneric() > 0) {
|
||||
computedMana.setGeneric(count * manaTemplate.getGeneric());
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(Arrays.asList(computedMana));
|
||||
}
|
||||
|
|
|
@ -1,15 +1,19 @@
|
|||
package mage.abilities.mana;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbilityImpl;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.ManaEffect;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.AsThoughEffectType;
|
||||
import mage.constants.ManaType;
|
||||
import mage.constants.TimingRule;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
|
@ -105,6 +109,17 @@ public abstract class ActivatedManaAbilityImpl extends ActivatedAbilityImpl impl
|
|||
return netManaCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ManaType> getProducableManaTypes(Game game) {
|
||||
Set<ManaType> manaTypes = new HashSet<>();
|
||||
for (Effect effect : getEffects()) {
|
||||
if (effect instanceof ManaEffect) {
|
||||
manaTypes.addAll(((ManaEffect) effect).getProducableManaTypes(game, this));
|
||||
}
|
||||
}
|
||||
return manaTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to check if the ability itself defines mana types it can produce.
|
||||
*
|
||||
|
|
|
@ -17,7 +17,10 @@ import mage.game.permanent.Permanent;
|
|||
import mage.players.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import mage.constants.ManaType;
|
||||
|
||||
/**
|
||||
* @author LevelX2
|
||||
|
@ -55,6 +58,16 @@ public class AnyColorLandsProduceManaAbility extends ActivatedManaAbilityImpl {
|
|||
return true;
|
||||
}
|
||||
|
||||
public static Set<ManaType> getManaTypesFromPermanent(Permanent permanent, Game game) {
|
||||
Set<ManaType> allTypes = new HashSet<>();
|
||||
if (permanent != null) {
|
||||
Abilities<ActivatedManaAbilityImpl> manaAbilities = permanent.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD);
|
||||
for (ActivatedManaAbilityImpl ability : manaAbilities) {
|
||||
allTypes.addAll(ability.getProducableManaTypes(game));
|
||||
}
|
||||
}
|
||||
return allTypes;
|
||||
}
|
||||
}
|
||||
|
||||
class AnyColorLandsProduceManaEffect extends ManaEffect {
|
||||
|
@ -87,27 +100,30 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
|
|||
@Override
|
||||
public List<Mana> getNetMana(Game game, Ability source) {
|
||||
List<Mana> netManas = new ArrayList<>();
|
||||
Mana types = getManaTypes(game, source);
|
||||
if (types.getBlack() > 0) {
|
||||
netManas.add(new Mana(ColoredManaSymbol.B));
|
||||
}
|
||||
if (types.getRed() > 0) {
|
||||
netManas.add(new Mana(ColoredManaSymbol.R));
|
||||
}
|
||||
if (types.getBlue() > 0) {
|
||||
netManas.add(new Mana(ColoredManaSymbol.U));
|
||||
}
|
||||
if (types.getGreen() > 0) {
|
||||
netManas.add(new Mana(ColoredManaSymbol.G));
|
||||
}
|
||||
if (types.getWhite() > 0) {
|
||||
netManas.add(new Mana(ColoredManaSymbol.W));
|
||||
}
|
||||
if (!onlyColors && types.getColorless() > 0) {
|
||||
netManas.add(Mana.ColorlessMana(1));
|
||||
}
|
||||
if (types.getAny() > 0) {
|
||||
netManas.add(Mana.AnyMana(1));
|
||||
if (game != null) {
|
||||
Set<ManaType> manaTypes = getManaTypes(game, source);
|
||||
if ((manaTypes.size() == 5 && !manaTypes.contains(ManaType.COLORLESS)) || manaTypes.size() == 6) { // GENERIC should never be returned from getManaTypes
|
||||
netManas.add(Mana.AnyMana(1));
|
||||
} else {
|
||||
if (manaTypes.contains(ManaType.BLACK)) {
|
||||
netManas.add(Mana.BlackMana(1));
|
||||
}
|
||||
if (manaTypes.contains(ManaType.RED)) {
|
||||
netManas.add(Mana.RedMana(1));
|
||||
}
|
||||
if (manaTypes.contains(ManaType.BLUE)) {
|
||||
netManas.add(Mana.BlueMana(1));
|
||||
}
|
||||
if (manaTypes.contains(ManaType.GREEN)) {
|
||||
netManas.add(Mana.GreenMana(1));
|
||||
}
|
||||
if (manaTypes.contains(ManaType.WHITE)) {
|
||||
netManas.add(Mana.WhiteMana(1));
|
||||
}
|
||||
}
|
||||
if (!onlyColors && manaTypes.contains(ManaType.COLORLESS)) {
|
||||
netManas.add(Mana.ColorlessMana(1));
|
||||
}
|
||||
}
|
||||
return netManas;
|
||||
}
|
||||
|
@ -118,35 +134,28 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
|
|||
if (game == null) {
|
||||
return mana;
|
||||
}
|
||||
Mana types = getManaTypes(game, source);
|
||||
Set<ManaType> types = getManaTypes(game, source);
|
||||
Choice choice = new ChoiceColor(true);
|
||||
choice.getChoices().clear();
|
||||
choice.setMessage("Pick a mana color");
|
||||
if (types.getBlack() > 0) {
|
||||
choice.setMessage("Pick a mana " + (onlyColors ? "color" : "type"));
|
||||
if (types.contains(ManaType.BLACK)) {
|
||||
choice.getChoices().add("Black");
|
||||
}
|
||||
if (types.getRed() > 0) {
|
||||
if (types.contains(ManaType.RED)) {
|
||||
choice.getChoices().add("Red");
|
||||
}
|
||||
if (types.getBlue() > 0) {
|
||||
if (types.contains(ManaType.BLUE)) {
|
||||
choice.getChoices().add("Blue");
|
||||
}
|
||||
if (types.getGreen() > 0) {
|
||||
if (types.contains(ManaType.GREEN)) {
|
||||
choice.getChoices().add("Green");
|
||||
}
|
||||
if (types.getWhite() > 0) {
|
||||
if (types.contains(ManaType.WHITE)) {
|
||||
choice.getChoices().add("White");
|
||||
}
|
||||
if (!onlyColors && types.getColorless() > 0) {
|
||||
if (types.contains(ManaType.COLORLESS)) {
|
||||
choice.getChoices().add("Colorless");
|
||||
}
|
||||
if (types.getAny() > 0) { // Only any Color
|
||||
choice.getChoices().add("Black");
|
||||
choice.getChoices().add("Red");
|
||||
choice.getChoices().add("Blue");
|
||||
choice.getChoices().add("Green");
|
||||
choice.getChoices().add("White");
|
||||
}
|
||||
if (!choice.getChoices().isEmpty()) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (choice.getChoices().size() == 1) {
|
||||
|
@ -182,24 +191,19 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
|
|||
return mana;
|
||||
}
|
||||
|
||||
private Mana getManaTypes(Game game, Ability source) {
|
||||
Mana types = new Mana();
|
||||
private Set<ManaType> getManaTypes(Game game, Ability source) {
|
||||
Set types = new HashSet<>();
|
||||
if (game == null || game.getPhase() == null) {
|
||||
return types;
|
||||
}
|
||||
if (inManaTypeCalculation) {
|
||||
if (inManaTypeCalculation) { // Stop endless loops
|
||||
return types;
|
||||
}
|
||||
inManaTypeCalculation = true;
|
||||
List<Permanent> lands = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game);
|
||||
for (Permanent land : lands) {
|
||||
Abilities<ActivatedManaAbilityImpl> mana = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD);
|
||||
for (ActivatedManaAbilityImpl ability : mana) {
|
||||
if (!ability.getSourceId().equals(source.getSourceId()) && ability.definesMana(game)) {
|
||||
for (Mana netMana : ability.getNetMana(game)) {
|
||||
types.add(netMana);
|
||||
}
|
||||
}
|
||||
if (!land.getId().equals(source.getSourceId())) {
|
||||
types.addAll(AnyColorLandsProduceManaAbility.getManaTypesFromPermanent(land, game));
|
||||
}
|
||||
}
|
||||
inManaTypeCalculation = false;
|
||||
|
@ -210,4 +214,5 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
|
|||
public AnyColorLandsProduceManaEffect copy() {
|
||||
return new AnyColorLandsProduceManaEffect(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
package mage.abilities.mana;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import mage.Mana;
|
||||
import mage.constants.ManaType;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
|
@ -24,6 +26,18 @@ public interface ManaAbility {
|
|||
*/
|
||||
List<Mana> getNetMana(Game game);
|
||||
|
||||
/**
|
||||
* The type of mana a permanent "could produce" is the type of mana that any
|
||||
* ability of that permanent can generate, taking into account any
|
||||
* applicable replacement effects. If the type of mana can’t be defined,
|
||||
* there’s no type of mana that that permanent could produce. The "type" of
|
||||
* mana is its color, or lack thereof (for colorless mana).
|
||||
*
|
||||
* @param game
|
||||
* @return
|
||||
*/
|
||||
Set<ManaType> getProducableManaTypes(Game game);
|
||||
|
||||
/**
|
||||
* Used to check if the ability itself defines mana types it can produce.
|
||||
*
|
||||
|
|
|
@ -94,7 +94,7 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
this.clear();
|
||||
for (Mana netMana : netManas) {
|
||||
for (Mana mana : copy) {
|
||||
if (!hasTapCost(ability) || checkManaReplacementAndTriggeredMana(ability, game, netMana)) {
|
||||
if (ability.hasTapCost() || checkManaReplacementAndTriggeredMana(ability, game, netMana)) {
|
||||
Mana newMana = new Mana();
|
||||
newMana.add(mana);
|
||||
newMana.add(netMana);
|
||||
|
@ -104,7 +104,7 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
}
|
||||
}
|
||||
|
||||
private List<List<Mana>> getSimulatedTriggeredManaFromPlayer(Game game, Ability ability) {
|
||||
private static List<List<Mana>> getSimulatedTriggeredManaFromPlayer(Game game, Ability ability) {
|
||||
Player player = game.getPlayer(ability.getControllerId());
|
||||
List<List<Mana>> newList = new ArrayList<>();
|
||||
if (player != null) {
|
||||
|
@ -124,7 +124,7 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
* @return false if mana production was completely replaced
|
||||
*/
|
||||
private boolean checkManaReplacementAndTriggeredMana(Ability ability, Game game, Mana mana) {
|
||||
if (hasTapCost(ability)) {
|
||||
if (ability.hasTapCost()) {
|
||||
ManaEvent event = new ManaEvent(GameEvent.EventType.TAPPED_FOR_MANA, ability.getSourceId(), ability.getSourceId(), ability.getControllerId(), mana);
|
||||
if (game.replaceEvent(event)) {
|
||||
return false;
|
||||
|
@ -137,15 +137,6 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
return true;
|
||||
}
|
||||
|
||||
public boolean hasTapCost(Ability ability) {
|
||||
for (Cost cost : ability.getCosts()) {
|
||||
if (cost instanceof TapSourceCost) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This adds the mana the abilities can produce to the possible mana
|
||||
* variabtion.
|
||||
|
@ -267,10 +258,10 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
return wasUsable;
|
||||
}
|
||||
|
||||
private List<Mana> getTriggeredManaVariations(Game game, Ability ability, Mana baseMana) {
|
||||
public static List<Mana> getTriggeredManaVariations(Game game, Ability ability, Mana baseMana) {
|
||||
List<Mana> baseManaPlusTriggeredMana = new ArrayList<>();
|
||||
baseManaPlusTriggeredMana.add(baseMana);
|
||||
List<List<Mana>> availableTriggeredManaList = getSimulatedTriggeredManaFromPlayer(game, ability);
|
||||
List<List<Mana>> availableTriggeredManaList = ManaOptions.getSimulatedTriggeredManaFromPlayer(game, ability);
|
||||
for (List<Mana> availableTriggeredMana : availableTriggeredManaList) {
|
||||
if (availableTriggeredMana.size() == 1) {
|
||||
for (Mana prevMana : baseManaPlusTriggeredMana) {
|
||||
|
@ -372,7 +363,7 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
Mana prevMana = currentMana.copy();
|
||||
// generic mana costs can be paid with different colored mana, can lead to different color combinations
|
||||
if (cost.getGeneric() > 0 && cost.getGeneric() > (currentMana.getGeneric() + currentMana.getColorless())) {
|
||||
for (Mana payCombination : getPossiblePayCombinations(cost.getGeneric(), currentMana)) {
|
||||
for (Mana payCombination : ManaOptions.getPossiblePayCombinations(cost.getGeneric(), currentMana)) {
|
||||
Mana currentManaCopy = currentMana.copy();
|
||||
while (currentManaCopy.includesMana(payCombination)) { // loop for multiple usage if possible
|
||||
boolean newCombinations = false;
|
||||
|
@ -420,7 +411,13 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
return oldManaWasReplaced;
|
||||
}
|
||||
|
||||
private List<Mana> getPossiblePayCombinations(int number, Mana manaAvailable) {
|
||||
/**
|
||||
*
|
||||
* @param number of generic mana
|
||||
* @param manaAvailable
|
||||
* @return
|
||||
*/
|
||||
public static List<Mana> getPossiblePayCombinations(int number, Mana manaAvailable) {
|
||||
List<Mana> payCombinations = new ArrayList<>();
|
||||
List<String> payCombinationsStrings = new ArrayList<>();
|
||||
if (manaAvailable.countColored() > 0) {
|
||||
|
@ -439,28 +436,28 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
manaToPayFrom.subtract(existingMana);
|
||||
if (manaToPayFrom.getBlack() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.BlackMana(1).toString())) {
|
||||
manaToPayFrom.subtract(Mana.BlackMana(1));
|
||||
addManaCombination(Mana.BlackMana(1), existingMana, payCombinations, payCombinationsStrings);
|
||||
ManaOptions.addManaCombination(Mana.BlackMana(1), existingMana, payCombinations, payCombinationsStrings);
|
||||
}
|
||||
if (manaToPayFrom.getBlue() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.BlueMana(1).toString())) {
|
||||
manaToPayFrom.subtract(Mana.BlueMana(1));
|
||||
addManaCombination(Mana.BlueMana(1), existingMana, payCombinations, payCombinationsStrings);
|
||||
ManaOptions.addManaCombination(Mana.BlueMana(1), existingMana, payCombinations, payCombinationsStrings);
|
||||
}
|
||||
if (manaToPayFrom.getGreen() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.GreenMana(1).toString())) {
|
||||
manaToPayFrom.subtract(Mana.GreenMana(1));
|
||||
addManaCombination(Mana.GreenMana(1), existingMana, payCombinations, payCombinationsStrings);
|
||||
ManaOptions.addManaCombination(Mana.GreenMana(1), existingMana, payCombinations, payCombinationsStrings);
|
||||
}
|
||||
if (manaToPayFrom.getRed() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.RedMana(1).toString())) {
|
||||
manaToPayFrom.subtract(Mana.RedMana(1));
|
||||
addManaCombination(Mana.RedMana(1), existingMana, payCombinations, payCombinationsStrings);
|
||||
ManaOptions.addManaCombination(Mana.RedMana(1), existingMana, payCombinations, payCombinationsStrings);
|
||||
}
|
||||
if (manaToPayFrom.getWhite() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.WhiteMana(1).toString())) {
|
||||
manaToPayFrom.subtract(Mana.WhiteMana(1));
|
||||
addManaCombination(Mana.WhiteMana(1), existingMana, payCombinations, payCombinationsStrings);
|
||||
ManaOptions.addManaCombination(Mana.WhiteMana(1), existingMana, payCombinations, payCombinationsStrings);
|
||||
}
|
||||
// Pay with any only needed if colored payment was not possible
|
||||
if (payCombinations.isEmpty() && manaToPayFrom.getAny() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.AnyMana(1).toString())) {
|
||||
manaToPayFrom.subtract(Mana.AnyMana(1));
|
||||
addManaCombination(Mana.AnyMana(1), existingMana, payCombinations, payCombinationsStrings);
|
||||
ManaOptions.addManaCombination(Mana.AnyMana(1), existingMana, payCombinations, payCombinationsStrings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -480,7 +477,7 @@ public class ManaOptions extends ArrayList<Mana> {
|
|||
return false;
|
||||
}
|
||||
|
||||
private void addManaCombination(Mana mana, Mana existingMana, List<Mana> payCombinations, List<String> payCombinationsStrings) {
|
||||
public static void addManaCombination(Mana mana, Mana existingMana, List<Mana> payCombinations, List<String> payCombinationsStrings) {
|
||||
Mana newMana = existingMana.copy();
|
||||
newMana.add(mana);
|
||||
payCombinations.add(newMana);
|
||||
|
|
|
@ -9,7 +9,10 @@ import mage.constants.Zone;
|
|||
import mage.game.Game;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import mage.constants.ManaType;
|
||||
|
||||
/**
|
||||
* see 20110715 - 605.1b
|
||||
|
@ -56,7 +59,18 @@ public abstract class TriggeredManaAbility extends TriggeredAbilityImpl implemen
|
|||
}
|
||||
return new ArrayList<>(netMana);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Set<ManaType> getProducableManaTypes(Game game) {
|
||||
Set<ManaType> manaTypes = new HashSet<>();
|
||||
for (Effect effect : getEffects()) {
|
||||
if (effect instanceof ManaEffect) {
|
||||
manaTypes.addAll(((ManaEffect) effect).getProducableManaTypes(game, this));
|
||||
}
|
||||
}
|
||||
return manaTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to check if the ability itself defines mana types it can produce.
|
||||
*
|
||||
|
|
|
@ -2906,7 +2906,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
if (canUse && ability.canActivate(playerId, game).canActivate()) {
|
||||
// abilities without Tap costs have to be handled as separate sources, because they can be used also
|
||||
if (!availableMana.hasTapCost(ability)) {
|
||||
if (!ability.hasTapCost()) {
|
||||
it.remove();
|
||||
Abilities<ActivatedManaAbilityImpl> noTapAbilities = new AbilitiesImpl<>(ability);
|
||||
if (ability.getManaCosts().isEmpty()) {
|
||||
|
|
Loading…
Reference in a new issue