mirror of
https://github.com/magefree/mage.git
synced 2025-12-26 05:22:02 -08:00
[NEO] Implementing Compleated mechanic and hybrid phyrexian mana (ready for review) (#8677)
* [NEO] Implemented Tamiyo, Compleated Sage * replaced PhyrexianManaCost calls with ManaCostsImpl calls * updated phyrexian mana implementation * added phyrexian hybrid symbol support * updated starting loyalty implementation for planeswalkers * change compleated to singleton * implemented Compleated ability * added some missing loyalty setters * changed when loyalty is added to a walker to fix bugs * slight change to some tests to fix them from failing * fixed token issue
This commit is contained in:
parent
3709b5c098
commit
54203c16d3
293 changed files with 865 additions and 870 deletions
|
|
@ -3,7 +3,6 @@ package mage;
|
|||
import mage.abilities.Abilities;
|
||||
import mage.abilities.AbilitiesImpl;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
|
|
@ -40,6 +39,7 @@ public abstract class MageObjectImpl implements MageObject {
|
|||
protected String text;
|
||||
protected MageInt power;
|
||||
protected MageInt toughness;
|
||||
protected int startingLoyalty = -1; // -2 means X, -1 means none, 0 and up is normal
|
||||
protected boolean copy;
|
||||
protected MageObject copyFrom; // copied card INFO (used to call original adjusters)
|
||||
|
||||
|
|
@ -68,6 +68,7 @@ public abstract class MageObjectImpl implements MageObject {
|
|||
frameStyle = object.frameStyle;
|
||||
power = object.power.copy();
|
||||
toughness = object.toughness.copy();
|
||||
startingLoyalty = object.startingLoyalty;
|
||||
abilities = object.abilities.copy();
|
||||
this.cardType.addAll(object.cardType);
|
||||
this.subtype.copyFrom(object.subtype);
|
||||
|
|
@ -167,21 +168,12 @@ public abstract class MageObjectImpl implements MageObject {
|
|||
|
||||
@Override
|
||||
public int getStartingLoyalty() {
|
||||
for (Ability ab : getAbilities()) {
|
||||
if (ab instanceof PlaneswalkerEntersWithLoyaltyCountersAbility) {
|
||||
return ((PlaneswalkerEntersWithLoyaltyCountersAbility) ab).getStartingLoyalty();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return startingLoyalty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStartingLoyalty(int startingLoyalty) {
|
||||
for (Ability ab : getAbilities()) {
|
||||
if (ab instanceof PlaneswalkerEntersWithLoyaltyCountersAbility) {
|
||||
((PlaneswalkerEntersWithLoyaltyCountersAbility) ab).setStartingLoyalty(startingLoyalty);
|
||||
}
|
||||
}
|
||||
this.startingLoyalty = startingLoyalty;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -83,6 +83,16 @@ public enum ManaSymbol {
|
|||
PHYREXIAN_R("{R/P}", R, Type.PHYREXIAN, Type.COLORED, Type.MONOCOLORED),
|
||||
PHYREXIAN_B("{B/P}", B, Type.PHYREXIAN, Type.COLORED, Type.MONOCOLORED),
|
||||
PHYREXIAN_U("{U/P}", U, Type.PHYREXIAN, Type.COLORED, Type.MONOCOLORED),
|
||||
PHYREXIAN_HYBRID_WU("{W/U/P}", W, U, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
PHYREXIAN_HYBRID_WB("{W/B/P}", W, B, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
PHYREXIAN_HYBRID_UB("{U/B/P}", U, B, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
PHYREXIAN_HYBRID_UR("{U/R/P}", U, R, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
PHYREXIAN_HYBRID_BR("{B/R/P}", B, R, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
PHYREXIAN_HYBRID_BG("{B/G/P}", B, G, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
PHYREXIAN_HYBRID_RG("{R/G/P}", R, G, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
PHYREXIAN_HYBRID_RW("{R/W/P}", R, W, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
PHYREXIAN_HYBRID_GW("{G/W/P}", G, W, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
PHYREXIAN_HYBRID_GU("{G/U/P}", G, U, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
SNOW("{S}", Type.SNOW);
|
||||
|
||||
private enum Type {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@ import mage.MageIdentifier;
|
|||
import mage.MageObject;
|
||||
import mage.abilities.costs.*;
|
||||
import mage.abilities.costs.common.PayLifeCost;
|
||||
import mage.abilities.costs.mana.*;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.costs.mana.VariableManaCost;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.Effects;
|
||||
|
|
@ -536,14 +539,15 @@ public abstract class AbilityImpl implements Ability {
|
|||
while (costIterator.hasNext()) {
|
||||
ManaCost cost = costIterator.next();
|
||||
|
||||
if (cost instanceof PhyrexianManaCost) {
|
||||
PhyrexianManaCost phyrexianManaCost = (PhyrexianManaCost) cost;
|
||||
PayLifeCost payLifeCost = new PayLifeCost(2);
|
||||
if (payLifeCost.canPay(this, this, controller.getId(), game)
|
||||
&& controller.chooseUse(Outcome.LoseLife, "Pay 2 life instead of " + phyrexianManaCost.getBaseText() + '?', this, game)) {
|
||||
costIterator.remove();
|
||||
costs.add(payLifeCost);
|
||||
}
|
||||
if (!cost.isPhyrexian()) {
|
||||
continue;
|
||||
}
|
||||
PayLifeCost payLifeCost = new PayLifeCost(2);
|
||||
if (payLifeCost.canPay(this, this, controller.getId(), game)
|
||||
&& controller.chooseUse(Outcome.LoseLife, "Pay 2 life instead of " + cost.getText().replace("/P", "") + '?', this, game)) {
|
||||
costIterator.remove();
|
||||
costs.add(payLifeCost);
|
||||
manaCostsToPay.incrPhyrexianPaid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import mage.abilities.condition.Condition;
|
|||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.Costs;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.costs.mana.PhyrexianManaCost;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.Effects;
|
||||
import mage.abilities.keyword.FlashAbility;
|
||||
|
|
@ -61,19 +60,13 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
|
||||
public ActivatedAbilityImpl(Zone zone, Effect effect) {
|
||||
super(AbilityType.ACTIVATED, zone);
|
||||
if (effect != null) {
|
||||
this.addEffect(effect);
|
||||
}
|
||||
this.addEffect(effect);
|
||||
}
|
||||
|
||||
public ActivatedAbilityImpl(Zone zone, Effect effect, ManaCosts cost) {
|
||||
super(AbilityType.ACTIVATED, zone);
|
||||
if (effect != null) {
|
||||
this.addEffect(effect);
|
||||
}
|
||||
if (cost != null) {
|
||||
this.addManaCost(cost);
|
||||
}
|
||||
this.addEffect(effect);
|
||||
this.addManaCost(cost);
|
||||
}
|
||||
|
||||
public ActivatedAbilityImpl(Zone zone, Effects effects, ManaCosts cost) {
|
||||
|
|
@ -83,30 +76,18 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
this.addEffect(effect);
|
||||
}
|
||||
}
|
||||
if (cost != null) {
|
||||
this.addManaCost(cost);
|
||||
}
|
||||
this.addManaCost(cost);
|
||||
}
|
||||
|
||||
public ActivatedAbilityImpl(Zone zone, Effect effect, Cost cost) {
|
||||
super(AbilityType.ACTIVATED, zone);
|
||||
if (effect != null) {
|
||||
this.addEffect(effect);
|
||||
}
|
||||
if (cost != null) {
|
||||
if (cost instanceof PhyrexianManaCost) {
|
||||
this.addManaCost((PhyrexianManaCost) cost);
|
||||
} else {
|
||||
this.addCost(cost);
|
||||
}
|
||||
}
|
||||
this.addEffect(effect);
|
||||
this.addCost(cost);
|
||||
}
|
||||
|
||||
public ActivatedAbilityImpl(Zone zone, Effect effect, Costs<Cost> costs) {
|
||||
super(AbilityType.ACTIVATED, zone);
|
||||
if (effect != null) {
|
||||
this.addEffect(effect);
|
||||
}
|
||||
this.addEffect(effect);
|
||||
if (costs != null) {
|
||||
for (Cost cost : costs) {
|
||||
this.addCost(cost);
|
||||
|
|
@ -121,15 +102,13 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
this.addEffect(effect);
|
||||
}
|
||||
}
|
||||
if (cost != null) {
|
||||
this.addCost(cost);
|
||||
}
|
||||
this.addCost(cost);
|
||||
}
|
||||
|
||||
public ActivatedAbilityImpl(Zone zone, Effects effects, Costs<Cost> costs) {
|
||||
super(AbilityType.ACTIVATED, zone);
|
||||
for (Effect effect : effects) {
|
||||
if (effect != null) {
|
||||
if (effects != null) {
|
||||
for (Effect effect : effects) {
|
||||
this.addEffect(effect);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.effects.EntersBattlefieldEffect;
|
||||
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
|
||||
import mage.counters.CounterType;
|
||||
|
||||
/**
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class PlaneswalkerEntersWithLoyaltyCountersAbility extends EntersBattlefieldAbility {
|
||||
|
||||
private int startingLoyalty;
|
||||
|
||||
public PlaneswalkerEntersWithLoyaltyCountersAbility(int loyalty) {
|
||||
super(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(loyalty)));
|
||||
startingLoyalty = loyalty;
|
||||
setRuleVisible(false);
|
||||
}
|
||||
|
||||
public PlaneswalkerEntersWithLoyaltyCountersAbility(final PlaneswalkerEntersWithLoyaltyCountersAbility ability) {
|
||||
super(ability);
|
||||
startingLoyalty = ability.startingLoyalty;
|
||||
}
|
||||
|
||||
public int getStartingLoyalty() {
|
||||
return startingLoyalty;
|
||||
}
|
||||
|
||||
public void setStartingLoyalty(int startingLoyalty) {
|
||||
this.startingLoyalty = startingLoyalty;
|
||||
this.getEffects().clear();
|
||||
this.addEffect(new EntersBattlefieldEffect(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(startingLoyalty))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlaneswalkerEntersWithLoyaltyCountersAbility copy() {
|
||||
return new PlaneswalkerEntersWithLoyaltyCountersAbility(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ public class ColoredManaCost extends ManaCostImpl {
|
|||
|
||||
@Override
|
||||
public String getText() {
|
||||
return '{' + mana.toString() + '}';
|
||||
return '{' + mana.toString() + (this.phyrexian ? "/P" : "") + '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
|
||||
package mage.abilities.costs.mana;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
|
|
@ -10,6 +7,9 @@ import mage.constants.ColoredManaSymbol;
|
|||
import mage.game.Game;
|
||||
import mage.players.ManaPool;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class HybridManaCost extends ManaCostImpl {
|
||||
|
||||
private final ColoredManaSymbol mana1;
|
||||
|
|
@ -50,7 +50,7 @@ public class HybridManaCost extends ManaCostImpl {
|
|||
|
||||
@Override
|
||||
public String getText() {
|
||||
return '{' + mana1.toString() + '/' + mana2.toString() + '}';
|
||||
return '{' + mana1.toString() + '/' + mana2.toString() + (this.phyrexian ? "/P" : "") + '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
package mage.abilities.costs.mana;
|
||||
|
||||
import java.util.List;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
|
|
@ -11,6 +9,8 @@ import mage.filter.Filter;
|
|||
import mage.game.Game;
|
||||
import mage.players.ManaPool;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ManaCost extends Cost {
|
||||
|
||||
int manaValue();
|
||||
|
|
@ -45,4 +45,7 @@ public interface ManaCost extends Cost {
|
|||
@Override
|
||||
ManaCost copy();
|
||||
|
||||
boolean isPhyrexian();
|
||||
|
||||
void setPhyrexian(boolean phyrexian);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost {
|
|||
protected Mana cost;
|
||||
protected ManaOptions options;
|
||||
protected Filter sourceFilter;
|
||||
protected boolean phyrexian = false;
|
||||
|
||||
public ManaCostImpl() {
|
||||
payment = new Mana();
|
||||
|
|
@ -41,6 +42,7 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost {
|
|||
if (manaCost.sourceFilter != null) {
|
||||
this.sourceFilter = manaCost.sourceFilter.copy();
|
||||
}
|
||||
this.phyrexian = manaCost.phyrexian;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -288,4 +290,17 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost {
|
|||
public String toString() {
|
||||
return getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPhyrexian() {
|
||||
return phyrexian;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPhyrexian(boolean phyrexian) {
|
||||
if (phyrexian) {
|
||||
this.options.add(Mana.GenericMana(0));
|
||||
}
|
||||
this.phyrexian = phyrexian;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,4 +54,8 @@ public interface ManaCosts<T extends ManaCost> extends List<T>, ManaCost {
|
|||
.collect(Collectors.toCollection(ManaCostsImpl::new));
|
||||
|
||||
}
|
||||
|
||||
void incrPhyrexianPaid();
|
||||
|
||||
int getPhyrexianPaid();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
|
||||
protected final UUID id;
|
||||
protected String text = null;
|
||||
protected boolean phyrexian = false;
|
||||
private int phyrexianPaid = 0;
|
||||
|
||||
private static final Map<String, ManaCosts> costsCache = new ConcurrentHashMap<>(); // must be thread safe, can't use nulls
|
||||
|
||||
|
|
@ -46,6 +48,7 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
for (T cost : costs) {
|
||||
this.add(cost.copy());
|
||||
}
|
||||
this.phyrexian = costs.phyrexian;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -175,58 +178,53 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
|
||||
while (manaCostIterator.hasNext()) {
|
||||
ManaCost manaCost = manaCostIterator.next();
|
||||
if (manaCost instanceof PhyrexianManaCost) {
|
||||
PhyrexianManaCost phyrexianManaCost = (PhyrexianManaCost) manaCost;
|
||||
PayLifeCost payLifeCost = new PayLifeCost(2);
|
||||
if (payLifeCost.canPay(abilityToPay, source, payingPlayer.getId(), game)
|
||||
&& payingPlayer.chooseUse(Outcome.LoseLife, "Pay 2 life instead of " + phyrexianManaCost.getBaseText() + '?', source, game)) {
|
||||
manaCostIterator.remove();
|
||||
tempCosts.add(payLifeCost);
|
||||
}
|
||||
if (!manaCost.isPhyrexian()) {
|
||||
continue;
|
||||
}
|
||||
PayLifeCost payLifeCost = new PayLifeCost(2);
|
||||
if (payLifeCost.canPay(abilityToPay, source, payingPlayer.getId(), game)
|
||||
&& payingPlayer.chooseUse(Outcome.LoseLife, "Pay 2 life instead of " + manaCost.getText().replace("/P", "") + '?', source, game)) {
|
||||
manaCostIterator.remove();
|
||||
tempCosts.add(payLifeCost);
|
||||
this.incrPhyrexianPaid();
|
||||
}
|
||||
}
|
||||
|
||||
tempCosts.pay(source, game, source, payingPlayer.getId(), false, null);
|
||||
}
|
||||
|
||||
|
||||
private void handleLikePhyrexianManaCosts(Player player, Ability source, Game game) {
|
||||
if (this.isEmpty()) {
|
||||
return; // nothing to be done without any mana costs. prevents NRE from occurring here
|
||||
}
|
||||
FilterMana phyrexianColors = player.getPhyrexianColors();
|
||||
if (player.getPhyrexianColors() != null) {
|
||||
Costs<PayLifeCost> tempCosts = new CostsImpl<>();
|
||||
|
||||
Iterator<T> manaCostIterator = this.iterator();
|
||||
while (manaCostIterator.hasNext()) {
|
||||
ManaCost manaCost = manaCostIterator.next();
|
||||
Mana mana = manaCost.getMana();
|
||||
PhyrexianManaCost tempPhyrexianCost = null;
|
||||
|
||||
/* find which color mana is in the cost and set it in the temp Phyrexian cost */
|
||||
if (phyrexianColors.isWhite() && mana.getWhite() > 0) {
|
||||
tempPhyrexianCost = new PhyrexianManaCost(ColoredManaSymbol.W);
|
||||
} else if (phyrexianColors.isBlue() && mana.getBlue() > 0) {
|
||||
tempPhyrexianCost = new PhyrexianManaCost(ColoredManaSymbol.U);
|
||||
} else if (phyrexianColors.isBlack() && mana.getBlack() > 0) {
|
||||
tempPhyrexianCost = new PhyrexianManaCost(ColoredManaSymbol.B);
|
||||
} else if (phyrexianColors.isRed() && mana.getRed() > 0) {
|
||||
tempPhyrexianCost = new PhyrexianManaCost(ColoredManaSymbol.R);
|
||||
} else if (phyrexianColors.isGreen() && mana.getGreen() > 0) {
|
||||
tempPhyrexianCost = new PhyrexianManaCost(ColoredManaSymbol.G);
|
||||
}
|
||||
|
||||
if (tempPhyrexianCost != null) {
|
||||
PayLifeCost payLifeCost = new PayLifeCost(2);
|
||||
if (payLifeCost.canPay(source, source, player.getId(), game)
|
||||
&& player.chooseUse(Outcome.LoseLife, "Pay 2 life (using an active ability) instead of " + tempPhyrexianCost.getBaseText() + '?', source, game)) {
|
||||
manaCostIterator.remove();
|
||||
tempCosts.add(payLifeCost);
|
||||
}
|
||||
}
|
||||
}
|
||||
tempCosts.pay(source, game, source, player.getId(), false, null);
|
||||
if (player.getPhyrexianColors() == null) {
|
||||
return;
|
||||
}
|
||||
Costs<PayLifeCost> tempCosts = new CostsImpl<>();
|
||||
|
||||
Iterator<T> manaCostIterator = this.iterator();
|
||||
while (manaCostIterator.hasNext()) {
|
||||
ManaCost manaCost = manaCostIterator.next();
|
||||
Mana mana = manaCost.getMana();
|
||||
|
||||
/* find which color mana is in the cost and set it in the temp Phyrexian cost */
|
||||
if ((!phyrexianColors.isWhite() || mana.getWhite() <= 0)
|
||||
&& (!phyrexianColors.isBlue() || mana.getBlue() <= 0)
|
||||
&& (!phyrexianColors.isBlack() || mana.getBlack() <= 0)
|
||||
&& (!phyrexianColors.isRed() || mana.getRed() <= 0)
|
||||
&& (!phyrexianColors.isGreen() || mana.getGreen() <= 0)) {
|
||||
continue;
|
||||
}
|
||||
PayLifeCost payLifeCost = new PayLifeCost(2);
|
||||
if (payLifeCost.canPay(source, source, player.getId(), game)
|
||||
&& player.chooseUse(Outcome.LoseLife, "Pay 2 life (using an active ability) instead of " + manaCost.getMana() + '?', source, game)) {
|
||||
manaCostIterator.remove();
|
||||
tempCosts.add(payLifeCost);
|
||||
}
|
||||
}
|
||||
tempCosts.pay(source, game, source, player.getId(), false, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -447,49 +445,57 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
for (ManaCost cost : savedCosts) {
|
||||
this.add(cost.copy());
|
||||
}
|
||||
} else {
|
||||
String[] symbols = mana.split("^\\{|}\\{|}$");
|
||||
int modifierForX = 0;
|
||||
for (String symbol : symbols) {
|
||||
if (!symbol.isEmpty()) {
|
||||
if (symbol.length() == 1 || isNumeric(symbol)) {
|
||||
if (Character.isDigit(symbol.charAt(0))) {
|
||||
this.add(new GenericManaCost(Integer.valueOf(symbol)));
|
||||
} else if (symbol.equals("S")) {
|
||||
this.add(new SnowManaCost());
|
||||
} else if (symbol.equals("C")) {
|
||||
this.add(new ColorlessManaCost(1));
|
||||
} else if (!symbol.equals("X")) {
|
||||
this.add(new ColoredManaCost(ColoredManaSymbol.lookup(symbol.charAt(0))));
|
||||
} else // check X wasn't added before
|
||||
if (modifierForX == 0) {
|
||||
// count X occurence
|
||||
for (String s : symbols) {
|
||||
if (s.equals("X")) {
|
||||
modifierForX++;
|
||||
}
|
||||
}
|
||||
this.add(new VariableManaCost(VariableCostType.NORMAL, modifierForX));
|
||||
} //TODO: handle multiple {X} and/or {Y} symbols
|
||||
} else if (Character.isDigit(symbol.charAt(0))) {
|
||||
MonoHybridManaCost cost;
|
||||
if (extractMonoHybridGenericValue) {
|
||||
// for tests only, no usage in real game
|
||||
cost = new MonoHybridManaCost(ColoredManaSymbol.lookup(symbol.charAt(2)), Integer.parseInt(symbol.substring(0, 1)));
|
||||
} else {
|
||||
cost = new MonoHybridManaCost(ColoredManaSymbol.lookup(symbol.charAt(2)));
|
||||
return;
|
||||
}
|
||||
String[] symbols = mana.split("^\\{|}\\{|}$");
|
||||
int modifierForX = 0;
|
||||
for (String symbol : symbols) {
|
||||
if (symbol.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (symbol.length() == 1 || isNumeric(symbol)) {
|
||||
if (Character.isDigit(symbol.charAt(0))) {
|
||||
this.add(new GenericManaCost(Integer.valueOf(symbol)));
|
||||
} else if (symbol.equals("S")) {
|
||||
this.add(new SnowManaCost());
|
||||
} else if (symbol.equals("C")) {
|
||||
this.add(new ColorlessManaCost(1));
|
||||
} else if (!symbol.equals("X")) {
|
||||
this.add(new ColoredManaCost(ColoredManaSymbol.lookup(symbol.charAt(0))));
|
||||
} else // check X wasn't added before
|
||||
if (modifierForX == 0) {
|
||||
// count X occurence
|
||||
for (String s : symbols) {
|
||||
if (s.equals("X")) {
|
||||
modifierForX++;
|
||||
}
|
||||
}
|
||||
this.add(cost);
|
||||
} else if (symbol.contains("P")) {
|
||||
this.add(new PhyrexianManaCost(ColoredManaSymbol.lookup(symbol.charAt(0))));
|
||||
} else {
|
||||
this.add(new HybridManaCost(ColoredManaSymbol.lookup(symbol.charAt(0)), ColoredManaSymbol.lookup(symbol.charAt(2))));
|
||||
}
|
||||
this.add(new VariableManaCost(VariableCostType.NORMAL, modifierForX));
|
||||
} //TODO: handle multiple {X} and/or {Y} symbols
|
||||
} else if (Character.isDigit(symbol.charAt(0))) {
|
||||
MonoHybridManaCost cost;
|
||||
if (extractMonoHybridGenericValue) {
|
||||
// for tests only, no usage in real game
|
||||
cost = new MonoHybridManaCost(ColoredManaSymbol.lookup(symbol.charAt(2)), Integer.parseInt(symbol.substring(0, 1)));
|
||||
} else {
|
||||
cost = new MonoHybridManaCost(ColoredManaSymbol.lookup(symbol.charAt(2)));
|
||||
}
|
||||
this.add(cost);
|
||||
} else {
|
||||
boolean phyrexian = symbol.contains("/P");
|
||||
String without = symbol.replace("/P", "");
|
||||
ManaCost cost;
|
||||
if (without.length() == 1) {
|
||||
cost = new ColoredManaCost(ColoredManaSymbol.lookup(without.charAt(0)));
|
||||
} else {
|
||||
cost = new HybridManaCost(ColoredManaSymbol.lookup(without.charAt(0)), ColoredManaSymbol.lookup(without.charAt(2)));
|
||||
}
|
||||
cost.setPhyrexian(phyrexian);
|
||||
this.add(cost);
|
||||
}
|
||||
if (!extractMonoHybridGenericValue) {
|
||||
costsCache.put(mana, this.copy());
|
||||
}
|
||||
}
|
||||
if (!extractMonoHybridGenericValue) {
|
||||
costsCache.put(mana, this.copy());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -597,6 +603,29 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
return new ManaCostsImpl<>(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPhyrexian() {
|
||||
return phyrexian;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPhyrexian(boolean phyrexian) {
|
||||
this.phyrexian = phyrexian;
|
||||
for (T cost : this) {
|
||||
cost.setPhyrexian(phyrexian);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrPhyrexianPaid() {
|
||||
this.phyrexianPaid++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPhyrexianPaid() {
|
||||
return phyrexianPaid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter getSourceFilter() {
|
||||
for (T cost : this) {
|
||||
|
|
|
|||
|
|
@ -1,40 +0,0 @@
|
|||
|
||||
package mage.abilities.costs.mana;
|
||||
|
||||
import mage.Mana;
|
||||
import mage.constants.ColoredManaSymbol;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author nantuko
|
||||
*/
|
||||
public class PhyrexianManaCost extends ColoredManaCost {
|
||||
|
||||
public PhyrexianManaCost(ColoredManaSymbol mana) {
|
||||
super(mana);
|
||||
options.add(Mana.GenericMana(0));
|
||||
}
|
||||
|
||||
public PhyrexianManaCost(PhyrexianManaCost manaCost) {
|
||||
super(manaCost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return '{' + mana.toString() + "/P}";
|
||||
}
|
||||
|
||||
public String getBaseText() {
|
||||
return super.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColoredManaCost getUnpaid() {
|
||||
return new ColoredManaCost(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PhyrexianManaCost copy() {
|
||||
return new PhyrexianManaCost(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -132,6 +132,7 @@ public class CopyEffect extends ContinuousEffectImpl {
|
|||
// and abilities that were chosen for this creature as it entered the battlefield. (2018-03-16)
|
||||
permanent.getPower().setValue(copyFromObject.getPower().getBaseValueModified());
|
||||
permanent.getToughness().setValue(copyFromObject.getToughness().getBaseValueModified());
|
||||
permanent.setStartingLoyalty(copyFromObject.getStartingLoyalty());
|
||||
if (copyFromObject instanceof Permanent) {
|
||||
Permanent targetPermanent = (Permanent) copyFromObject;
|
||||
permanent.setTransformed(targetPermanent.isTransformed());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.MageSingleton;
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.constants.Zone;
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class CompleatedAbility extends StaticAbility implements MageSingleton {
|
||||
|
||||
private static final CompleatedAbility instance;
|
||||
|
||||
static {
|
||||
instance = new CompleatedAbility();
|
||||
}
|
||||
|
||||
private Object readResolve() throws ObjectStreamException {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static CompleatedAbility getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private CompleatedAbility() {
|
||||
super(Zone.ALL, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "compleated";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompleatedAbility copy() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -66,6 +66,7 @@ public class TransformAbility extends SimpleStaticAbility {
|
|||
}
|
||||
permanent.getPower().modifyBaseValue(sourceCard.getPower().getValue());
|
||||
permanent.getToughness().modifyBaseValue(sourceCard.getToughness().getValue());
|
||||
permanent.setStartingLoyalty(sourceCard.getStartingLoyalty());
|
||||
}
|
||||
|
||||
public static Card transformCardSpellStatic(Card mainSide, Card otherSide, Game game) {
|
||||
|
|
|
|||
|
|
@ -4,9 +4,7 @@ import com.j256.ormlite.field.DataType;
|
|||
import com.j256.ormlite.field.DatabaseField;
|
||||
import com.j256.ormlite.table.DatabaseTable;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility;
|
||||
import mage.cards.*;
|
||||
import mage.cards.mock.MockCard;
|
||||
import mage.cards.mock.MockSplitCard;
|
||||
|
|
@ -246,13 +244,15 @@ public class CardInfo {
|
|||
|
||||
// Starting loyalty
|
||||
if (card.isPlaneswalker()) {
|
||||
for (Ability ab : card.getAbilities()) {
|
||||
if (ab instanceof PlaneswalkerEntersWithLoyaltyCountersAbility) {
|
||||
this.startingLoyalty = "" + ((PlaneswalkerEntersWithLoyaltyCountersAbility) ab).getStartingLoyalty();
|
||||
}
|
||||
}
|
||||
if (this.startingLoyalty == null) {
|
||||
this.startingLoyalty = "";
|
||||
switch (card.getStartingLoyalty()) {
|
||||
case -2:
|
||||
this.startingLoyalty = "X";
|
||||
break;
|
||||
case -1:
|
||||
this.startingLoyalty = "";
|
||||
break;
|
||||
default:
|
||||
this.startingLoyalty = "" + card.getStartingLoyalty();
|
||||
}
|
||||
} else {
|
||||
this.startingLoyalty = "";
|
||||
|
|
@ -491,8 +491,8 @@ public class CardInfo {
|
|||
if (o == null || !(o instanceof CardInfo)) return false;
|
||||
CardInfo other = (CardInfo) o;
|
||||
return (this.name.equals(other.name)
|
||||
&& this.setCode.equals(other.setCode)
|
||||
&& this.cardNumber.equals(other.cardNumber));
|
||||
&& this.setCode.equals(other.setCode)
|
||||
&& this.cardNumber.equals(other.cardNumber));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ public class PermanentCard extends PermanentImpl {
|
|||
private void init(Card card, Game game) {
|
||||
power = card.getPower().copy();
|
||||
toughness = card.getToughness().copy();
|
||||
startingLoyalty = card.getStartingLoyalty();
|
||||
copyFromCard(card, game);
|
||||
// if temporary added abilities to the spell/card exist, you need to add it to the permanent derived from that card
|
||||
Abilities<Ability> otherAbilities = game.getState().getAllOtherAbilities(card.getId());
|
||||
|
|
|
|||
|
|
@ -1123,19 +1123,35 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
MorphAbility.setPermanentToFaceDownCreature(this, game);
|
||||
}
|
||||
|
||||
EntersTheBattlefieldEvent event = new EntersTheBattlefieldEvent(this, source, getControllerId(), fromZone, EnterEventType.SELF);
|
||||
if (game.replaceEvent(new EntersTheBattlefieldEvent(this, source, getControllerId(), fromZone, EnterEventType.SELF))) {
|
||||
return false;
|
||||
}
|
||||
EntersTheBattlefieldEvent event = new EntersTheBattlefieldEvent(this, source, getControllerId(), fromZone);
|
||||
if (game.replaceEvent(event)) {
|
||||
return false;
|
||||
}
|
||||
event = new EntersTheBattlefieldEvent(this, source, getControllerId(), fromZone);
|
||||
if (!game.replaceEvent(event)) {
|
||||
if (fireEvent) {
|
||||
game.addSimultaneousEvent(event);
|
||||
return true;
|
||||
if (this.isPlaneswalker(game)) {
|
||||
int loyalty;
|
||||
if (this.getStartingLoyalty() == -2) {
|
||||
loyalty = source.getManaCostsToPay().getX();
|
||||
} else {
|
||||
loyalty = this.getStartingLoyalty();
|
||||
}
|
||||
int countersToAdd;
|
||||
if (this.hasAbility(CompleatedAbility.getInstance(), game)) {
|
||||
countersToAdd = loyalty - 2 * source.getManaCostsToPay().getPhyrexianPaid();
|
||||
} else {
|
||||
countersToAdd = loyalty;
|
||||
}
|
||||
if (countersToAdd > 0) {
|
||||
this.addCounters(CounterType.LOYALTY.createInstance(countersToAdd), source, game);
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
if (!fireEvent) {
|
||||
return false;
|
||||
}
|
||||
game.addSimultaneousEvent(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ public class PermanentToken extends PermanentImpl {
|
|||
this.supertype.addAll(token.getSuperType());
|
||||
this.subtype.copyFrom(token.getSubtype(game));
|
||||
this.tokenDescriptor = token.getTokenDescriptor();
|
||||
this.startingLoyalty = token.getStartingLoyalty();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||
import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.filter.FilterCard;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class TamiyosNotebookToken extends TokenImpl {
|
||||
|
||||
private static final FilterCard filter = new FilterCard("spells");
|
||||
|
||||
public TamiyosNotebookToken() {
|
||||
super("Tamiyo's Notebook", "Tamiyo's Notebook, a legendary colorless artifact token with \"Spells you cast cost {2} less to cast\" and \"{T}: Draw a card.\"");
|
||||
addSuperType(SuperType.LEGENDARY);
|
||||
this.cardType.add(CardType.ARTIFACT);
|
||||
this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 2)));
|
||||
this.addAbility(new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new TapSourceCost()));
|
||||
}
|
||||
|
||||
public TamiyosNotebookToken(final TamiyosNotebookToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public TamiyosNotebookToken copy() {
|
||||
return new TamiyosNotebookToken(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -92,6 +92,7 @@ public class CopyTokenFunction implements Function<Token, Card> {
|
|||
|
||||
target.getPower().modifyBaseValue(sourceObj.getPower().getBaseValueModified());
|
||||
target.getToughness().modifyBaseValue(sourceObj.getToughness().getBaseValueModified());
|
||||
target.setStartingLoyalty(sourceObj.getStartingLoyalty());
|
||||
|
||||
return target;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue