mirror of
https://github.com/correl/mage.git
synced 2024-11-14 11:09:31 +00:00
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
|
@ -55,7 +55,7 @@ public final class BrimazBlightOfOreskos extends CardImpl {
|
|||
|
||||
// At the beginning of each end step, if a Phyrexian died under your control this turn, proliferate.
|
||||
this.addAbility(new BeginningOfEndStepTriggeredAbility(
|
||||
new ProliferateEffect(), TargetController.ANY,
|
||||
new ProliferateEffect(false), TargetController.ANY,
|
||||
BrimazBlightOfOreskosCondition.instance, false
|
||||
), new BrimazBlightOfOreskosWatcher());
|
||||
}
|
||||
|
|
|
@ -18,12 +18,11 @@ import mage.game.Game;
|
|||
import mage.game.events.CreateTokenEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.token.EmptyToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.functions.CopyApplier;
|
||||
import mage.util.functions.CopyTokenFunction;
|
||||
import mage.util.functions.EmptyCopyApplier;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
|
@ -145,8 +144,7 @@ class EsixFractalBloomEffect extends ReplacementEffectImpl {
|
|||
}
|
||||
|
||||
// create token and modify all attributes permanently (without game usage)
|
||||
EmptyToken token = new EmptyToken();
|
||||
CardUtil.copyTo(token).from(copyFromPermanent, game); // needed so that entersBattlefied triggered abilities see the attributes (e.g. Master Biomancer)
|
||||
Token token = CopyTokenFunction.createTokenCopy(copyFromPermanent, game); // needed so that entersBattlefied triggered abilities see the attributes (e.g. Master Biomancer)
|
||||
applier.apply(game, token, source, permanent.getId());
|
||||
return token;
|
||||
}
|
||||
|
|
|
@ -14,11 +14,11 @@ import mage.constants.*;
|
|||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.token.EmptyToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
import mage.target.targetpointer.FixedTargets;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.functions.CopyTokenFunction;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
@ -83,12 +83,11 @@ class GodPharaohsGiftEffect extends OneShotEffect {
|
|||
return false;
|
||||
}
|
||||
// create token and modify all attributes permanently (without game usage)
|
||||
EmptyToken token = new EmptyToken();
|
||||
CardUtil.copyTo(token).from(cardChosen, game);
|
||||
Token token = CopyTokenFunction.createTokenCopy(cardChosen, game);
|
||||
token.removePTCDA();
|
||||
token.setPower(4);
|
||||
token.setToughness(4);
|
||||
token.getColor().setColor(ObjectColor.BLACK);
|
||||
token.setColor(ObjectColor.BLACK);
|
||||
token.removeAllCreatureTypes();
|
||||
token.addSubType(SubType.ZOMBIE);
|
||||
token.putOntoBattlefield(1, game, source, source.getControllerId());
|
||||
|
|
|
@ -12,12 +12,12 @@ import mage.constants.SubType;
|
|||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.token.EmptyToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
import mage.target.targetadjustment.TargetAdjuster;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.functions.CopyTokenFunction;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
@ -91,12 +91,11 @@ class HourOfEternityEffect extends OneShotEffect {
|
|||
for (Card card : cardsToExile) {
|
||||
if (game.getState().getZone(card.getId()) == Zone.EXILED) {
|
||||
// create token and modify all attributes permanently (without game usage)
|
||||
EmptyToken token = new EmptyToken();
|
||||
CardUtil.copyTo(token).from(card, game);
|
||||
Token token = CopyTokenFunction.createTokenCopy(card, game);
|
||||
token.removePTCDA();
|
||||
token.setPower(4);
|
||||
token.setToughness(4);
|
||||
token.getColor().setColor(ObjectColor.BLACK);
|
||||
token.setColor(ObjectColor.BLACK);
|
||||
token.removeAllCreatureTypes();
|
||||
token.addSubType(SubType.ZOMBIE);
|
||||
token.putOntoBattlefield(1, game, source, source.getControllerId());
|
||||
|
|
|
@ -15,11 +15,11 @@ import mage.filter.common.FilterArtifactPermanent;
|
|||
import mage.filter.common.FilterControlledArtifactPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.token.EmptyToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetControlledPermanent;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.functions.CopyTokenFunction;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -79,8 +79,7 @@ class MechanizedProductionEffect extends OneShotEffect {
|
|||
if (sourceObject != null && sourceObject.getAttachedTo() != null) {
|
||||
Permanent enchantedArtifact = game.getPermanentOrLKIBattlefield(sourceObject.getAttachedTo());
|
||||
if (enchantedArtifact != null) {
|
||||
EmptyToken token = new EmptyToken();
|
||||
CardUtil.copyTo(token).from(enchantedArtifact, game);
|
||||
Token token = CopyTokenFunction.createTokenCopy(enchantedArtifact, game);
|
||||
token.putOntoBattlefield(1, game, source, source.getControllerId());
|
||||
}
|
||||
Map<String, Integer> countNames = new HashMap<>();
|
||||
|
|
|
@ -104,7 +104,7 @@ class MyrkulLordOfBonesEffect extends OneShotEffect {
|
|||
return new CreateTokenCopyTargetEffect().setSavedPermanent(
|
||||
new PermanentCard(CardUtil.getDefaultCardSideForBattlefield(game, card), source.getControllerId(), game)
|
||||
).setPermanentModifier((token, g) -> {
|
||||
token.getCardType().clear();
|
||||
token.removeAllCardTypes();
|
||||
token.addCardType(CardType.ENCHANTMENT);
|
||||
token.retainAllEnchantmentSubTypes(g);
|
||||
}).apply(game, source);
|
||||
|
|
|
@ -23,10 +23,11 @@ import mage.filter.predicate.mageobject.AnotherPredicate;
|
|||
import mage.game.ExileZone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.token.EmptyToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.targetpointer.FixedTargets;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.functions.CopyTokenFunction;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
@ -99,8 +100,7 @@ class PhantomSteedEffect extends OneShotEffect {
|
|||
return false;
|
||||
}
|
||||
for (Card card : exileZone.getCards(game)) {
|
||||
EmptyToken token = new EmptyToken();
|
||||
CardUtil.copyTo(token).from(card, game);
|
||||
Token token = CopyTokenFunction.createTokenCopy(card, game);
|
||||
token.addSubType(SubType.ILLUSION);
|
||||
token.putOntoBattlefield(1, game, source, source.getControllerId(), true, true);
|
||||
List<Permanent> permanents = token
|
||||
|
|
|
@ -21,10 +21,10 @@ import mage.constants.Zone;
|
|||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.token.EmptyToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetCard;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.functions.CopyTokenFunction;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -149,8 +149,7 @@ class PrototypePortalCreateTokenEffect extends OneShotEffect {
|
|||
if (!permanent.getImprinted().isEmpty()) {
|
||||
Card card = game.getCard(permanent.getImprinted().get(0));
|
||||
if (card != null) {
|
||||
EmptyToken token = new EmptyToken();
|
||||
CardUtil.copyTo(token).from(card, game);
|
||||
Token token = CopyTokenFunction.createTokenCopy(card, game);
|
||||
token.putOntoBattlefield(1, game, source, source.getControllerId());
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@ import mage.constants.Outcome;
|
|||
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.common.TargetCreaturePermanent;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.functions.CopyTokenFunction;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -62,8 +62,7 @@ class SpittingImageEffect extends OneShotEffect {
|
|||
permanent = (Permanent) game.getLastKnownInformation(source.getFirstTarget(), Zone.BATTLEFIELD);
|
||||
}
|
||||
if (permanent != null) {
|
||||
EmptyToken token = new EmptyToken();
|
||||
CardUtil.copyTo(token).from(permanent, game);
|
||||
Token token = CopyTokenFunction.createTokenCopy(permanent, game);
|
||||
token.putOntoBattlefield(1, game, source, source.getControllerId());
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -4,16 +4,11 @@ import mage.cards.ExpansionSet;
|
|||
import mage.constants.Rarity;
|
||||
import mage.constants.SetType;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class MarchOfTheMachine extends ExpansionSet {
|
||||
|
||||
private static final List<String> unfinished = Arrays.asList("Assimilate Essence", "Blighted Burgeoning", "Bloated Processor", "Chrome Host Seedshark", "Compleated Huntmaster", "Converter Beast", "Corruption of Towashi", "Elesh Norn", "The Argent Etchings", "Elvish Vatkeeper", "Essence of Orthodoxy", "Eyes of Gitaxias", "Furnace Gremlin", "Gift of Compleation", "Glissa, Herald of Predation", "Glistening Dawn", "Ichor Drinker", "Infected Defector", "Injector Crocodile", "Marauding Dreadship", "Merciless Repurposing", "Norn's Inquisitor", "Phyrexian Awakening", "Progenitor Exarch", "Sculpted Perfection", "Searing Barb", "Sunder the Gateway", "Sunfall", "Tangled Skyline", "Tiller of Flesh", "Traumatic Revelation");
|
||||
|
||||
private static final MarchOfTheMachine instance = new MarchOfTheMachine();
|
||||
|
||||
public static MarchOfTheMachine getInstance() {
|
||||
|
@ -488,8 +483,6 @@ public final class MarchOfTheMachine extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Zimone and Dina", 318, Rarity.MYTHIC, mage.cards.z.ZimoneAndDina.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Zurgo and Ojutai", 258, Rarity.MYTHIC, mage.cards.z.ZurgoAndOjutai.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Zurgo and Ojutai", 319, Rarity.MYTHIC, mage.cards.z.ZurgoAndOjutai.class, NON_FULL_USE_VARIOUS));
|
||||
|
||||
cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName())); // remove when mechanic is implemented
|
||||
}
|
||||
|
||||
// @Override
|
||||
|
|
|
@ -4,16 +4,11 @@ import mage.cards.ExpansionSet;
|
|||
import mage.constants.Rarity;
|
||||
import mage.constants.SetType;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class MarchOfTheMachineCommander extends ExpansionSet {
|
||||
|
||||
private static final List<String> unfinished = Arrays.asList("Blight Titan", "Brimaz, Blight of Oreskos", "Excise the Imperfect");
|
||||
|
||||
private static final MarchOfTheMachineCommander instance = new MarchOfTheMachineCommander();
|
||||
|
||||
public static MarchOfTheMachineCommander getInstance() {
|
||||
|
@ -367,7 +362,5 @@ public final class MarchOfTheMachineCommander extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Workshop Elders", 245, Rarity.RARE, mage.cards.w.WorkshopElders.class));
|
||||
cards.add(new SetCardInfo("Worthy Knight", 217, Rarity.RARE, mage.cards.w.WorthyKnight.class));
|
||||
cards.add(new SetCardInfo("Yawgmoth's Vile Offering", 271, Rarity.RARE, mage.cards.y.YawgmothsVileOffering.class));
|
||||
|
||||
cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName())); // remove when mechanic is implemented
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
package org.mage.test.cards.copy;
|
||||
|
||||
import mage.ObjectColor;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.permanent.Permanent;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class TokenCopyTest extends CardTestPlayerBase {
|
||||
|
||||
private static final String rite = "Rite of Replication";
|
||||
private static final String prowler = "Kessig Prowler";
|
||||
private static final String predator = "Sinuous Predator";
|
||||
private static final String brink = "Back from the Brink";
|
||||
|
||||
private void checkProwlers(int prowlerCount, int predatorCount) {
|
||||
assertPermanentCount(playerA, prowler, prowlerCount);
|
||||
assertPermanentCount(playerA, predator, predatorCount);
|
||||
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) {
|
||||
switch (permanent.getName()) {
|
||||
case prowler:
|
||||
Assert.assertEquals("Power of " + prowler + " should be 2", 2, permanent.getPower().getValue());
|
||||
Assert.assertEquals("Toughness of " + prowler + " should be 1", 1, permanent.getToughness().getValue());
|
||||
Assert.assertEquals(prowler + " should be green", ObjectColor.GREEN, permanent.getColor(currentGame));
|
||||
Assert.assertTrue(prowler + " should be a Werewolf", permanent.hasSubtype(SubType.WEREWOLF, currentGame));
|
||||
Assert.assertTrue(prowler + " should be a Horror", permanent.hasSubtype(SubType.HORROR, currentGame));
|
||||
Assert.assertFalse(prowler + " should not be an Eldrazi", permanent.hasSubtype(SubType.ELDRAZI, currentGame));
|
||||
Assert.assertEquals(prowler + " should have mana value 1", 1, permanent.getManaValue());
|
||||
Assert.assertFalse(prowler + " should not be transformed", permanent.isTransformed());
|
||||
break;
|
||||
case predator:
|
||||
Assert.assertEquals("Power of " + predator + " should be 4", 4, permanent.getPower().getValue());
|
||||
Assert.assertEquals("Toughness of " + predator + " should be 4", 4, permanent.getToughness().getValue());
|
||||
Assert.assertTrue(predator + " should be colorless", permanent.getColor(currentGame).isColorless());
|
||||
Assert.assertTrue(predator + " should be an Eldrazi", permanent.hasSubtype(SubType.ELDRAZI, currentGame));
|
||||
Assert.assertTrue(predator + " should be a Werewolf", permanent.hasSubtype(SubType.WEREWOLF, currentGame));
|
||||
Assert.assertFalse(predator + " should not be a Horror", permanent.hasSubtype(SubType.HORROR, currentGame));
|
||||
Assert.assertEquals(predator + " should have mana value 1", 1, permanent.getManaValue());
|
||||
Assert.assertTrue(prowler + " should be transformed", permanent.isTransformed());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyDFC() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerA, prowler);
|
||||
addCard(Zone.HAND, playerA, rite);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, rite, prowler);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, rite, 1);
|
||||
checkProwlers(1 + 1, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyDFCAndTransform() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 5 + 5 + 4);
|
||||
addCard(Zone.BATTLEFIELD, playerA, prowler);
|
||||
addCard(Zone.HAND, playerA, rite);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, rite, prowler);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{G}");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{G}");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, rite, 1);
|
||||
checkProwlers(0, 1 + 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyTransformedDFC() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 5 + 4);
|
||||
addCard(Zone.BATTLEFIELD, playerA, prowler);
|
||||
addCard(Zone.HAND, playerA, rite);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{G}");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, rite, predator);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, rite, 1);
|
||||
checkProwlers(0, 1 + 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackFromTheBrink() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 6 + 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, brink);
|
||||
addCard(Zone.GRAVEYARD, playerA, prowler);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Exile");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertExileCount(playerA, prowler, 1);
|
||||
checkProwlers(1, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackFromTheBrinkTransform() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 6 + 1 + 5);
|
||||
addCard(Zone.BATTLEFIELD, playerA, brink);
|
||||
addCard(Zone.GRAVEYARD, playerA, prowler);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Exile");
|
||||
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{4}{G}");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertExileCount(playerA, prowler, 1);
|
||||
checkProwlers(0, 1);
|
||||
}
|
||||
}
|
|
@ -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…
Reference in a new issue