mirror of
https://github.com/correl/mage.git
synced 2024-12-25 11:11:16 +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.MageObject;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.costs.common.TapSourceCost;
|
|
||||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||||
import mage.abilities.effects.RestrictionEffect;
|
import mage.abilities.effects.RestrictionEffect;
|
||||||
import mage.abilities.keyword.FlyingAbility;
|
import mage.abilities.keyword.FlyingAbility;
|
||||||
|
@ -119,14 +118,12 @@ class KatabaticWindsRuleModifyingEffect extends ContinuousRuleModifyingEffectImp
|
||||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||||
MageObject object = game.getObject(event.getSourceId());
|
MageObject object = game.getObject(event.getSourceId());
|
||||||
Optional<Ability> ability = game.getAbility(event.getTargetId(), event.getSourceId());
|
Optional<Ability> ability = game.getAbility(event.getTargetId(), event.getSourceId());
|
||||||
if (ability.isPresent()
|
return ability.isPresent()
|
||||||
&& object != null
|
&& object != null
|
||||||
&& object.isCreature()
|
&& object.isCreature()
|
||||||
&& object.getAbilities().contains(FlyingAbility.getInstance())
|
&& object.getAbilities().contains(FlyingAbility.getInstance())
|
||||||
&& game.getState().getPlayersInRange(source.getControllerId(), game).contains(event.getPlayerId())) {
|
&& game.getState().getPlayersInRange(source.getControllerId(), game).contains(event.getPlayerId())
|
||||||
return ability.get().getCosts().stream().anyMatch((cost) -> (cost instanceof TapSourceCost));
|
&& ability.get().hasTapCost();
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -66,13 +66,11 @@ class HasAbilityWithTapSymbolPredicate implements Predicate<MageObject> {
|
||||||
|
|
||||||
for (Ability ability : abilities) {
|
for (Ability ability : abilities) {
|
||||||
if ((ability.getAbilityType() == AbilityType.ACTIVATED || ability.getAbilityType() == AbilityType.MANA) && !ability.getCosts().isEmpty()) {
|
if ((ability.getAbilityType() == AbilityType.ACTIVATED || ability.getAbilityType() == AbilityType.MANA) && !ability.getCosts().isEmpty()) {
|
||||||
for (Cost cost : ability.getCosts()) {
|
if (ability.hasTapCost()) {
|
||||||
if (cost instanceof TapSourceCost) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,15 +2,18 @@
|
||||||
package mage.cards.m;
|
package mage.cards.m;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.Mana;
|
import mage.Mana;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.TriggeredAbilityImpl;
|
import mage.abilities.TriggeredAbilityImpl;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
||||||
|
import mage.abilities.mana.AnyColorLandsProduceManaAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.ManaType;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.filter.common.FilterLandPermanent;
|
import mage.filter.common.FilterLandPermanent;
|
||||||
|
@ -61,6 +64,9 @@ class ManaWebTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
|
if (game.inCheckPlayableState()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (game.getOpponents(controllerId).contains(event.getPlayerId())) {
|
if (game.getOpponents(controllerId).contains(event.getPlayerId())) {
|
||||||
Permanent permanent = game.getPermanent(event.getSourceId());
|
Permanent permanent = game.getPermanent(event.getSourceId());
|
||||||
|
|
||||||
|
@ -103,34 +109,18 @@ class ManaWebeffect extends OneShotEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent permanent = null;
|
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||||
|
if (permanent != null) {
|
||||||
if (game != null && source != null) {
|
Set<ManaType> manaTypesSource = AnyColorLandsProduceManaAbility.getManaTypesFromPermanent(permanent, game);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean tappedLands = false;
|
boolean tappedLands = false;
|
||||||
for (Permanent opponentPermanent : game.getBattlefield().getActivePermanents(filter, permanent.getControllerId(), game)) {
|
for (Permanent opponentPermanent : game.getBattlefield().getActivePermanents(filter, permanent.getControllerId(), game)) {
|
||||||
if (Objects.equals(opponentPermanent.getControllerId(), permanent.getControllerId())) {
|
if (Objects.equals(opponentPermanent.getControllerId(), permanent.getControllerId())) {
|
||||||
Mana opponentLandMana = new Mana();
|
Set<ManaType> manaTypes = AnyColorLandsProduceManaAbility.getManaTypesFromPermanent(opponentPermanent, game);
|
||||||
|
for (ManaType manaType : manaTypes) {
|
||||||
for (ActivatedManaAbilityImpl ability : opponentPermanent.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, game)) {
|
if (manaTypesSource.contains(manaType)) {
|
||||||
for (Mana netMana : ability.getNetMana(game)) {
|
|
||||||
opponentLandMana.add(netMana);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mana.containsAny(opponentLandMana, true)) {
|
|
||||||
tappedLands = opponentPermanent.tap(game) || tappedLands;
|
tappedLands = opponentPermanent.tap(game) || tappedLands;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,6 @@ package mage.cards.p;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.abilities.TriggeredAbilityImpl;
|
import mage.abilities.TriggeredAbilityImpl;
|
||||||
import mage.abilities.costs.Cost;
|
|
||||||
import mage.abilities.costs.common.TapSourceCost;
|
|
||||||
import mage.abilities.effects.common.GainLifeEffect;
|
import mage.abilities.effects.common.GainLifeEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
@ -25,7 +23,7 @@ public final class Powerleech extends CardImpl {
|
||||||
public Powerleech(UUID ownerId, CardSetInfo setInfo) {
|
public Powerleech(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}{G}");
|
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());
|
this.addAbility(new PowerleechTriggeredAbility());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,17 +73,8 @@ class PowerleechTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
if (stackAbility == null) {
|
if (stackAbility == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
boolean triggerable = true;
|
return !stackAbility.hasTapCost()
|
||||||
for (Cost cost : stackAbility.getCosts()) {
|
&& player.hasOpponent(permanent.getControllerId(), game);
|
||||||
if (cost instanceof TapSourceCost) {
|
|
||||||
triggerable = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!triggerable) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return player.hasOpponent(permanent.getControllerId(), game);
|
|
||||||
}
|
}
|
||||||
if (event.getType() == GameEvent.EventType.TAPPED) {
|
if (event.getType() == GameEvent.EventType.TAPPED) {
|
||||||
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId());
|
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId());
|
||||||
|
|
|
@ -7,7 +7,6 @@ import mage.MageObject;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.costs.common.TapSourceCost;
|
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||||
import mage.abilities.effects.common.AttachEffect;
|
import mage.abilities.effects.common.AttachEffect;
|
||||||
|
@ -104,16 +103,12 @@ class SerraBestiaryRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl
|
||||||
}
|
}
|
||||||
MageObject object = game.getObject(event.getSourceId());
|
MageObject object = game.getObject(event.getSourceId());
|
||||||
Optional<Ability> ability = game.getAbility(event.getTargetId(), event.getSourceId());
|
Optional<Ability> ability = game.getAbility(event.getTargetId(), event.getSourceId());
|
||||||
if (ability.isPresent()
|
return ability.isPresent()
|
||||||
&& object != null
|
&& object != null
|
||||||
&& object.isCreature()
|
&& object.isCreature()
|
||||||
&& object.getId().equals(enchantedCreature.getId())
|
&& object.getId().equals(enchantedCreature.getId())
|
||||||
&& game.getState().getPlayersInRange(source.getControllerId(), game).contains(event.getPlayerId())) {
|
&& game.getState().getPlayersInRange(source.getControllerId(), game).contains(event.getPlayerId())
|
||||||
if (ability.get().getCosts().stream().anyMatch((cost) -> (cost instanceof TapSourceCost))) {
|
&& ability.get().hasTapCost();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -5,6 +5,8 @@ import java.util.UUID;
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.Mana;
|
import mage.Mana;
|
||||||
import mage.abilities.costs.common.DiscardCardCost;
|
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.keyword.FlyingAbility;
|
||||||
import mage.abilities.mana.SimpleManaAbility;
|
import mage.abilities.mana.SimpleManaAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
@ -29,7 +31,13 @@ public final class SkirgeFamiliar extends CardImpl {
|
||||||
this.addAbility(FlyingAbility.getInstance());
|
this.addAbility(FlyingAbility.getInstance());
|
||||||
|
|
||||||
// Discard a card: Add {B}.
|
// 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) {
|
public SkirgeFamiliar(final SkirgeFamiliar card) {
|
||||||
|
|
|
@ -7,6 +7,8 @@ import mage.Mana;
|
||||||
import mage.ObjectColor;
|
import mage.ObjectColor;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.costs.common.SacrificeTargetCost;
|
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.dynamicvalue.common.SacrificeCostConvertedMana;
|
||||||
import mage.abilities.mana.DynamicManaAbility;
|
import mage.abilities.mana.DynamicManaAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
@ -38,8 +40,9 @@ public final class SoldeviAdnate extends CardImpl {
|
||||||
this.toughness = new MageInt(2);
|
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.
|
// {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"),
|
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");
|
"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)));
|
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter)));
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import mage.cards.CardSetInfo;
|
||||||
import mage.choices.Choice;
|
import mage.choices.Choice;
|
||||||
import mage.choices.ChoiceColor;
|
import mage.choices.ChoiceColor;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.ColoredManaSymbol;
|
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.filter.common.FilterControlledLandPermanent;
|
import mage.filter.common.FilterControlledLandPermanent;
|
||||||
import mage.filter.common.FilterControlledPermanent;
|
import mage.filter.common.FilterControlledPermanent;
|
||||||
|
@ -23,8 +22,13 @@ import mage.players.Player;
|
||||||
import mage.target.common.TargetControlledPermanent;
|
import mage.target.common.TargetControlledPermanent;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
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)
|
* @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
|
||||||
|
@ -64,25 +68,36 @@ class SquanderedResourcesEffect extends ManaEffect {
|
||||||
@Override
|
@Override
|
||||||
public List<Mana> getNetMana(Game game, Ability source) {
|
public List<Mana> getNetMana(Game game, Ability source) {
|
||||||
List<Mana> netManas = new ArrayList<>();
|
List<Mana> netManas = new ArrayList<>();
|
||||||
Mana types = getManaTypes(game, source);
|
Set<ManaType> manaTypes = new HashSet<>();
|
||||||
if (types.getBlack() > 0) {
|
if (game != null && game.inCheckPlayableState()) {
|
||||||
netManas.add(new Mana(ColoredManaSymbol.B));
|
for (Permanent land : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), game)) {
|
||||||
|
manaTypes.addAll(AnyColorLandsProduceManaAbility.getManaTypesFromPermanent(land, game));
|
||||||
}
|
}
|
||||||
if (types.getRed() > 0) {
|
} else {
|
||||||
netManas.add(new Mana(ColoredManaSymbol.R));
|
manaTypes = getManaTypesFromSacrificedPermanent(game, source);
|
||||||
}
|
}
|
||||||
if (types.getBlue() > 0) {
|
if (manaTypes.size() == 5 && !manaTypes.contains(ManaType.COLORLESS) && !manaTypes.contains(ManaType.GENERIC)) {
|
||||||
netManas.add(new Mana(ColoredManaSymbol.U));
|
netManas.add(Mana.AnyMana(1));
|
||||||
|
} else {
|
||||||
|
if (manaTypes.contains(ManaType.BLACK)) {
|
||||||
|
netManas.add(Mana.BlackMana(1));
|
||||||
}
|
}
|
||||||
if (types.getGreen() > 0) {
|
if (manaTypes.contains(ManaType.RED)) {
|
||||||
netManas.add(new Mana(ColoredManaSymbol.G));
|
netManas.add(Mana.RedMana(1));
|
||||||
}
|
}
|
||||||
if (types.getWhite() > 0) {
|
if (manaTypes.contains(ManaType.BLUE)) {
|
||||||
netManas.add(new Mana(ColoredManaSymbol.W));
|
netManas.add(Mana.BlueMana(1));
|
||||||
}
|
}
|
||||||
if (types.getGeneric() > 0) {
|
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));
|
netManas.add(Mana.ColorlessMana(1));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return netManas;
|
return netManas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,34 +107,26 @@ class SquanderedResourcesEffect extends ManaEffect {
|
||||||
if (game == null) {
|
if (game == null) {
|
||||||
return mana;
|
return mana;
|
||||||
}
|
}
|
||||||
Mana types = getManaTypes(game, source);
|
Set<ManaType> manaTypes = getManaTypesFromSacrificedPermanent(game, source);
|
||||||
Choice choice = new ChoiceColor(true);
|
Choice choice = new ChoiceColor(true);
|
||||||
choice.getChoices().clear();
|
choice.getChoices().clear();
|
||||||
choice.setMessage("Pick a mana color");
|
choice.setMessage("Pick a mana color");
|
||||||
if (types.getBlack() > 0) {
|
if (manaTypes.contains(ManaType.BLACK)) {
|
||||||
choice.getChoices().add("Black");
|
choice.getChoices().add("Black");
|
||||||
}
|
}
|
||||||
if (types.getRed() > 0) {
|
if (manaTypes.contains(ManaType.RED)) {
|
||||||
choice.getChoices().add("Red");
|
choice.getChoices().add("Red");
|
||||||
}
|
}
|
||||||
if (types.getBlue() > 0) {
|
if (manaTypes.contains(ManaType.BLUE)) {
|
||||||
choice.getChoices().add("Blue");
|
choice.getChoices().add("Blue");
|
||||||
}
|
}
|
||||||
if (types.getGreen() > 0) {
|
if (manaTypes.contains(ManaType.GREEN)) {
|
||||||
choice.getChoices().add("Green");
|
choice.getChoices().add("Green");
|
||||||
}
|
}
|
||||||
if (types.getWhite() > 0) {
|
if (manaTypes.contains(ManaType.WHITE)) {
|
||||||
choice.getChoices().add("White");
|
choice.getChoices().add("White");
|
||||||
}
|
}
|
||||||
if (types.getColorless() > 0) {
|
if (manaTypes.contains(ManaType.COLORLESS)) {
|
||||||
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");
|
choice.getChoices().add("Colorless");
|
||||||
}
|
}
|
||||||
if (!choice.getChoices().isEmpty()) {
|
if (!choice.getChoices().isEmpty()) {
|
||||||
|
@ -158,20 +165,14 @@ class SquanderedResourcesEffect extends ManaEffect {
|
||||||
return mana;
|
return mana;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mana getManaTypes(Game game, Ability source) {
|
private Set<ManaType> getManaTypesFromSacrificedPermanent(Game game, Ability source) {
|
||||||
Mana types = new Mana();
|
Set<ManaType> types = new HashSet<>();
|
||||||
for (Cost cost : source.getCosts()) {
|
for (Cost cost : source.getCosts()) {
|
||||||
if (cost instanceof SacrificeTargetCost && !((SacrificeTargetCost) cost).getPermanents().isEmpty()) {
|
if (cost instanceof SacrificeTargetCost && !((SacrificeTargetCost) cost).getPermanents().isEmpty()) {
|
||||||
Permanent land = ((SacrificeTargetCost) cost).getPermanents().get(0);
|
Permanent land = ((SacrificeTargetCost) cost).getPermanents().get(0);
|
||||||
if (land != null) {
|
if (land != null) {
|
||||||
Abilities<ActivatedManaAbilityImpl> manaAbilities = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD);
|
types.addAll(AnyColorLandsProduceManaAbility.getManaTypesFromPermanent(land, game));
|
||||||
for (ActivatedManaAbilityImpl ability : manaAbilities) {
|
break;
|
||||||
if (!ability.equals(source) && ability.definesMana(game)) {
|
|
||||||
for (Mana netMana : ability.getNetMana(game)) {
|
|
||||||
types.add(netMana);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,43 +1,34 @@
|
||||||
package mage.cards.s;
|
package mage.cards.s;
|
||||||
|
|
||||||
import mage.Mana;
|
|
||||||
import mage.abilities.Abilities;
|
|
||||||
import mage.abilities.Ability;
|
|
||||||
import mage.abilities.common.EntersBattlefieldTappedAbility;
|
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.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.choices.Choice;
|
|
||||||
import mage.choices.ChoiceColor;
|
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.ColoredManaSymbol;
|
|
||||||
import mage.constants.SuperType;
|
import mage.constants.SuperType;
|
||||||
import mage.constants.Zone;
|
|
||||||
import mage.filter.common.FilterControlledLandPermanent;
|
import mage.filter.common.FilterControlledLandPermanent;
|
||||||
import mage.filter.common.FilterControlledPermanent;
|
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 java.util.UUID;
|
||||||
|
import mage.abilities.mana.AnyColorLandsProduceManaAbility;
|
||||||
|
import mage.constants.TargetController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author anonymous
|
* @author anonymous
|
||||||
*/
|
*/
|
||||||
public final class StarCompass extends CardImpl {
|
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) {
|
public StarCompass(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
|
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
|
||||||
|
|
||||||
// Star Compass enters the battlefield tapped.
|
// Star Compass enters the battlefield tapped.
|
||||||
this.addAbility(new EntersBattlefieldTappedAbility());
|
this.addAbility(new EntersBattlefieldTappedAbility());
|
||||||
// {tap}: Add one mana of any color that a basic land you control could produce.
|
// {T}: Add one mana of any color that a basic land you control could produce.
|
||||||
this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new StarCompassManaEffect(), new TapSourceCost()));
|
this.addAbility(new AnyColorLandsProduceManaAbility(TargetController.YOU, true, filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
public StarCompass(final StarCompass card) {
|
public StarCompass(final StarCompass card) {
|
||||||
|
@ -49,143 +40,3 @@ public final class StarCompass extends CardImpl {
|
||||||
return new StarCompass(this);
|
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());
|
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
|
||||||
assertManaOptions("{R}{R}{R}", manaOptions);
|
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();
|
execute();
|
||||||
|
|
||||||
ManaOptions options = playerA.getAvailableManaTest(currentGame);
|
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}{C}{Any}", options);
|
||||||
assertManaOptions("{C}{Any}{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();
|
execute();
|
||||||
|
|
||||||
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
|
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);
|
assertDuplicatedManaOptions(manaOptions);
|
||||||
|
assertManaOptions("{C}{C}", manaOptions);
|
||||||
assertManaOptions("{Any}{Any}", manaOptions);
|
assertManaOptions("{Any}{Any}", manaOptions);
|
||||||
|
assertManaOptions("{C}{Any}", manaOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -170,39 +170,22 @@ public abstract class MageObjectImpl implements MageObject {
|
||||||
// its frame colors.
|
// its frame colors.
|
||||||
if (this.isLand()) {
|
if (this.isLand()) {
|
||||||
ObjectColor cl = frameColor.copy();
|
ObjectColor cl = frameColor.copy();
|
||||||
|
Set<ManaType> manaTypes = EnumSet.noneOf(ManaType.class);
|
||||||
for (Ability ab : getAbilities()) {
|
for (Ability ab : getAbilities()) {
|
||||||
if (ab instanceof ActivatedManaAbilityImpl) {
|
if (ab instanceof ActivatedManaAbilityImpl) {
|
||||||
ActivatedManaAbilityImpl mana = (ActivatedManaAbilityImpl) ab;
|
manaTypes.addAll(((ActivatedManaAbilityImpl) ab).getProducableManaTypes(game));
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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;
|
return cl;
|
||||||
} else {
|
} else {
|
||||||
// For everything else, just return the frame colors
|
// 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()) {
|
if (lessMana.getColorless() > moreMana.getColorless()) {
|
||||||
anyDiff -= lessMana.getColorless() - moreMana.getColorless();
|
return null; // Any (color) can't produce colorless mana
|
||||||
if (anyDiff < 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (lessMana.getAny() > moreMana.getAny()) {
|
if (lessMana.getAny() > moreMana.getAny()) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -23,6 +23,7 @@ import mage.watchers.Watcher;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import mage.abilities.costs.common.TapSourceCost;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Practically everything in the game is started from an Ability. This interface
|
* Practically everything in the game is started from an Ability. This interface
|
||||||
|
@ -367,6 +368,19 @@ public interface Ability extends Controllable, Serializable {
|
||||||
*/
|
*/
|
||||||
boolean hasSourceObjectAbility(Game game, MageObject source, GameEvent event);
|
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
|
* Returns true if this ability has to be shown as topmost of all the rules
|
||||||
* of the object
|
* of the object
|
||||||
|
|
|
@ -35,6 +35,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.costs.common.TapSourceCost;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com
|
||||||
|
|
|
@ -13,24 +13,23 @@ import mage.game.events.ManaEvent;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import mage.abilities.TriggeredAbility;
|
import mage.abilities.TriggeredAbility;
|
||||||
|
import mage.constants.ManaType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com
|
||||||
*/
|
*/
|
||||||
public abstract class ManaEffect extends OneShotEffect {
|
public abstract class ManaEffect extends OneShotEffect {
|
||||||
|
|
||||||
protected Mana createdMana;
|
|
||||||
|
|
||||||
public ManaEffect() {
|
public ManaEffect() {
|
||||||
super(Outcome.PutManaInPool);
|
super(Outcome.PutManaInPool);
|
||||||
createdMana = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ManaEffect(final ManaEffect effect) {
|
public ManaEffect(final ManaEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
this.createdMana = effect.createdMana == null ? null : effect.createdMana.copy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -81,6 +80,53 @@ public abstract class ManaEffect extends OneShotEffect {
|
||||||
return netMana;
|
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 --
|
* 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)
|
* return all added as mana object to process by replace events)
|
||||||
|
@ -105,9 +151,7 @@ public abstract class ManaEffect extends OneShotEffect {
|
||||||
* @param source
|
* @param source
|
||||||
*/
|
*/
|
||||||
public void checkToFirePossibleEvents(Mana mana, Game game, Ability source) {
|
public void checkToFirePossibleEvents(Mana mana, Game game, Ability source) {
|
||||||
if (source.getAbilityType() == AbilityType.MANA) {
|
if (source.getAbilityType() == AbilityType.MANA && source.hasTapCost()) {
|
||||||
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);
|
ManaEvent event = new ManaEvent(GameEvent.EventType.TAPPED_FOR_MANA, source.getSourceId(), source.getSourceId(), source.getControllerId(), mana);
|
||||||
if (!game.replaceEvent(event)) {
|
if (!game.replaceEvent(event)) {
|
||||||
game.fireEvent(event);
|
game.fireEvent(event);
|
||||||
|
@ -115,5 +159,3 @@ public abstract class ManaEffect extends OneShotEffect {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,7 +2,9 @@ package mage.abilities.effects.mana;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import mage.Mana;
|
import mage.Mana;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
@ -11,6 +13,7 @@ import mage.abilities.dynamicvalue.common.StaticValue;
|
||||||
import mage.abilities.effects.common.ManaEffect;
|
import mage.abilities.effects.common.ManaEffect;
|
||||||
import mage.abilities.mana.ManaOptions;
|
import mage.abilities.mana.ManaOptions;
|
||||||
import mage.constants.ColoredManaSymbol;
|
import mage.constants.ColoredManaSymbol;
|
||||||
|
import mage.constants.ManaType;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.util.CardUtil;
|
import mage.util.CardUtil;
|
||||||
|
@ -101,8 +104,7 @@ public class AddManaInAnyCombinationEffect extends ManaEffect {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mana produceMana(Game game, Ability source
|
public Mana produceMana(Game game, Ability source) {
|
||||||
) {
|
|
||||||
Player player = game.getPlayer(source.getControllerId());
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
Mana mana = new Mana();
|
Mana mana = new Mana();
|
||||||
|
@ -130,6 +132,29 @@ public class AddManaInAnyCombinationEffect extends ManaEffect {
|
||||||
return null;
|
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() {
|
private String setText() {
|
||||||
StringBuilder sb = new StringBuilder("Add ");
|
StringBuilder sb = new StringBuilder("Add ");
|
||||||
sb.append(CardUtil.numberToText(amount.toString()));
|
sb.append(CardUtil.numberToText(amount.toString()));
|
||||||
|
|
|
@ -47,6 +47,7 @@ public class BasicManaEffect extends ManaEffect {
|
||||||
// calculate the maximum available mana
|
// calculate the maximum available mana
|
||||||
int count = netAmount.calculate(game, source, this);
|
int count = netAmount.calculate(game, source, this);
|
||||||
Mana computedMana = new Mana();
|
Mana computedMana = new Mana();
|
||||||
|
if (count > 0) {
|
||||||
if (manaTemplate.getBlack() > 0) {
|
if (manaTemplate.getBlack() > 0) {
|
||||||
computedMana.setBlack(count * manaTemplate.getBlack());
|
computedMana.setBlack(count * manaTemplate.getBlack());
|
||||||
}
|
}
|
||||||
|
@ -71,6 +72,7 @@ public class BasicManaEffect extends ManaEffect {
|
||||||
if (manaTemplate.getGeneric() > 0) {
|
if (manaTemplate.getGeneric() > 0) {
|
||||||
computedMana.setGeneric(count * manaTemplate.getGeneric());
|
computedMana.setGeneric(count * manaTemplate.getGeneric());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return new ArrayList<>(Arrays.asList(computedMana));
|
return new ArrayList<>(Arrays.asList(computedMana));
|
||||||
}
|
}
|
||||||
return super.getNetMana(game, source);
|
return super.getNetMana(game, source);
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
package mage.abilities.mana;
|
package mage.abilities.mana;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.Mana;
|
import mage.Mana;
|
||||||
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.ActivatedAbilityImpl;
|
import mage.abilities.ActivatedAbilityImpl;
|
||||||
import mage.abilities.costs.Cost;
|
import mage.abilities.costs.Cost;
|
||||||
import mage.abilities.effects.Effect;
|
import mage.abilities.effects.Effect;
|
||||||
import mage.abilities.effects.common.ManaEffect;
|
import mage.abilities.effects.common.ManaEffect;
|
||||||
import mage.constants.AbilityType;
|
import mage.constants.AbilityType;
|
||||||
import mage.constants.AsThoughEffectType;
|
import mage.constants.AsThoughEffectType;
|
||||||
|
import mage.constants.ManaType;
|
||||||
import mage.constants.TimingRule;
|
import mage.constants.TimingRule;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
@ -105,6 +109,17 @@ public abstract class ActivatedManaAbilityImpl extends ActivatedAbilityImpl impl
|
||||||
return netManaCopy;
|
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.
|
* 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 mage.players.Player;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import mage.constants.ManaType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
|
@ -55,6 +58,16 @@ public class AnyColorLandsProduceManaAbility extends ActivatedManaAbilityImpl {
|
||||||
return true;
|
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 {
|
class AnyColorLandsProduceManaEffect extends ManaEffect {
|
||||||
|
@ -87,27 +100,30 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
|
||||||
@Override
|
@Override
|
||||||
public List<Mana> getNetMana(Game game, Ability source) {
|
public List<Mana> getNetMana(Game game, Ability source) {
|
||||||
List<Mana> netManas = new ArrayList<>();
|
List<Mana> netManas = new ArrayList<>();
|
||||||
Mana types = getManaTypes(game, source);
|
if (game != null) {
|
||||||
if (types.getBlack() > 0) {
|
Set<ManaType> manaTypes = getManaTypes(game, source);
|
||||||
netManas.add(new Mana(ColoredManaSymbol.B));
|
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 (types.getRed() > 0) {
|
if (manaTypes.contains(ManaType.RED)) {
|
||||||
netManas.add(new Mana(ColoredManaSymbol.R));
|
netManas.add(Mana.RedMana(1));
|
||||||
}
|
}
|
||||||
if (types.getBlue() > 0) {
|
if (manaTypes.contains(ManaType.BLUE)) {
|
||||||
netManas.add(new Mana(ColoredManaSymbol.U));
|
netManas.add(Mana.BlueMana(1));
|
||||||
}
|
}
|
||||||
if (types.getGreen() > 0) {
|
if (manaTypes.contains(ManaType.GREEN)) {
|
||||||
netManas.add(new Mana(ColoredManaSymbol.G));
|
netManas.add(Mana.GreenMana(1));
|
||||||
}
|
}
|
||||||
if (types.getWhite() > 0) {
|
if (manaTypes.contains(ManaType.WHITE)) {
|
||||||
netManas.add(new Mana(ColoredManaSymbol.W));
|
netManas.add(Mana.WhiteMana(1));
|
||||||
}
|
}
|
||||||
if (!onlyColors && types.getColorless() > 0) {
|
}
|
||||||
|
if (!onlyColors && manaTypes.contains(ManaType.COLORLESS)) {
|
||||||
netManas.add(Mana.ColorlessMana(1));
|
netManas.add(Mana.ColorlessMana(1));
|
||||||
}
|
}
|
||||||
if (types.getAny() > 0) {
|
|
||||||
netManas.add(Mana.AnyMana(1));
|
|
||||||
}
|
}
|
||||||
return netManas;
|
return netManas;
|
||||||
}
|
}
|
||||||
|
@ -118,35 +134,28 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
|
||||||
if (game == null) {
|
if (game == null) {
|
||||||
return mana;
|
return mana;
|
||||||
}
|
}
|
||||||
Mana types = getManaTypes(game, source);
|
Set<ManaType> types = getManaTypes(game, source);
|
||||||
Choice choice = new ChoiceColor(true);
|
Choice choice = new ChoiceColor(true);
|
||||||
choice.getChoices().clear();
|
choice.getChoices().clear();
|
||||||
choice.setMessage("Pick a mana color");
|
choice.setMessage("Pick a mana " + (onlyColors ? "color" : "type"));
|
||||||
if (types.getBlack() > 0) {
|
if (types.contains(ManaType.BLACK)) {
|
||||||
choice.getChoices().add("Black");
|
choice.getChoices().add("Black");
|
||||||
}
|
}
|
||||||
if (types.getRed() > 0) {
|
if (types.contains(ManaType.RED)) {
|
||||||
choice.getChoices().add("Red");
|
choice.getChoices().add("Red");
|
||||||
}
|
}
|
||||||
if (types.getBlue() > 0) {
|
if (types.contains(ManaType.BLUE)) {
|
||||||
choice.getChoices().add("Blue");
|
choice.getChoices().add("Blue");
|
||||||
}
|
}
|
||||||
if (types.getGreen() > 0) {
|
if (types.contains(ManaType.GREEN)) {
|
||||||
choice.getChoices().add("Green");
|
choice.getChoices().add("Green");
|
||||||
}
|
}
|
||||||
if (types.getWhite() > 0) {
|
if (types.contains(ManaType.WHITE)) {
|
||||||
choice.getChoices().add("White");
|
choice.getChoices().add("White");
|
||||||
}
|
}
|
||||||
if (!onlyColors && types.getColorless() > 0) {
|
if (types.contains(ManaType.COLORLESS)) {
|
||||||
choice.getChoices().add("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()) {
|
if (!choice.getChoices().isEmpty()) {
|
||||||
Player player = game.getPlayer(source.getControllerId());
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
if (choice.getChoices().size() == 1) {
|
if (choice.getChoices().size() == 1) {
|
||||||
|
@ -182,24 +191,19 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
|
||||||
return mana;
|
return mana;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mana getManaTypes(Game game, Ability source) {
|
private Set<ManaType> getManaTypes(Game game, Ability source) {
|
||||||
Mana types = new Mana();
|
Set types = new HashSet<>();
|
||||||
if (game == null || game.getPhase() == null) {
|
if (game == null || game.getPhase() == null) {
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
if (inManaTypeCalculation) {
|
if (inManaTypeCalculation) { // Stop endless loops
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
inManaTypeCalculation = true;
|
inManaTypeCalculation = true;
|
||||||
List<Permanent> lands = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game);
|
List<Permanent> lands = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game);
|
||||||
for (Permanent land : lands) {
|
for (Permanent land : lands) {
|
||||||
Abilities<ActivatedManaAbilityImpl> mana = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD);
|
if (!land.getId().equals(source.getSourceId())) {
|
||||||
for (ActivatedManaAbilityImpl ability : mana) {
|
types.addAll(AnyColorLandsProduceManaAbility.getManaTypesFromPermanent(land, game));
|
||||||
if (!ability.getSourceId().equals(source.getSourceId()) && ability.definesMana(game)) {
|
|
||||||
for (Mana netMana : ability.getNetMana(game)) {
|
|
||||||
types.add(netMana);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inManaTypeCalculation = false;
|
inManaTypeCalculation = false;
|
||||||
|
@ -210,4 +214,5 @@ class AnyColorLandsProduceManaEffect extends ManaEffect {
|
||||||
public AnyColorLandsProduceManaEffect copy() {
|
public AnyColorLandsProduceManaEffect copy() {
|
||||||
return new AnyColorLandsProduceManaEffect(this);
|
return new AnyColorLandsProduceManaEffect(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
package mage.abilities.mana;
|
package mage.abilities.mana;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import mage.Mana;
|
import mage.Mana;
|
||||||
|
import mage.constants.ManaType;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,6 +26,18 @@ public interface ManaAbility {
|
||||||
*/
|
*/
|
||||||
List<Mana> getNetMana(Game game);
|
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.
|
* 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();
|
this.clear();
|
||||||
for (Mana netMana : netManas) {
|
for (Mana netMana : netManas) {
|
||||||
for (Mana mana : copy) {
|
for (Mana mana : copy) {
|
||||||
if (!hasTapCost(ability) || checkManaReplacementAndTriggeredMana(ability, game, netMana)) {
|
if (ability.hasTapCost() || checkManaReplacementAndTriggeredMana(ability, game, netMana)) {
|
||||||
Mana newMana = new Mana();
|
Mana newMana = new Mana();
|
||||||
newMana.add(mana);
|
newMana.add(mana);
|
||||||
newMana.add(netMana);
|
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());
|
Player player = game.getPlayer(ability.getControllerId());
|
||||||
List<List<Mana>> newList = new ArrayList<>();
|
List<List<Mana>> newList = new ArrayList<>();
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
|
@ -124,7 +124,7 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
* @return false if mana production was completely replaced
|
* @return false if mana production was completely replaced
|
||||||
*/
|
*/
|
||||||
private boolean checkManaReplacementAndTriggeredMana(Ability ability, Game game, Mana mana) {
|
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);
|
ManaEvent event = new ManaEvent(GameEvent.EventType.TAPPED_FOR_MANA, ability.getSourceId(), ability.getSourceId(), ability.getControllerId(), mana);
|
||||||
if (game.replaceEvent(event)) {
|
if (game.replaceEvent(event)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -137,15 +137,6 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
return true;
|
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
|
* This adds the mana the abilities can produce to the possible mana
|
||||||
* variabtion.
|
* variabtion.
|
||||||
|
@ -267,10 +258,10 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
return wasUsable;
|
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<>();
|
List<Mana> baseManaPlusTriggeredMana = new ArrayList<>();
|
||||||
baseManaPlusTriggeredMana.add(baseMana);
|
baseManaPlusTriggeredMana.add(baseMana);
|
||||||
List<List<Mana>> availableTriggeredManaList = getSimulatedTriggeredManaFromPlayer(game, ability);
|
List<List<Mana>> availableTriggeredManaList = ManaOptions.getSimulatedTriggeredManaFromPlayer(game, ability);
|
||||||
for (List<Mana> availableTriggeredMana : availableTriggeredManaList) {
|
for (List<Mana> availableTriggeredMana : availableTriggeredManaList) {
|
||||||
if (availableTriggeredMana.size() == 1) {
|
if (availableTriggeredMana.size() == 1) {
|
||||||
for (Mana prevMana : baseManaPlusTriggeredMana) {
|
for (Mana prevMana : baseManaPlusTriggeredMana) {
|
||||||
|
@ -372,7 +363,7 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
Mana prevMana = currentMana.copy();
|
Mana prevMana = currentMana.copy();
|
||||||
// generic mana costs can be paid with different colored mana, can lead to different color combinations
|
// 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())) {
|
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();
|
Mana currentManaCopy = currentMana.copy();
|
||||||
while (currentManaCopy.includesMana(payCombination)) { // loop for multiple usage if possible
|
while (currentManaCopy.includesMana(payCombination)) { // loop for multiple usage if possible
|
||||||
boolean newCombinations = false;
|
boolean newCombinations = false;
|
||||||
|
@ -420,7 +411,13 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
return oldManaWasReplaced;
|
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<Mana> payCombinations = new ArrayList<>();
|
||||||
List<String> payCombinationsStrings = new ArrayList<>();
|
List<String> payCombinationsStrings = new ArrayList<>();
|
||||||
if (manaAvailable.countColored() > 0) {
|
if (manaAvailable.countColored() > 0) {
|
||||||
|
@ -439,28 +436,28 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
manaToPayFrom.subtract(existingMana);
|
manaToPayFrom.subtract(existingMana);
|
||||||
if (manaToPayFrom.getBlack() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.BlackMana(1).toString())) {
|
if (manaToPayFrom.getBlack() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.BlackMana(1).toString())) {
|
||||||
manaToPayFrom.subtract(Mana.BlackMana(1));
|
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())) {
|
if (manaToPayFrom.getBlue() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.BlueMana(1).toString())) {
|
||||||
manaToPayFrom.subtract(Mana.BlueMana(1));
|
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())) {
|
if (manaToPayFrom.getGreen() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.GreenMana(1).toString())) {
|
||||||
manaToPayFrom.subtract(Mana.GreenMana(1));
|
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())) {
|
if (manaToPayFrom.getRed() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.RedMana(1).toString())) {
|
||||||
manaToPayFrom.subtract(Mana.RedMana(1));
|
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())) {
|
if (manaToPayFrom.getWhite() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.WhiteMana(1).toString())) {
|
||||||
manaToPayFrom.subtract(Mana.WhiteMana(1));
|
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
|
// 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())) {
|
if (payCombinations.isEmpty() && manaToPayFrom.getAny() > 0 && !payCombinationsStrings.contains(existingMana.toString() + Mana.AnyMana(1).toString())) {
|
||||||
manaToPayFrom.subtract(Mana.AnyMana(1));
|
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;
|
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();
|
Mana newMana = existingMana.copy();
|
||||||
newMana.add(mana);
|
newMana.add(mana);
|
||||||
payCombinations.add(newMana);
|
payCombinations.add(newMana);
|
||||||
|
|
|
@ -9,7 +9,10 @@ import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import mage.constants.ManaType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* see 20110715 - 605.1b
|
* see 20110715 - 605.1b
|
||||||
|
@ -57,6 +60,17 @@ public abstract class TriggeredManaAbility extends TriggeredAbilityImpl implemen
|
||||||
return new ArrayList<>(netMana);
|
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.
|
* 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()) {
|
if (canUse && ability.canActivate(playerId, game).canActivate()) {
|
||||||
// abilities without Tap costs have to be handled as separate sources, because they can be used also
|
// 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();
|
it.remove();
|
||||||
Abilities<ActivatedManaAbilityImpl> noTapAbilities = new AbilitiesImpl<>(ability);
|
Abilities<ActivatedManaAbilityImpl> noTapAbilities = new AbilitiesImpl<>(ability);
|
||||||
if (ability.getManaCosts().isEmpty()) {
|
if (ability.getManaCosts().isEmpty()) {
|
||||||
|
|
Loading…
Reference in a new issue