* Fixed available mana calculation for Cryptic Trilobite and Titans' Nest. Added some improvements for available mana calculation of conditional mana.

This commit is contained in:
LevelX2 2020-08-16 01:16:52 +02:00
parent 3d989b24ac
commit 768f1bec4f
100 changed files with 507 additions and 144 deletions

View file

@ -52,7 +52,7 @@ public class ConditionalMana extends Mana implements Serializable {
public ConditionalMana(final ConditionalMana conditionalMana) {
super(conditionalMana);
conditions = conditionalMana.conditions;
conditions.addAll(conditionalMana.conditions);
scope = conditionalMana.scope;
staticText = conditionalMana.staticText;
manaProducerId = conditionalMana.manaProducerId;
@ -67,6 +67,10 @@ public class ConditionalMana extends Mana implements Serializable {
this.scope = scope;
}
public List<Condition> getConditions() {
return conditions;
}
public boolean apply(Ability ability, Game game, UUID manaProducerId, Cost costToPay) {
if (conditions.isEmpty()) {
throw new IllegalStateException("Conditional mana should contain at least one Condition");
@ -173,6 +177,24 @@ public class ConditionalMana extends Mana implements Serializable {
}
}
@Override
public void add(Mana mana) {
if (mana instanceof ConditionalMana) {
for (Condition condition : ((ConditionalMana) mana).getConditions()) {
addCondition(condition);
}
}
super.add(mana);
}
public String getConditionString() {
String condStr = "[";
for (Condition condition : conditions) {
condStr += condition.getManaText();
}
return condStr + "]";
}
public void add(ManaType manaType, int amount) {
switch (manaType) {
case BLACK:

View file

@ -275,6 +275,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
/**
* Adds mana from the passed in {@link Mana} object to this object.
* Ignores conditions from conditional mana
*
* @param mana mana to add to this object.
*/
@ -1111,6 +1112,17 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
* @return
*/
public static Mana getMoreValuableMana(final Mana mana1, final Mana mana2) {
String conditionString1 = "";
String conditionString2 = "";
if (mana1 instanceof ConditionalMana){
conditionString1 = ((ConditionalMana)mana1).getConditionString();
}
if (mana2 instanceof ConditionalMana){
conditionString2 = ((ConditionalMana)mana2).getConditionString();
}
if (!conditionString1.equals(conditionString2)) {
return null;
}
Mana moreMana;
Mana lessMana;
if (mana2.countColored() > mana1.countColored() || mana2.getAny() > mana1.getAny() || mana2.count() > mana1.count()) {

View file

@ -8,7 +8,7 @@ import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.Effects;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.effects.mana.ManaEffect;
import mage.abilities.hint.Hint;
import mage.abilities.mana.ActivatedManaAbilityImpl;
import mage.cards.Card;

View file

@ -16,7 +16,6 @@ import mage.players.Player;
import java.util.Optional;
import java.util.UUID;
import javax.naming.directory.InvalidAttributesException;
/**
* @author BetaSteward_at_googlemail.com

View file

@ -2,7 +2,7 @@
package mage.abilities.common;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.effects.mana.ManaEffect;
import mage.abilities.mana.TriggeredManaAbility;
import mage.constants.SetTargetPointer;
import mage.constants.Zone;

View file

@ -2,7 +2,7 @@
package mage.abilities.common;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.effects.mana.ManaEffect;
import mage.abilities.mana.TriggeredManaAbility;
import mage.constants.Zone;
import mage.game.Game;

View file

@ -5,7 +5,6 @@ import mage.game.Game;
import java.io.Serializable;
/**
* Interface describing condition occurrence.
*
@ -16,10 +15,14 @@ public interface Condition extends Serializable {
/**
* Checks the game to see if this condition applies for the given ability.
*
*
* @param game
* @param source
* @return
*/
boolean apply(Game game, Ability source);
default String getManaText() {
return "{" + this.getClass().getSimpleName() + "}";
}
}

View file

@ -3,7 +3,7 @@ package mage.abilities.decorator;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.effects.mana.ManaEffect;
import mage.abilities.effects.mana.BasicManaEffect;
import mage.choices.ChoiceColor;
import mage.game.Game;

View file

@ -6,6 +6,7 @@
package mage.abilities.effects.mana;
import mage.Mana;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.mana.builder.ConditionalManaBuilder;
/**
@ -15,7 +16,11 @@ import mage.abilities.mana.builder.ConditionalManaBuilder;
public class AddConditionalColorlessManaEffect extends AddConditionalManaEffect {
public AddConditionalColorlessManaEffect(int amount, ConditionalManaBuilder manaBuilder) {
super(Mana.ColorlessMana(amount), manaBuilder);
this(amount, manaBuilder, null);
}
public AddConditionalColorlessManaEffect(int amount, ConditionalManaBuilder manaBuilder, DynamicValue netAmount) {
super(Mana.ColorlessMana(amount), manaBuilder, netAmount);
}
public AddConditionalColorlessManaEffect(final AddConditionalColorlessManaEffect effect) {

View file

@ -5,10 +5,13 @@
*/
package mage.abilities.effects.mana;
import java.util.ArrayList;
import java.util.List;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.mana.builder.ConditionalManaBuilder;
import mage.constants.ManaType;
import mage.game.Game;
/**
@ -18,18 +21,26 @@ public class AddConditionalManaEffect extends ManaEffect {
private final Mana mana;
private final ConditionalManaBuilder manaBuilder;
private final DynamicValue netAmount;
public AddConditionalManaEffect(Mana mana, ConditionalManaBuilder manaBuilder) {
this(mana, manaBuilder, null);
}
public AddConditionalManaEffect(Mana mana, ConditionalManaBuilder manaBuilder, DynamicValue netAmount) {
super();
this.mana = mana;
this.manaBuilder = manaBuilder;
this.netAmount = netAmount;
staticText = "Add " + this.mana.toString() + ". " + manaBuilder.getRule();
}
public AddConditionalManaEffect(final AddConditionalManaEffect effect) {
super(effect);
this.mana = effect.mana.copy();
this.manaBuilder = effect.manaBuilder;
this.netAmount = effect.netAmount;
}
@Override
@ -37,6 +48,23 @@ public class AddConditionalManaEffect extends ManaEffect {
return new AddConditionalManaEffect(this);
}
@Override
public List<Mana> getNetMana(Game game, Ability source) {
if (game != null && game.inCheckPlayableState() && netAmount != null) {
List<Mana> maxAvailableMana = new ArrayList<>();
int amountAvailableMana = netAmount.calculate(game, source, this);
if (amountAvailableMana > 0) {
Mana calculatedMana = mana.copy();
for(ManaType manaType: ManaType.getTrueManaTypes()) {
calculatedMana.set(manaType, calculatedMana.get(manaType) * amountAvailableMana);
}
maxAvailableMana.add(manaBuilder.setMana(calculatedMana, source, game).build());
}
return maxAvailableMana;
}
return super.getNetMana(game, source); //To change body of generated methods, choose Tools | Templates.
}
@Override
public Mana produceMana(Game game, Ability source) {
if (game != null) {

View file

@ -7,7 +7,6 @@ import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.mana.builder.ConditionalManaBuilder;
import mage.choices.ChoiceColor;
import mage.game.Game;

View file

@ -8,7 +8,6 @@ package mage.abilities.effects.mana;
import mage.ConditionalMana;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.mana.builder.ConditionalManaBuilder;
import mage.choices.ManaChoice;
import mage.game.Game;

View file

@ -2,7 +2,6 @@ package mage.abilities.effects.mana;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.effects.common.ManaEffect;
import mage.choices.ChoiceColor;
import mage.game.Game;
import mage.game.permanent.Permanent;

View file

@ -4,7 +4,6 @@ import mage.Mana;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.common.ManaEffect;
import mage.constants.ColoredManaSymbol;
import mage.game.Game;

View file

@ -10,7 +10,6 @@ import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
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;

View file

@ -2,7 +2,6 @@ package mage.abilities.effects.mana;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.effects.common.ManaEffect;
import mage.choices.Choice;
import mage.choices.ChoiceColor;
import mage.game.Game;

View file

@ -3,7 +3,6 @@ package mage.abilities.effects.mana;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.effects.common.ManaEffect;
import mage.choices.ManaChoice;
import mage.game.Game;
import mage.players.Player;

View file

@ -7,7 +7,6 @@ package mage.abilities.effects.mana;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.effects.common.ManaEffect;
import mage.game.Game;
import mage.players.Player;

View file

@ -7,7 +7,6 @@ import mage.ConditionalMana;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.common.ManaEffect;
import mage.game.Game;
public class BasicManaEffect extends ManaEffect {
@ -28,10 +27,14 @@ public class BasicManaEffect extends ManaEffect {
}
public BasicManaEffect(ConditionalMana conditionalMana) {
this(conditionalMana, null);
}
public BasicManaEffect(ConditionalMana conditionalMana, DynamicValue netAmount) {
super();
this.manaTemplate = conditionalMana;
staticText = "add " + manaTemplate.toString() + " " + conditionalMana.getDescription();
this.netAmount = null;
this.netAmount = netAmount;
}
public BasicManaEffect(final BasicManaEffect effect) {
@ -46,7 +49,7 @@ public class BasicManaEffect extends ManaEffect {
if (game != null && game.inCheckPlayableState() && netAmount != null) {
// calculate the maximum available mana
int count = netAmount.calculate(game, source, this);
Mana computedMana = new Mana();
Mana computedMana = manaTemplate.copy(); // Copy to get condition
if (count > 0) {
if (manaTemplate.getBlack() > 0) {
computedMana.setBlack(count * manaTemplate.getBlack());

View file

@ -10,7 +10,6 @@ import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.costs.Cost;
import mage.abilities.effects.common.ManaEffect;
import mage.constants.Outcome;
import mage.game.Game;
import mage.players.Player;

View file

@ -4,7 +4,6 @@ import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.common.ManaEffect;
import mage.choices.ChoiceColor;
import mage.constants.Outcome;
import mage.game.Game;

View file

@ -1,4 +1,4 @@
package mage.abilities.effects.common;
package mage.abilities.effects.mana;
import mage.Mana;
import mage.abilities.Ability;

View file

@ -4,7 +4,7 @@ import mage.Mana;
import mage.abilities.ActivatedAbilityImpl;
import mage.abilities.costs.Cost;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.effects.mana.ManaEffect;
import mage.constants.*;
import mage.game.Game;
import mage.game.stack.Spell;

View file

@ -4,7 +4,7 @@ import mage.Mana;
import mage.abilities.Abilities;
import mage.abilities.Ability;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.effects.mana.ManaEffect;
import mage.choices.Choice;
import mage.constants.TargetController;
import mage.constants.Zone;

View file

@ -7,7 +7,7 @@ import mage.abilities.costs.Cost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.effects.mana.ManaEffect;
import mage.abilities.effects.mana.AddManaOfAnyColorEffect;
import mage.constants.Zone;
import mage.game.Game;

View file

@ -9,7 +9,7 @@ import mage.Mana;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.effects.mana.ManaEffect;
import mage.choices.Choice;
import mage.choices.ChoiceColor;
import mage.constants.ColoredManaSymbol;

View file

@ -1,7 +1,7 @@
package mage.abilities.mana;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.effects.mana.ManaEffect;
import mage.constants.Zone;
/**

View file

@ -4,7 +4,7 @@ import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.costs.Cost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.effects.mana.ManaEffect;
import mage.cards.Card;
import mage.choices.Choice;
import mage.choices.ChoiceImpl;

View file

@ -7,6 +7,7 @@ package mage.abilities.mana;
import mage.abilities.costs.Cost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.mana.AddConditionalColorlessManaEffect;
import mage.abilities.mana.builder.ConditionalManaBuilder;
import mage.constants.Zone;
@ -21,7 +22,11 @@ public class ConditionalColorlessManaAbility extends ActivatedManaAbilityImpl {
}
public ConditionalColorlessManaAbility(Cost cost, int amount, ConditionalManaBuilder manaBuilder) {
super(Zone.BATTLEFIELD, new AddConditionalColorlessManaEffect(amount, manaBuilder), cost);
this(cost, amount, manaBuilder, null);
}
public ConditionalColorlessManaAbility(Cost cost, int amount, ConditionalManaBuilder manaBuilder, DynamicValue netAmount) {
super(Zone.BATTLEFIELD, new AddConditionalColorlessManaEffect(amount, manaBuilder, netAmount), cost);
}
public ConditionalColorlessManaAbility(final ConditionalColorlessManaAbility ability) {

View file

@ -5,7 +5,7 @@ package mage.abilities.mana;
import mage.constants.Zone;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.effects.mana.ManaEffect;
import mage.constants.Duration;
/**

View file

@ -10,8 +10,10 @@ import org.apache.log4j.Logger;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import mage.ConditionalMana;
/**
* @author BetaSteward_at_googlemail.com
@ -312,15 +314,27 @@ public class ManaOptions extends ArrayList<Mana> {
/**
* Adds the given mana value to all existing options
*
*
* @param addMana Mana to add to the existing options
*/
public void addMana(Mana addMana) {
if (isEmpty()) {
this.add(new Mana());
}
for (Mana mana : this) {
mana.add(addMana);
if (addMana instanceof ConditionalMana) {
ManaOptions copy = this.copy();
this.clear();
for (Mana mana : copy) {
ConditionalMana condMana = ((ConditionalMana) addMana).copy();
condMana.add(mana);
add(condMana); // Add mana as option with condition
add(mana); // Add old mana without the condition
}
} else {
for (Mana mana : this) {
mana.add(addMana);
}
}
forceManaDeduplication();
@ -514,8 +528,15 @@ public class ManaOptions extends ArrayList<Mana> {
Set<String> list = new HashSet<>();
for (int i = this.size() - 1; i >= 0; i--) {
String s = this.get(i).toString();
if (list.contains(s)) {
String s;
if (this.get(i) instanceof ConditionalMana) {
s = this.get(i).toString() + ((ConditionalMana) this.get(i)).getConditionString();
} else {
s = this.get(i).toString();
}
if (s.isEmpty()) {
this.remove(i);
} else if (list.contains(s)) {
// remove duplicated
this.remove(i);
} else {
@ -550,4 +571,25 @@ public class ManaOptions extends ArrayList<Mana> {
}
return false;
}
public String toString() {
Iterator<Mana> it = this.iterator();
if (!it.hasNext()) {
return "[]";
}
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
Mana mana = it.next();
sb.append(mana.toString());
if (mana instanceof ConditionalMana) {
sb.append(((ConditionalMana) mana).getConditionString());
}
if (!it.hasNext()) {
return sb.append(']').toString();
}
sb.append(',').append(' ');
}
}
}

View file

@ -5,7 +5,7 @@ import java.util.List;
import mage.Mana;
import mage.abilities.costs.Cost;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.effects.mana.ManaEffect;
import mage.abilities.effects.mana.BasicManaEffect;
import mage.constants.Zone;
import mage.game.Game;

View file

@ -3,7 +3,7 @@ package mage.abilities.mana;
import mage.Mana;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.effects.mana.ManaEffect;
import mage.constants.AbilityType;
import mage.constants.Zone;
import mage.game.Game;

View file

@ -5,7 +5,10 @@
*/
package mage.abilities.mana.conditional;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.sql.rowset.Predicate;
import mage.ConditionalMana;
import mage.MageObject;
import mage.Mana;
@ -14,8 +17,14 @@ import mage.abilities.SpellAbility;
import mage.abilities.condition.Condition;
import mage.abilities.costs.Cost;
import mage.abilities.mana.builder.ConditionalManaBuilder;
import mage.cards.Card;
import mage.constants.DependencyType;
import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.FilterSpell;
import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.game.stack.Spell;
import mage.game.stack.StackObject;
/**
@ -63,6 +72,10 @@ class SpellCastManaCondition extends ManaCondition implements Condition {
public boolean apply(Game game, Ability source) {
if (source instanceof SpellAbility) {
MageObject object = game.getObject(source.getSourceId());
if (game.inCheckPlayableState() && object instanceof Card) {
Spell spell = new Spell((Card) object, (SpellAbility) source, source.getControllerId(), game.getState().getZone(source.getSourceId()));
return spell != null && filter.match(spell, source.getSourceId(), source.getControllerId(), game);
}
if ((object instanceof StackObject)) {
return filter.match((StackObject) object, source.getSourceId(), source.getControllerId(), game);
}

View file

@ -58,35 +58,35 @@ public enum ManaType {
}
return choice;
}
public static List<Mana> getManaListFromManaTypes(Set<ManaType> manaTypes, boolean onlyColors) {
public static List<Mana> getManaListFromManaTypes(Set<ManaType> manaTypes, boolean onlyColors) {
List<Mana> netManas = new ArrayList<>();
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 ((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 (!onlyColors && manaTypes.contains(ManaType.COLORLESS)) {
netManas.add(Mana.ColorlessMana(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;
}
public static Set<ManaType> getManaTypesFromManaList(Mana mana) {
Set<ManaType> manaTypes = EnumSet.noneOf(ManaType.class);
if (mana.getAny() > 0) {
@ -124,4 +124,7 @@ public enum ManaType {
}
return manaTypes;
}
public static Set<ManaType> getTrueManaTypes() {
return EnumSet.of(BLACK, BLUE, GREEN, RED, WHITE, COLORLESS);
}
}

View file

@ -3121,6 +3121,9 @@ public abstract class PlayerImpl implements Player, Serializable {
MageObjectReference permittingObject = game.getContinuousEffects().asThough(ability.getSourceId(),
AsThoughEffectType.SPEND_OTHER_MANA, ability, ability.getControllerId(), game);
for (Mana mana : abilityOptions) {
if (mana.count() == 0) {
return true;
}
for (Mana avail : availableMana) {
// TODO: SPEND_OTHER_MANA effects with getAsThoughManaType can change mana type to pay,
// but that code processing it as any color, need to test and fix another use cases
@ -3131,6 +3134,9 @@ public abstract class PlayerImpl implements Player, Serializable {
if (permittingObject != null && mana.count() <= avail.count()) {
return true;
}
if (avail instanceof ConditionalMana && !((ConditionalMana) avail).apply(ability, game, getId(), ability.getManaCosts())) {
continue;
}
if (mana.enough(avail)) { // here we need to check if spend mana as though allow to pay the mana cost
return true;
}
@ -4620,4 +4626,10 @@ public abstract class PlayerImpl implements Player, Serializable {
public SpellAbility chooseAbilityForCast(Card card, Game game, boolean noMana) {
return card.getSpellAbility();
}
@Override
public String toString() {
return getName() + " " + super.toString();
}
}