forked from External/mage
Implement DFC tokens for Incubate (#10231)
* remove incubate skip * initial implementation of DFC tokens * separate incubator back face to separate class * small refactor to token copy function * token copies now have back faces as well * effects which modify token copies now correctly apply to both faces * add skip for exception * tokens now enter transformed correctly * [MOC] remove skip for incubate * fix verify failure
This commit is contained in:
parent
f8d23ff56b
commit
726e289646
30 changed files with 540 additions and 156 deletions
|
|
@ -246,6 +246,10 @@ public interface MageObject extends MageItem, Serializable, Copyable<MageObject>
|
|||
getSuperType().add(superType);
|
||||
}
|
||||
|
||||
default void removeSuperType(SuperType superType) {
|
||||
getSuperType().remove(superType);
|
||||
}
|
||||
|
||||
default boolean isBasic() {
|
||||
return getSuperType().contains(SuperType.BASIC);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@ import mage.constants.*;
|
|||
import mage.counters.CounterType;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.token.EmptyToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.target.targetpointer.FixedTargets;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.functions.CopyApplier;
|
||||
import mage.util.functions.CopyTokenFunction;
|
||||
import mage.util.functions.EmptyCopyApplier;
|
||||
|
||||
import java.util.*;
|
||||
|
|
@ -200,14 +200,13 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
|
|||
}
|
||||
|
||||
// create token and modify all attributes permanently (without game usage)
|
||||
EmptyToken token = new EmptyToken();
|
||||
CardUtil.copyTo(token).from(copyFrom, game); // needed so that entersBattlefied triggered abilities see the attributes (e.g. Master Biomancer)
|
||||
Token token = CopyTokenFunction.createTokenCopy(copyFrom, game); // needed so that entersBattlefied triggered abilities see the attributes (e.g. Master Biomancer)
|
||||
applier.apply(game, token, source, targetId);
|
||||
if (becomesArtifact) {
|
||||
token.addCardType(CardType.ARTIFACT);
|
||||
}
|
||||
if (isntLegendary) {
|
||||
token.getSuperType().remove(SuperType.LEGENDARY);
|
||||
token.removeSuperType(SuperType.LEGENDARY);
|
||||
}
|
||||
|
||||
if (startingLoyalty != -1) {
|
||||
|
|
@ -238,7 +237,7 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
|
|||
token.addSubType(additionalSubType);
|
||||
}
|
||||
if (color != null) {
|
||||
token.getColor().setColor(color);
|
||||
token.setColor(color);
|
||||
}
|
||||
additionalAbilities.stream().forEach(token::addAbility);
|
||||
if (permanentModifier != null) {
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ import mage.constants.TimingRule;
|
|||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.token.EmptyToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.functions.CopyTokenFunction;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
|
@ -87,11 +87,10 @@ class EmbalmEffect extends OneShotEffect {
|
|||
}
|
||||
|
||||
// create token and modify all attributes permanently (without game usage)
|
||||
EmptyToken token = new EmptyToken();
|
||||
CardUtil.copyTo(token).from(card, game); // needed so that entersBattlefied triggered abilities see the attributes (e.g. Master Biomancer)
|
||||
token.getColor().setColor(ObjectColor.WHITE);
|
||||
Token token = CopyTokenFunction.createTokenCopy(card, game); // needed so that entersBattlefied triggered abilities see the attributes (e.g. Master Biomancer)
|
||||
token.setColor(ObjectColor.WHITE);
|
||||
token.addSubType(SubType.ZOMBIE);
|
||||
token.getManaCost().clear();
|
||||
token.clearManaCost();
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.EMBALMED_CREATURE, token.getId(), source, controller.getId()));
|
||||
token.putOntoBattlefield(1, game, source, controller.getId(), false, false, null);
|
||||
// Probably it makes sense to remove also the Embalm ability (it's not shown on the token cards).
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@ import mage.constants.TimingRule;
|
|||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.token.EmptyToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.functions.CopyTokenFunction;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
|
@ -85,8 +85,7 @@ class EncoreEffect extends OneShotEffect {
|
|||
if (card == null) {
|
||||
return false;
|
||||
}
|
||||
EmptyToken token = new EmptyToken();
|
||||
CardUtil.copyTo(token).from(card, game);
|
||||
Token token = CopyTokenFunction.createTokenCopy(card, game);
|
||||
Set<MageObjectReference> addedTokens = new HashSet<>();
|
||||
int opponentCount = OpponentsCount.instance.calculate(game, source, this);
|
||||
if (opponentCount < 1) {
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ import mage.constants.TimingRule;
|
|||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.token.EmptyToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.functions.CopyTokenFunction;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
|
@ -91,11 +91,10 @@ class EternalizeEffect extends OneShotEffect {
|
|||
}
|
||||
|
||||
// create token and modify all attributes permanently (without game usage)
|
||||
EmptyToken token = new EmptyToken();
|
||||
CardUtil.copyTo(token).from(card, game); // needed so that entersBattlefied triggered abilities see the attributes (e.g. Master Biomancer)
|
||||
token.getColor().setColor(ObjectColor.BLACK);
|
||||
Token token = CopyTokenFunction.createTokenCopy(card, game); // needed so that entersBattlefied triggered abilities see the attributes (e.g. Master Biomancer)
|
||||
token.setColor(ObjectColor.BLACK);
|
||||
token.addSubType(SubType.ZOMBIE);
|
||||
token.getManaCost().clear();
|
||||
token.clearManaCost();
|
||||
token.removePTCDA();
|
||||
token.setPower(4);
|
||||
token.setToughness(4);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
|
|
@ -9,6 +10,7 @@ import mage.constants.*;
|
|||
import mage.game.Game;
|
||||
import mage.game.MageObjectAttribute;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
|
|
@ -38,7 +40,7 @@ public class TransformAbility extends SimpleStaticAbility {
|
|||
return "";
|
||||
}
|
||||
|
||||
public static void transformPermanent(Permanent permanent, Card sourceCard, Game game, Ability source) {
|
||||
public static void transformPermanent(Permanent permanent, MageObject sourceCard, Game game, Ability source) {
|
||||
if (sourceCard == null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -58,9 +60,10 @@ public class TransformAbility extends SimpleStaticAbility {
|
|||
for (SuperType type : sourceCard.getSuperType()) {
|
||||
permanent.addSuperType(type);
|
||||
}
|
||||
|
||||
if (sourceCard instanceof Card) {
|
||||
permanent.setExpansionSetCode(((Card) sourceCard).getExpansionSetCode());
|
||||
}
|
||||
CardUtil.copySetAndCardNumber(permanent, sourceCard);
|
||||
|
||||
permanent.getAbilities().clear();
|
||||
for (Ability ability : sourceCard.getAbilities()) {
|
||||
// source == null -- call from init card (e.g. own abilities)
|
||||
|
|
@ -144,7 +147,12 @@ class TransformEffect extends ContinuousEffectImpl {
|
|||
return true;
|
||||
}
|
||||
|
||||
Card card = permanent.getSecondCardFace();
|
||||
MageObject card;
|
||||
if (permanent instanceof PermanentToken) {
|
||||
card = ((PermanentToken) permanent).getToken().getBackFace();
|
||||
} else {
|
||||
card = permanent.getSecondCardFace();
|
||||
}
|
||||
|
||||
if (card == null) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -18,11 +18,10 @@ import mage.constants.TimingRule;
|
|||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.command.Emblem;
|
||||
import mage.game.permanent.token.EmptyToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.game.permanent.token.custom.CreatureToken;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.RandomUtil;
|
||||
import mage.util.functions.CopyTokenFunction;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -79,7 +78,7 @@ class MomirEffect extends OneShotEffect {
|
|||
}
|
||||
|
||||
// search for a random non custom set creature
|
||||
EmptyToken token = null;
|
||||
Token token = null;
|
||||
while (!options.isEmpty()) {
|
||||
int index = RandomUtil.nextInt(options.size());
|
||||
ExpansionSet expansionSet = Sets.findSet(options.get(index).getSetCode());
|
||||
|
|
@ -88,8 +87,7 @@ class MomirEffect extends OneShotEffect {
|
|||
} else {
|
||||
Card card = options.get(index).getCard();
|
||||
if (card != null) {
|
||||
token = new EmptyToken();
|
||||
CardUtil.copyTo(token).from(card, game);
|
||||
token = CopyTokenFunction.createTokenCopy(card, game);
|
||||
break;
|
||||
} else {
|
||||
options.remove(index);
|
||||
|
|
|
|||
|
|
@ -609,7 +609,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
return true;
|
||||
}
|
||||
|
||||
private Card getOtherFace() {
|
||||
protected MageObject getOtherFace() {
|
||||
return transformed ? this.getMainCard() : this.getMainCard().getSecondCardFace();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import mage.MageObject;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.keyword.ChangelingAbility;
|
||||
import mage.abilities.keyword.TransformAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.EmptyNames;
|
||||
import mage.game.Game;
|
||||
|
|
@ -28,6 +29,9 @@ public class PermanentToken extends PermanentImpl {
|
|||
this.power = new MageInt(token.getPower().getModifiedBaseValue());
|
||||
this.toughness = new MageInt(token.getToughness().getModifiedBaseValue());
|
||||
this.copyFromToken(this.token, game, false); // needed to have at this time (e.g. for subtypes for entersTheBattlefield replacement effects)
|
||||
if (this.token.isEntersTransformed()) {
|
||||
TransformAbility.transformPermanent(this, this.token.getBackFace(), game, null);
|
||||
}
|
||||
|
||||
// token's ZCC must be synced with original token to keep abilities settings
|
||||
// Example: kicker ability and kicked status
|
||||
|
|
@ -50,6 +54,14 @@ public class PermanentToken extends PermanentImpl {
|
|||
this.toughness.resetToBaseValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getManaValue() {
|
||||
if (this.isTransformed()) {
|
||||
return token.getManaValue();
|
||||
}
|
||||
return super.getManaValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if (name.isEmpty()) {
|
||||
|
|
@ -121,6 +133,16 @@ public class PermanentToken extends PermanentImpl {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransformable() {
|
||||
return token.getBackFace() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MageObject getOtherFace() {
|
||||
return this.transformed ? token : this.token.getBackFace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCardNumber() {
|
||||
return token.getOriginalCardNumber();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.game.permanent.token;
|
||||
|
||||
/**
|
||||
|
|
@ -7,7 +6,14 @@ package mage.game.permanent.token;
|
|||
public final class EmptyToken extends TokenImpl {
|
||||
|
||||
public EmptyToken() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public EmptyToken(boolean withBackFace) {
|
||||
super(" Token", "");
|
||||
if (withBackFace) {
|
||||
this.backFace = new EmptyToken();
|
||||
}
|
||||
}
|
||||
|
||||
public EmptyToken(final EmptyToken token) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.common.TransformSourceEffect;
|
||||
import mage.abilities.keyword.TransformAbility;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
|
|
@ -14,9 +18,12 @@ public final class IncubatorToken extends TokenImpl {
|
|||
super("Incubator Token", "Incubator artifact token with \"{2}: Transform this artifact.\"");
|
||||
cardType.add(CardType.ARTIFACT);
|
||||
subtype.add(SubType.INCUBATOR);
|
||||
this.backFace = new Phyrexian00Token();
|
||||
|
||||
// TODO: Implement this correctly
|
||||
|
||||
this.addAbility(new TransformAbility());
|
||||
this.addAbility(new SimpleActivatedAbility(
|
||||
new TransformSourceEffect().setText("transform this artifact"), new GenericManaCost(2)
|
||||
));
|
||||
availableImageSetCodes = Arrays.asList("MOM");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class Phyrexian00Token extends TokenImpl {
|
||||
|
||||
Phyrexian00Token() {
|
||||
super("Phyrexian Token", "0/0 Phyrexian artifact creature token");
|
||||
cardType.add(CardType.ARTIFACT);
|
||||
cardType.add(CardType.CREATURE);
|
||||
subtype.add(SubType.PHYREXIAN);
|
||||
power = new MageInt(0);
|
||||
toughness = new MageInt(0);
|
||||
|
||||
availableImageSetCodes = Arrays.asList("MOM");
|
||||
}
|
||||
|
||||
public Phyrexian00Token(final Phyrexian00Token token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public Phyrexian00Token copy() {
|
||||
return new Phyrexian00Token(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.cards.Card;
|
||||
import mage.game.Game;
|
||||
|
|
@ -58,4 +59,14 @@ public interface Token extends MageObject {
|
|||
void setCopySourceCard(Card copySourceCard);
|
||||
|
||||
void setExpansionSetCodeForImage(String code);
|
||||
|
||||
Token getBackFace();
|
||||
|
||||
void setColor(ObjectColor color);
|
||||
|
||||
void clearManaCost();
|
||||
|
||||
void setEntersTransformed(boolean entersTransformed);
|
||||
|
||||
boolean isEntersTransformed();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package mage.game.permanent.token;
|
|||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectImpl;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
|
|
@ -12,9 +13,7 @@ import mage.cards.Card;
|
|||
import mage.cards.repository.TokenInfo;
|
||||
import mage.cards.repository.TokenRepository;
|
||||
import mage.cards.repository.TokenType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.command.CommandObject;
|
||||
import mage.game.events.CreateTokenEvent;
|
||||
|
|
@ -45,21 +44,8 @@ public abstract class TokenImpl extends MageObjectImpl implements Token {
|
|||
// list of set codes token images are available for
|
||||
protected List<String> availableImageSetCodes = new ArrayList<>(); // TODO: delete
|
||||
|
||||
public enum Type {
|
||||
|
||||
FIRST(1),
|
||||
SECOND(2);
|
||||
|
||||
int code;
|
||||
|
||||
Type(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
int getCode() {
|
||||
return this.code;
|
||||
}
|
||||
}
|
||||
protected Token backFace = null;
|
||||
private boolean entersTransformed = false;
|
||||
|
||||
public TokenImpl() {
|
||||
}
|
||||
|
|
@ -69,7 +55,7 @@ public abstract class TokenImpl extends MageObjectImpl implements Token {
|
|||
this.description = description;
|
||||
}
|
||||
|
||||
public TokenImpl(final TokenImpl token) {
|
||||
protected TokenImpl(final TokenImpl token) {
|
||||
super(token);
|
||||
this.description = token.description;
|
||||
this.tokenType = token.tokenType;
|
||||
|
|
@ -78,6 +64,8 @@ public abstract class TokenImpl extends MageObjectImpl implements Token {
|
|||
this.originalExpansionSetCode = token.originalExpansionSetCode;
|
||||
this.copySourceCard = token.copySourceCard; // will never be changed
|
||||
this.availableImageSetCodes = token.availableImageSetCodes;
|
||||
this.backFace = token.backFace != null ? token.backFace.copy() : null;
|
||||
this.entersTransformed = token.entersTransformed;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -98,11 +86,17 @@ public abstract class TokenImpl extends MageObjectImpl implements Token {
|
|||
ability.setSourceId(this.getId());
|
||||
abilities.add(ability);
|
||||
abilities.addAll(ability.getSubAbilities());
|
||||
if (backFace != null) {
|
||||
backFace.addAbility(ability);
|
||||
}
|
||||
}
|
||||
|
||||
// Directly from PermanentImpl
|
||||
@Override
|
||||
public void removeAbility(Ability abilityToRemove) {
|
||||
if (backFace != null) {
|
||||
backFace.removeAbility(abilityToRemove);
|
||||
}
|
||||
if (abilityToRemove == null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -127,6 +121,9 @@ public abstract class TokenImpl extends MageObjectImpl implements Token {
|
|||
}
|
||||
|
||||
abilitiesToRemove.forEach(a -> removeAbility(a));
|
||||
if (backFace != null) {
|
||||
backFace.removeAbilities(abilitiesToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -389,11 +386,17 @@ public abstract class TokenImpl extends MageObjectImpl implements Token {
|
|||
|
||||
@Override
|
||||
public void setPower(int power) {
|
||||
if (this.backFace != null) {
|
||||
this.backFace.setPower(power);
|
||||
}
|
||||
this.power = new MageInt(power);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setToughness(int toughness) {
|
||||
if (this.backFace != null) {
|
||||
this.backFace.setToughness(toughness);
|
||||
}
|
||||
this.toughness = new MageInt(toughness);
|
||||
}
|
||||
|
||||
|
|
@ -426,6 +429,21 @@ public abstract class TokenImpl extends MageObjectImpl implements Token {
|
|||
return originalExpansionSetCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStartingLoyalty(int startingLoyalty) {
|
||||
if (backFace != null) {
|
||||
backFace.setStartingLoyalty(startingLoyalty);
|
||||
}
|
||||
super.setStartingLoyalty(startingLoyalty);
|
||||
}
|
||||
|
||||
public void setStartingDefense(int intArg) {
|
||||
if (backFace != null) {
|
||||
backFace.setStartingDefense(intArg);
|
||||
}
|
||||
super.setStartingDefense(intArg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOriginalExpansionSetCode(String originalExpansionSetCode) {
|
||||
// TODO: delete
|
||||
|
|
@ -451,4 +469,167 @@ public abstract class TokenImpl extends MageObjectImpl implements Token {
|
|||
// TODO: delete
|
||||
setOriginalExpansionSetCode(code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token getBackFace() {
|
||||
return backFace;
|
||||
}
|
||||
|
||||
public void retainAllArtifactSubTypes(Game game) {
|
||||
if (backFace != null) {
|
||||
backFace.retainAllArtifactSubTypes(game);
|
||||
}
|
||||
super.retainAllArtifactSubTypes(game);
|
||||
}
|
||||
|
||||
public void retainAllEnchantmentSubTypes(Game game) {
|
||||
if (backFace != null) {
|
||||
backFace.retainAllEnchantmentSubTypes(game);
|
||||
}
|
||||
super.retainAllEnchantmentSubTypes(game);
|
||||
}
|
||||
|
||||
public void addSuperType(SuperType superType) {
|
||||
if (backFace != null) {
|
||||
backFace.addSuperType(superType);
|
||||
}
|
||||
super.addSuperType(superType);
|
||||
}
|
||||
|
||||
public void removeSuperType(SuperType superType) {
|
||||
if (backFace != null) {
|
||||
backFace.removeSuperType(superType);
|
||||
}
|
||||
super.removeSuperType(superType);
|
||||
}
|
||||
|
||||
public void addCardType(CardType... cardTypes) {
|
||||
if (backFace != null) {
|
||||
backFace.addCardType(cardTypes);
|
||||
}
|
||||
super.addCardType(cardTypes);
|
||||
}
|
||||
|
||||
public void removeCardType(CardType... cardTypes) {
|
||||
if (backFace != null) {
|
||||
backFace.removeCardType(cardTypes);
|
||||
}
|
||||
super.removeCardType(cardTypes);
|
||||
}
|
||||
|
||||
public void removeAllCardTypes() {
|
||||
if (backFace != null) {
|
||||
backFace.removeAllCardTypes();
|
||||
}
|
||||
super.removeAllCardTypes();
|
||||
}
|
||||
|
||||
public void removeAllCardTypes(Game game) {
|
||||
if (backFace != null) {
|
||||
backFace.removeAllCardTypes(game);
|
||||
}
|
||||
super.removeAllCardTypes(game);
|
||||
}
|
||||
|
||||
public void addSubType(SubType... subTypes) {
|
||||
if (backFace != null) {
|
||||
backFace.addSubType(subTypes);
|
||||
}
|
||||
super.addSubType(subTypes);
|
||||
}
|
||||
|
||||
public void removeAllSubTypes(Game game, SubTypeSet subTypeSet) {
|
||||
if (backFace != null) {
|
||||
backFace.removeAllSubTypes(game, subTypeSet);
|
||||
}
|
||||
super.removeAllSubTypes(game, subTypeSet);
|
||||
}
|
||||
|
||||
public void removeAllSubTypes(Game game) {
|
||||
if (backFace != null) {
|
||||
backFace.removeAllSubTypes(game);
|
||||
}
|
||||
super.removeAllSubTypes(game);
|
||||
}
|
||||
|
||||
public void retainAllLandSubTypes(Game game) {
|
||||
if (backFace != null) {
|
||||
backFace.retainAllLandSubTypes(game);
|
||||
}
|
||||
super.retainAllLandSubTypes(game);
|
||||
}
|
||||
|
||||
public void removeAllCreatureTypes(Game game) {
|
||||
if (backFace != null) {
|
||||
backFace.removeAllCreatureTypes(game);
|
||||
}
|
||||
super.removeAllCreatureTypes(game);
|
||||
}
|
||||
|
||||
public void removeAllCreatureTypes() {
|
||||
if (backFace != null) {
|
||||
backFace.removeAllCreatureTypes();
|
||||
}
|
||||
super.removeAllCreatureTypes();
|
||||
}
|
||||
|
||||
public void removeSubType(Game game, SubType subType) {
|
||||
if (backFace != null) {
|
||||
backFace.removeSubType(game, subType);
|
||||
}
|
||||
super.removeSubType(game, subType);
|
||||
}
|
||||
|
||||
public void setIsAllCreatureTypes(boolean value) {
|
||||
if (backFace != null) {
|
||||
backFace.setIsAllCreatureTypes(value);
|
||||
}
|
||||
super.setIsAllCreatureTypes(value);
|
||||
}
|
||||
|
||||
public void removePTCDA() {
|
||||
if (backFace != null) {
|
||||
backFace.removePTCDA();
|
||||
}
|
||||
super.removePTCDA();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
if (backFace != null) {
|
||||
backFace.getName();
|
||||
}
|
||||
return super.getName();
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
if (backFace != null) {
|
||||
backFace.setName(name);
|
||||
}
|
||||
super.setName(name);
|
||||
}
|
||||
|
||||
public void setColor(ObjectColor color) {
|
||||
if (backFace != null) {
|
||||
backFace.setColor(color);
|
||||
}
|
||||
this.getColor().setColor(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearManaCost() {
|
||||
if (backFace != null) {
|
||||
backFace.clearManaCost();
|
||||
}
|
||||
this.getManaCost().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntersTransformed(boolean entersTransformed) {
|
||||
this.entersTransformed = entersTransformed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEntersTransformed() {
|
||||
return this.entersTransformed && this.backFace != null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,12 +25,13 @@ import mage.game.events.CopiedStackObjectEvent;
|
|||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentCard;
|
||||
import mage.game.permanent.token.EmptyToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.GameLog;
|
||||
import mage.util.ManaUtil;
|
||||
import mage.util.SubTypes;
|
||||
import mage.util.functions.CopyTokenFunction;
|
||||
import mage.util.functions.StackObjectCopyApplier;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
|
|
@ -275,8 +276,7 @@ public class Spell extends StackObjectImpl implements Card {
|
|||
UUID permId;
|
||||
boolean flag;
|
||||
if (isCopy()) {
|
||||
EmptyToken token = new EmptyToken();
|
||||
CardUtil.copyTo(token).from(card, game, this);
|
||||
Token token = CopyTokenFunction.createTokenCopy(card, game, this);
|
||||
// The token that a resolving copy of a spell becomes isn’t said to have been “created.” (2020-09-25)
|
||||
if (token.putOntoBattlefield(1, game, ability, getControllerId(), false, false, null, false)) {
|
||||
permId = token.getLastAddedTokenIds().stream().findFirst().orElse(null);
|
||||
|
|
@ -343,8 +343,7 @@ public class Spell extends StackObjectImpl implements Card {
|
|||
return false;
|
||||
}
|
||||
} else if (isCopy()) {
|
||||
EmptyToken token = new EmptyToken();
|
||||
CardUtil.copyTo(token).from(card, game, this);
|
||||
Token token = CopyTokenFunction.createTokenCopy(card, game, this);
|
||||
// The token that a resolving copy of a spell becomes isn’t said to have been “created.” (2020-09-25)
|
||||
token.putOntoBattlefield(1, game, ability, getControllerId(), false, false, null, false);
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ import mage.players.Player;
|
|||
import mage.target.Target;
|
||||
import mage.target.TargetCard;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.functions.CopyTokenFunction;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
|
@ -474,17 +473,6 @@ public final class CardUtil {
|
|||
spellAbility.getManaCostsToPay().addAll(adjustedCost);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns function that copies params\abilities from one card to
|
||||
* {@link Token}.
|
||||
*
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public static CopyTokenFunction copyTo(Token target) {
|
||||
return new CopyTokenFunction(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an integer number to string Numbers > 20 will be returned as
|
||||
* digits
|
||||
|
|
@ -1821,6 +1809,9 @@ public final class CardUtil {
|
|||
needSetCode = ((Card) copyFromObject).getExpansionSetCode();
|
||||
needCardNumber = ((Card) copyFromObject).getCardNumber();
|
||||
needTokenType = 0;
|
||||
} else if (copyFromObject instanceof Token) {
|
||||
// TODO: make this work
|
||||
return;
|
||||
} else {
|
||||
throw new IllegalStateException("Unsupported copyFromObject class: " + copyFromObject.getClass().getSimpleName());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,64 +7,95 @@ import mage.cards.Card;
|
|||
import mage.constants.CardType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentCard;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.game.permanent.token.EmptyToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.game.stack.Spell;
|
||||
|
||||
/**
|
||||
* @author nantuko
|
||||
*/
|
||||
public class CopyTokenFunction implements Function<Token, Card> {
|
||||
public class CopyTokenFunction {
|
||||
|
||||
protected Token target;
|
||||
protected final Token target;
|
||||
|
||||
public CopyTokenFunction(Token target) {
|
||||
private CopyTokenFunction(Token target) {
|
||||
if (target == null) {
|
||||
throw new IllegalArgumentException("Target can't be null");
|
||||
}
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token apply(Card source, Game game) {
|
||||
public static Token createTokenCopy(Card source, Game game) {
|
||||
return createTokenCopy(source, game, null);
|
||||
}
|
||||
|
||||
public static Token createTokenCopy(Card source, Game game, Spell spell) {
|
||||
return new CopyTokenFunction(new EmptyToken(source.isTransformable())).from(source, game, spell);
|
||||
}
|
||||
|
||||
public void apply(Card source, Game game) {
|
||||
if (target == null) {
|
||||
throw new IllegalArgumentException("Target can't be null");
|
||||
}
|
||||
// A copy contains only the attributes of the basic card or basic Token that's the base of the permanent
|
||||
// else gained abililies would be copied too.
|
||||
|
||||
MageObject sourceObj = source;
|
||||
target.setEntersTransformed(source instanceof Permanent && ((Permanent) source).isTransformed());
|
||||
MageObject sourceObj;
|
||||
if (source instanceof PermanentToken) {
|
||||
// create token from another token
|
||||
sourceObj = ((PermanentToken) source).getToken();
|
||||
Token sourceToken = ((PermanentToken) source).getToken();
|
||||
sourceObj = sourceToken;
|
||||
copyToToken(target, sourceObj, game);
|
||||
if (sourceToken.getBackFace() != null) {
|
||||
target.getBackFace().setOriginalExpansionSetCode(sourceToken.getOriginalExpansionSetCode());
|
||||
target.getBackFace().setOriginalCardNumber(sourceToken.getOriginalCardNumber());
|
||||
target.getBackFace().setCopySourceCard(sourceToken.getBackFace().getCopySourceCard());
|
||||
copyToToken(target.getBackFace(), sourceToken.getBackFace(), game);
|
||||
}
|
||||
// to show the source image, the original values have to be used
|
||||
target.setOriginalExpansionSetCode(((Token) sourceObj).getOriginalExpansionSetCode());
|
||||
target.setOriginalCardNumber(((Token) sourceObj).getOriginalCardNumber());
|
||||
target.setOriginalExpansionSetCode(sourceToken.getOriginalExpansionSetCode());
|
||||
target.setOriginalCardNumber(sourceToken.getOriginalCardNumber());
|
||||
target.setCopySourceCard(((PermanentToken) source).getToken().getCopySourceCard());
|
||||
} else if (source instanceof PermanentCard) {
|
||||
return;
|
||||
}
|
||||
if (source instanceof PermanentCard) {
|
||||
// create token from non-token permanent
|
||||
if (((PermanentCard) source).isMorphed() || ((PermanentCard) source).isManifested()) {
|
||||
MorphAbility.setPermanentToFaceDownCreature(target, game);
|
||||
return target;
|
||||
} else {
|
||||
if (((PermanentCard) source).isTransformed() && source.getSecondCardFace() != null) {
|
||||
sourceObj = ((PermanentCard) source).getSecondCardFace();
|
||||
} else {
|
||||
sourceObj = ((PermanentCard) source).getCard();
|
||||
}
|
||||
|
||||
target.setOriginalExpansionSetCode(source.getExpansionSetCode());
|
||||
target.setOriginalCardNumber(source.getCardNumber());
|
||||
target.setCopySourceCard((Card) sourceObj);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// create token from non-permanent object like card (example: Embalm ability)
|
||||
sourceObj = ((PermanentCard) source).getMainCard();
|
||||
copyToToken(target, sourceObj, game);
|
||||
if (((Card) sourceObj).isTransformable()) {
|
||||
target.getBackFace().setOriginalExpansionSetCode(source.getExpansionSetCode());
|
||||
target.getBackFace().setOriginalCardNumber(source.getCardNumber());
|
||||
target.getBackFace().setCopySourceCard(((Card) sourceObj).getSecondCardFace());
|
||||
copyToToken(target.getBackFace(), ((Card) sourceObj).getSecondCardFace(), game);
|
||||
}
|
||||
|
||||
target.setOriginalExpansionSetCode(source.getExpansionSetCode());
|
||||
target.setOriginalCardNumber(source.getCardNumber());
|
||||
target.setCopySourceCard(source);
|
||||
target.setCopySourceCard((Card) sourceObj);
|
||||
return;
|
||||
}
|
||||
sourceObj = source;
|
||||
copyToToken(target, sourceObj, game);
|
||||
if (source.isTransformable()) {
|
||||
target.getBackFace().setOriginalExpansionSetCode(source.getExpansionSetCode());
|
||||
target.getBackFace().setOriginalCardNumber(source.getCardNumber());
|
||||
target.getBackFace().setCopySourceCard(source.getSecondCardFace());
|
||||
copyToToken(target.getBackFace(), source.getSecondCardFace(), game);
|
||||
}
|
||||
// create token from non-permanent object like card (example: Embalm ability)
|
||||
target.setOriginalExpansionSetCode(source.getExpansionSetCode());
|
||||
target.setOriginalCardNumber(source.getCardNumber());
|
||||
target.setCopySourceCard(source);
|
||||
}
|
||||
|
||||
private static Token copyToToken(Token target, MageObject sourceObj, Game game) {
|
||||
// modify all attributes permanently (without game usage)
|
||||
target.setName(sourceObj.getName());
|
||||
target.getColor().setColor(sourceObj.getColor());
|
||||
|
|
@ -101,11 +132,7 @@ public class CopyTokenFunction implements Function<Token, Card> {
|
|||
return target;
|
||||
}
|
||||
|
||||
public Token from(Card source, Game game) {
|
||||
return from(source, game, null);
|
||||
}
|
||||
|
||||
public Token from(Card source, Game game, Spell spell) {
|
||||
private Token from(Card source, Game game, Spell spell) {
|
||||
apply(source, game);
|
||||
|
||||
// token's ZCC must be synced with original card to keep abilities settings
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
package mage.util.functions;
|
||||
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* @author nantuko
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Function<X, Y> {
|
||||
X apply(Y in, Game game);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue