diff --git a/Mage.Sets/src/mage/cards/c/CloisteredYouth.java b/Mage.Sets/src/mage/cards/c/CloisteredYouth.java index def252da59e..81718a2e0f3 100644 --- a/Mage.Sets/src/mage/cards/c/CloisteredYouth.java +++ b/Mage.Sets/src/mage/cards/c/CloisteredYouth.java @@ -1,34 +1,43 @@ - package mage.cards.c; -import java.util.UUID; - -import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** * @author Loki */ -public final class CloisteredYouth extends CardImpl { +public final class CloisteredYouth extends TransformingDoubleFacedCard { public CloisteredYouth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); - this.subtype.add(SubType.HUMAN); - - this.power = new MageInt(1); - this.toughness = new MageInt(1); + super( + ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN}, "{1}{W}", + "Unholy Fiend", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HORROR}, "B" + ); + this.getLeftHalfCard().setPT(1, 1); + this.getRightHalfCard().setPT(3, 3); this.secondSideCardClazz = mage.cards.u.UnholyFiend.class; // At the beginning of your upkeep, you may transform Cloistered Youth. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(), true)); + this.getLeftHalfCard().addAbility(new TransformAbility()); + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(), true)); + + // Unholy Fiend + // At the beginning of your end step, you lose 1 life. + this.getRightHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(new LoseLifeSourceControllerEffect(1))); + + this.finalizeDFC(); } private CloisteredYouth(final CloisteredYouth card) { diff --git a/Mage.Sets/src/mage/cards/u/UnholyFiend.java b/Mage.Sets/src/mage/cards/u/UnholyFiend.java index 726ca0db1bb..4650cd67dd5 100644 --- a/Mage.Sets/src/mage/cards/u/UnholyFiend.java +++ b/Mage.Sets/src/mage/cards/u/UnholyFiend.java @@ -1,33 +1,22 @@ - package mage.cards.u; -import java.util.UUID; -import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.cards.c.CloisteredYouth; import mage.constants.CardType; -import mage.constants.SubType; + +import java.util.UUID; /** - * * @author Loki */ public final class UnholyFiend extends CardImpl { public UnholyFiend(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.HORROR); - - this.color.setBlack(true); - - this.power = new MageInt(3); - this.toughness = new MageInt(3); - + super(ownerId, setInfo, new CardType[]{}, ""); this.nightCard = true; - - this.addAbility(new BeginningOfEndStepTriggeredAbility(new LoseLifeSourceControllerEffect(1))); + TransformingDoubleFacedCard.copyToBackFace(new CloisteredYouth(ownerId, setInfo), this); } private UnholyFiend(final UnholyFiend card) { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java index ad94dfaed49..1981f44a3f8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java @@ -1,8 +1,9 @@ package org.mage.test.cards.abilities.keywords; -import mage.cards.s.SpringOfEternalPeace; +import mage.ObjectColor; import mage.constants.CardType; import mage.constants.PhaseStep; +import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; import org.junit.Test; @@ -519,6 +520,54 @@ public class TransformTest extends CardTestPlayerBase { assertLife(playerB, 20); assertGraveyardCount(playerA, "Dress Down", 1); assertPermanentCount(playerA, "Huntmaster of the Fells", 1); - assertPermanentCount(playerA, 6+1+1); + assertPermanentCount(playerA, 6 + 1 + 1); + } + + /** + * The following tests exist to make sure the TDFC refactor workaround functions correctly. + * They should eventually not be necessary + */ + + private static final String youth = "Cloistered Youth"; + + @Test + public void testWorkaroundCloisteredYouth() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.HAND, playerA, youth); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, youth); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + + setStrictChooseMode(true); + execute(); + + assertPowerToughness(playerA, youth, 1, 1); + assertColor(playerA, youth, ObjectColor.WHITE, true); + assertColor(playerA, youth, ObjectColor.BLACK, false); + assertSubtype(youth, SubType.HUMAN); + assertNotSubtype(youth, SubType.HORROR); + } + + private static final String fiend = "Unholy Fiend"; + + @Test + public void testWorkaroundUnholyFiend() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.HAND, playerA, youth); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, youth); + setChoice(playerA, true); + setStopAt(3, PhaseStep.END_TURN); + + setStrictChooseMode(true); + execute(); + + assertPowerToughness(playerA, fiend, 3, 3); + assertColor(playerA, fiend, ObjectColor.BLACK, true); + assertColor(playerA, fiend, ObjectColor.WHITE, false); + assertSubtype(fiend, SubType.HORROR); + assertNotSubtype(fiend, SubType.HUMAN); + assertLife(playerA, 20 - 1); } } diff --git a/Mage/src/main/java/mage/cards/Card.java b/Mage/src/main/java/mage/cards/Card.java index 8882c14869d..9f842f74ae2 100644 --- a/Mage/src/main/java/mage/cards/Card.java +++ b/Mage/src/main/java/mage/cards/Card.java @@ -1,5 +1,6 @@ package mage.cards; +import mage.MageInt; import mage.MageObject; import mage.Mana; import mage.abilities.Abilities; @@ -250,6 +251,10 @@ public interface Card extends MageObject, Ownerable { List getAttachments(); + void setPT(int power, int toughness); + + void setPT(MageInt power, MageInt toughness); + /** * @param attachment can be any object: card, permanent, token * @param source can be null for default checks like state base diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java index 90acef7ccce..b65430bd221 100644 --- a/Mage/src/main/java/mage/cards/CardImpl.java +++ b/Mage/src/main/java/mage/cards/CardImpl.java @@ -1,5 +1,6 @@ package mage.cards; +import mage.MageInt; import mage.MageObject; import mage.MageObjectImpl; import mage.Mana; @@ -393,6 +394,17 @@ public abstract class CardImpl extends MageObjectImpl implements Card { this.abilities.setControllerId(ownerId); } + @Override + public void setPT(int power, int toughness) { + this.setPT(new MageInt(power), new MageInt(toughness)); + } + + @Override + public void setPT(MageInt power, MageInt toughness) { + this.power = power; + this.toughness = toughness; + } + @Override public UUID getControllerOrOwnerId() { return getOwnerId(); @@ -947,7 +959,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { } } } - if (controller != null && spellAbility != null && !spellAbility.getTargets().isEmpty()){ + if (controller != null && spellAbility != null && !spellAbility.getTargets().isEmpty()) { // Line of code below functionally gets the target of the aura's Enchant ability, then compares to this permanent. Enchant improperly implemented in XMage, see #9583 // Note: stillLegalTarget used exclusively to account for Dream Leash. Can be made canTarget in the event that that card is rewritten (and "stillLegalTarget" removed from TargetImpl). canAttach &= spellAbility.getTargets().get(0).copy().withNotTarget(true).stillLegalTarget(controller, this.getId(), source, game); diff --git a/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalf.java b/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalf.java index 78cba6bd606..b317bc8fca2 100644 --- a/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalf.java +++ b/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalf.java @@ -1,7 +1,5 @@ package mage.cards; -import mage.MageInt; - /** * @author JayDi85 */ @@ -9,8 +7,4 @@ public interface ModalDoubleFacedCardHalf extends SubCard @Override ModalDoubleFacedCardHalf copy(); - - void setPT(int power, int toughness); - - void setPT(MageInt power, MageInt toughness); } diff --git a/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalfImpl.java b/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalfImpl.java index 2521b78aee8..848ffbe7a40 100644 --- a/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalfImpl.java +++ b/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalfImpl.java @@ -114,17 +114,6 @@ public class ModalDoubleFacedCardHalfImpl extends CardImpl implements ModalDoubl return this.parentCard; } - @Override - public void setPT(int power, int toughness) { - this.setPT(new MageInt(power), new MageInt(toughness)); - } - - @Override - public void setPT(MageInt power, MageInt toughness) { - this.power = power; - this.toughness = toughness; - } - @Override public String getIdName() { // id must send to main card (popup card hint in game logs) diff --git a/Mage/src/main/java/mage/cards/TransformingDoubleFacedCard.java b/Mage/src/main/java/mage/cards/TransformingDoubleFacedCard.java new file mode 100644 index 00000000000..0761f05d805 --- /dev/null +++ b/Mage/src/main/java/mage/cards/TransformingDoubleFacedCard.java @@ -0,0 +1,90 @@ +package mage.cards; + +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public abstract class TransformingDoubleFacedCard extends CardImpl { + + protected TransformingDoubleFacedCardHalfImpl leftHalfCard; // main card in all zone + protected TransformingDoubleFacedCardHalfImpl rightHalfCard; // second side card, can be only in stack and battlefield zones + + public TransformingDoubleFacedCard( + UUID ownerId, CardSetInfo setInfo, + CardType[] typesLeft, SubType[] subTypesLeft, String costsLeft, + String secondSideName, + CardType[] typesRight, SubType[] subTypesRight, String colorRight + ) { + this( + ownerId, setInfo, + new SuperType[]{}, typesLeft, subTypesLeft, costsLeft, + secondSideName, + new SuperType[]{}, typesRight, subTypesRight, colorRight + ); + } + + public TransformingDoubleFacedCard( + UUID ownerId, CardSetInfo setInfo, + SuperType[] superTypesLeft, CardType[] typesLeft, SubType[] subTypesLeft, String costsLeft, + String secondSideName, + SuperType[] superTypesRight, CardType[] typesRight, SubType[] subTypesRight, String colorRight + ) { + super(ownerId, setInfo, typesLeft, costsLeft); + this.leftHalfCard = new TransformingDoubleFacedCardHalfImpl(ownerId, setInfo, costsLeft); + this.rightHalfCard = new TransformingDoubleFacedCardHalfImpl(ownerId, setInfo, ""); + for (SuperType superType : superTypesLeft) { + this.getLeftHalfCard().getSuperType().add(superType); + } + this.getLeftHalfCard().getSubtype().add(subTypesLeft); + for (SuperType superType : superTypesRight) { + this.getRightHalfCard().getSuperType().add(superType); + } + this.getRightHalfCard().addCardType(typesRight); + this.getRightHalfCard().setName(secondSideName); + this.getRightHalfCard().addSubType(subTypesRight); + this.getRightHalfCard().getColor().addColor(new ObjectColor(colorRight)); + } + + protected TransformingDoubleFacedCard(final TransformingDoubleFacedCard card) { + super(card); + this.leftHalfCard = card.leftHalfCard.copy(); + this.rightHalfCard = card.rightHalfCard.copy(); + } + + public Card getLeftHalfCard() { + return leftHalfCard; + } + + public Card getRightHalfCard() { + return rightHalfCard; + } + + protected void finalizeDFC() { + this.getSuperType().addAll(this.getLeftHalfCard().getSuperType()); + this.getCardType().addAll(this.getLeftHalfCard().getCardType()); + this.getSubtype().addAll(this.getLeftHalfCard().getSubtype()); + for (Ability ability : this.getLeftHalfCard().getAbilities()) { + this.addAbility(ability); + } + this.power = this.getLeftHalfCard().getPower().copy(); + this.toughness = this.getLeftHalfCard().getToughness().copy(); + } + + public static void copyToBackFace(TransformingDoubleFacedCard tdfc, Card card) { + card.getColor().setColor(tdfc.getRightHalfCard().getColor()); + card.getSuperType().addAll(tdfc.getRightHalfCard().getSuperType()); + card.getCardType().addAll(tdfc.getRightHalfCard().getCardType()); + card.getSubtype().addAll(tdfc.getRightHalfCard().getSubtype()); + for (Ability ability : tdfc.getRightHalfCard().getAbilities()) { + card.addAbility(ability); + } + card.setPT(tdfc.getRightHalfCard().getPower().copy(), tdfc.getRightHalfCard().getToughness().copy()); + } +} diff --git a/Mage/src/main/java/mage/cards/TransformingDoubleFacedCardHalfImpl.java b/Mage/src/main/java/mage/cards/TransformingDoubleFacedCardHalfImpl.java new file mode 100644 index 00000000000..a50afecb033 --- /dev/null +++ b/Mage/src/main/java/mage/cards/TransformingDoubleFacedCardHalfImpl.java @@ -0,0 +1,24 @@ +package mage.cards; + +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public class TransformingDoubleFacedCardHalfImpl extends CardImpl { + + TransformingDoubleFacedCardHalfImpl(UUID ownerId, CardSetInfo setInfo, String costs) { + super(ownerId, setInfo, new CardType[]{}, costs); + } + + private TransformingDoubleFacedCardHalfImpl(final TransformingDoubleFacedCardHalfImpl card) { + super(card); + } + + @Override + public TransformingDoubleFacedCardHalfImpl copy() { + return new TransformingDoubleFacedCardHalfImpl(this); + } +} diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index 7cc905df6b6..24a34b321fd 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -777,6 +777,16 @@ public class Spell extends StackObjectImpl implements Card { public void setOwnerId(UUID controllerId) { } + @Override + public void setPT(int power, int toughness) { + throw new UnsupportedOperationException("Unsupported operation"); + } + + @Override + public void setPT(MageInt power, MageInt toughness) { + throw new UnsupportedOperationException("Unsupported operation"); + } + @Override public List getRules() { return card.getRules();