mirror of
https://github.com/magefree/mage.git
synced 2025-12-25 13:02:06 -08: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
|
|
@ -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…
Add table
Add a link
Reference in a new issue