diff --git a/forge-game/src/main/java/forge/game/Match.java b/forge-game/src/main/java/forge/game/Match.java index 8ed54d83122..714755fb119 100644 --- a/forge-game/src/main/java/forge/game/Match.java +++ b/forge-game/src/main/java/forge/game/Match.java @@ -288,7 +288,7 @@ public class Match { if (!lostOwnership.isEmpty()) { List lostPaperOwnership = new ArrayList<>(); for(Card c : lostOwnership) { - lostPaperOwnership.add(c.getPaperCard()); + lostPaperOwnership.add((PaperCard)c.getPaperCard()); } if (outcome.anteResult.containsKey(fromGame)) { outcome.anteResult.get(fromGame).addLost(lostPaperOwnership); @@ -300,7 +300,7 @@ public class Match { if (!gainedOwnership.isEmpty()) { List gainedPaperOwnership = new ArrayList<>(); for(Card c : gainedOwnership) { - gainedPaperOwnership.add(c.getPaperCard()); + gainedPaperOwnership.add((PaperCard)c.getPaperCard()); } if (outcome.anteResult.containsKey(fromGame)) { outcome.anteResult.get(fromGame).addWon(gainedPaperOwnership); diff --git a/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java index c87d8e2652a..2b6e33a5673 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java @@ -6,6 +6,7 @@ import forge.game.Game; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; +import forge.game.card.CardCharacteristics; import forge.game.card.CardFactory; import forge.game.card.CardFactoryUtil; import forge.game.card.CardUtil; @@ -105,8 +106,7 @@ public class CloneEffect extends SpellAbilityEffect { tgtCard.addAlternateState(CardCharacteristicName.Cloner); tgtCard.switchStates(CardCharacteristicName.Original, CardCharacteristicName.Cloner); tgtCard.setState(CardCharacteristicName.Original); - } - else { + } else { //copy Original state to Cloned tgtCard.addAlternateState(CardCharacteristicName.Cloned); tgtCard.switchStates(CardCharacteristicName.Original, CardCharacteristicName.Cloned); @@ -114,51 +114,34 @@ public class CloneEffect extends SpellAbilityEffect { tgtCard.setState(CardCharacteristicName.Original); } } - - CardCharacteristicName stateToCopy = null; + + final CardCharacteristicName origState = cardToCopy.getCurState(); if (copyingSelf) { - stateToCopy = CardCharacteristicName.Cloned; + cardToCopy.setState(CardCharacteristicName.Cloned); } - else if (cardToCopy.isFlipCard()) { - stateToCopy = CardCharacteristicName.Original; - } - else { - stateToCopy = cardToCopy.getCurState(); + CardFactory.copyCopiableCharacteristics(cardToCopy, tgtCard); + if (copyingSelf) { + cardToCopy.setState(origState); } - CardFactory.copyState(cardToCopy, stateToCopy, tgtCard); // must call this before addAbilityFactoryAbilities so cloned added abilities are handled correctly addExtraCharacteristics(tgtCard, sa, origSVars); - CardFactoryUtil.addAbilityFactoryAbilities(tgtCard); - for (int i = 0; i < tgtCard.getStaticAbilityStrings().size(); i++) { - tgtCard.addStaticAbility(tgtCard.getStaticAbilityStrings().get(i)); - } + CardFactory.copyCopiableAbilities(cardToCopy, tgtCard); + + // restore name if it should be unchanged if (keepName) { - tgtCard.setName(originalName); + tgtCard.setName(originalName); } - // If target is a flipped card, also copy the flipped + // If target is a flip card, also set characteristics of the flipped // state. if (cardToCopy.isFlipCard()) { - if (!copyingSelf) { - tgtCard.addAlternateState(CardCharacteristicName.Flipped); - tgtCard.setState(CardCharacteristicName.Flipped); - } - CardFactory.copyState(cardToCopy, CardCharacteristicName.Flipped, tgtCard); - addExtraCharacteristics(tgtCard, sa, origSVars); - CardFactoryUtil.addAbilityFactoryAbilities(tgtCard); - for (int i = 0; i < tgtCard.getStaticAbilityStrings().size(); i++) { - tgtCard.addStaticAbility(tgtCard.getStaticAbilityStrings().get(i)); - } + final CardCharacteristics flippedState = tgtCard.getState(CardCharacteristicName.Flipped); if (keepName) { - tgtCard.setName(originalName); + flippedState.setName(originalName); } //keep the Clone card image for the cloned card - tgtCard.setImageKey(imageFileName); - - if (tgtCard.getCurState() != CardCharacteristicName.Flipped) { - tgtCard.setState(CardCharacteristicName.Original); - } + flippedState.setImageKey(imageFileName); } //Clean up copy of cloned state @@ -263,7 +246,7 @@ public class CloneEffect extends SpellAbilityEffect { } } - // set power of clone + // set ETB tapped of clone if (sa.hasParam("IntoPlayTapped")) { tgtCard.setTapped(true); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java index 90d07fb393f..dbd9dea65df 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java @@ -6,7 +6,6 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import forge.StaticData; -import forge.card.CardCharacteristicName; import forge.card.CardRulesPredicates; import forge.game.Game; import forge.game.GameEntity; @@ -15,7 +14,6 @@ import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.card.CardFactory; -import forge.game.card.CardFactoryUtil; import forge.game.card.CardLists; import forge.game.player.Player; import forge.game.spellability.SpellAbility; @@ -148,102 +146,13 @@ public class CopyPermanentEffect extends SpellAbilityEffect { for (final Card c : tgtCards) { if ((tgt == null) || c.canBeTargetedBy(sa)) { - boolean wasInAlt = false; - CardCharacteristicName stateName = CardCharacteristicName.Original; - if (c.isInAlternateState()) { - stateName = c.getCurState(); - wasInAlt = true; - c.setState(CardCharacteristicName.Original); - } - - // start copied Kiki code int multiplier = numCopies * hostCard.getController().getTokenDoublersMagnitude(); final List crds = new ArrayList(multiplier); for (int i = 0; i < multiplier; i++) { - // TODO Use central copy methods - Card copy; - if (!c.isToken() || c.isCopiedToken()) { - // copy creature and put it onto the battlefield - - copy = CardFactory.getCard(c.getPaperCard(), sa.getActivatingPlayer()); - - copy.setToken(true); - copy.setCopiedToken(true); - } else { // isToken() - copy = CardFactory.copyStats(c, controller); - - copy.setName(c.getName()); - copy.setImageKey(c.getImageKey()); - - copy.setManaCost(c.getManaCost()); - copy.setColor(c.getColor()); - copy.setToken(true); - - copy.setType(c.getType()); - - copy.setBaseAttack(c.getBaseAttack()); - copy.setBaseDefense(c.getBaseDefense()); - - CardFactoryUtil.addAbilityFactoryAbilities(copy); - for (String s : copy.getStaticAbilityStrings()) { - copy.addStaticAbility(s); - } - } - - // when copying something stolen: - copy.setController(controller, 0); - copy.setCurSetCode(c.getCurSetCode()); - - if (c.isDoubleFaced()) { // Cloned DFC's can't transform - if (wasInAlt) { - copy.setState(CardCharacteristicName.Transformed); - } - } - if (c.isFlipCard()) { // Cloned Flips CAN flip. - copy.setState(CardCharacteristicName.Original); - c.setState(CardCharacteristicName.Original); - copy.setImageKey(c.getImageKey()); - if (!c.isInAlternateState()) { - copy.setState(CardCharacteristicName.Flipped); - } - - c.setState(CardCharacteristicName.Flipped); - } - - if (c.isFaceDown()) { - c.setState(CardCharacteristicName.FaceDown); - } - - if (sa.hasParam("AttachedTo")) { - List list = AbilityUtils.getDefinedCards(hostCard, - sa.getParam("AttachedTo"), sa); - if (list.isEmpty()) { - list = copy.getController().getGame().getCardsIn(ZoneType.Battlefield); - list = CardLists.getValidCards(list, sa.getParam("AttachedTo"), copy.getController(), copy); - } - if (!list.isEmpty()) { - Card attachedTo = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(list, sa, copy + " - Select a card to attach to."); - if (copy.isAura()) { - if (attachedTo.canBeEnchantedBy(copy)) { - copy.enchantEntity(attachedTo); - } else {//can't enchant - continue; - } - } else if (copy.isEquipment()) { //Equipment - if (attachedTo.canBeEquippedBy(copy)) { - copy.equipCard(attachedTo); - } else { - continue; - } - } else { // Fortification - copy.fortifyCard(attachedTo); - } - } else { - continue; - } - } - + final Card copy = CardFactory.copyCopiableCharacteristics(c, sa.getActivatingPlayer()); + copy.setToken(true); + copy.setCopiedToken(true); // add keywords from sa for (final String kw : keywords) { copy.addIntrinsicKeyword(kw); @@ -260,20 +169,55 @@ public class CopyPermanentEffect extends SpellAbilityEffect { final Trigger parsedTrigger = TriggerHandler.parseTrigger(actualTrigger, copy, false); copy.addTrigger(parsedTrigger); } - copy = game.getAction().moveToPlay(copy); + CardFactory.copyCopiableAbilities(c, copy); - copy.setCloneOrigin(hostCard); - sa.getHostCard().addClone(copy); - crds.add(copy); + final Card copyInPlay = game.getAction().moveToPlay(copy); + + // when copying something stolen: + copyInPlay.setController(controller, 0); + copyInPlay.setCurSetCode(c.getCurSetCode()); + + copyInPlay.setCloneOrigin(hostCard); + sa.getHostCard().addClone(copyInPlay); + crds.add(copyInPlay); if (sa.hasParam("RememberCopied")) { - hostCard.addRemembered(copy); + hostCard.addRemembered(copyInPlay); } if (sa.hasParam("Tapped")) { - copy.setTapped(true); + copyInPlay.setTapped(true); } if (sa.hasParam("CopyAttacking") && game.getPhaseHandler().inCombat()) { final GameEntity defender = AbilityUtils.getDefinedPlayers(hostCard, sa.getParam("CopyAttacking"), sa).get(0); - game.getCombat().addAttacker(copy, defender); + game.getCombat().addAttacker(copyInPlay, defender); + } + + if (sa.hasParam("AttachedTo")) { + List list = AbilityUtils.getDefinedCards(hostCard, + sa.getParam("AttachedTo"), sa); + if (list.isEmpty()) { + list = copyInPlay.getController().getGame().getCardsIn(ZoneType.Battlefield); + list = CardLists.getValidCards(list, sa.getParam("AttachedTo"), copyInPlay.getController(), copyInPlay); + } + if (!list.isEmpty()) { + Card attachedTo = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(list, sa, copyInPlay + " - Select a card to attach to."); + if (copyInPlay.isAura()) { + if (attachedTo.canBeEnchantedBy(copyInPlay)) { + copyInPlay.enchantEntity(attachedTo); + } else {//can't enchant + continue; + } + } else if (copyInPlay.isEquipment()) { //Equipment + if (attachedTo.canBeEquippedBy(copyInPlay)) { + copyInPlay.equipCard(attachedTo); + } else { + continue; + } + } else { // Fortification + copyInPlay.fortifyCard(attachedTo); + } + } else { + continue; + } } } @@ -282,10 +226,6 @@ public class CopyPermanentEffect extends SpellAbilityEffect { final String location = sa.getParam("AtEOT"); registerDelayedTrigger(sa, location, crds); } - - if (wasInAlt) { - c.setState(stateName); - } } // end canBeTargetedBy } // end foreach Card } // end resolve diff --git a/forge-game/src/main/java/forge/game/ability/effects/PlayLandVariantEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PlayLandVariantEffect.java index c1f78f255ce..477d69568db 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PlayLandVariantEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PlayLandVariantEffect.java @@ -79,7 +79,7 @@ public class PlayLandVariantEffect extends SpellAbilityEffect { source.switchStates(CardCharacteristicName.Original, CardCharacteristicName.Cloner); source.setState(CardCharacteristicName.Original); CardCharacteristicName stateToCopy = random.getCurState(); - CardFactory.copyState(random, stateToCopy, source); + CardFactory.copyState(random, stateToCopy, source, source.getCurState()); source.setImageKey(imageFileName); source.setController(activator, 0); diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 05ccfd6c7ab..9d7e64782c3 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -82,6 +82,7 @@ import java.util.concurrent.CopyOnWriteArrayList; */ public class Card extends GameEntity implements Comparable { private final int uniqueNumber; + private final IPaperCard paperCard; private final Map characteristicsMap = new EnumMap(CardCharacteristicName.class); @@ -242,10 +243,24 @@ public class Card extends GameEntity implements Comparable { } /** - * Instantiates a new card. + * Instantiates a new card not associated to any paper card. + * @param id the unique id of the new card. */ - public Card(int id) { + public Card(final int id) { + this(id, null); + } + + /** + * Instantiates a new card with a given paper card. + * @param id the unique id of the new card. + * @param paperCard the {@link IPaperCard} of which the new card is a + * representation, or {@code null} if this new {@link Card} doesn't represent any paper + * card. + * @see IPaperCard + */ + public Card(final int id, final IPaperCard paperCard) { this.uniqueNumber = id; + this.paperCard = paperCard; this.characteristicsMap.put(CardCharacteristicName.Original, new CardCharacteristics()); this.characteristicsMap.put(CardCharacteristicName.FaceDown, CardUtil.getFaceDownCharacteristic()); } @@ -8911,15 +8926,20 @@ public class Card extends GameEntity implements Comparable { return fromPaperCard(pc, null); } - public PaperCard getPaperCard() { + public IPaperCard getPaperCard() { + IPaperCard cp = this.paperCard; + if (cp != null) { + return cp; + } + final String name = getName(); final String set = getCurSetCode(); if (StringUtils.isNotBlank(set)) { - PaperCard cp = StaticData.instance().getVariantCards().getCard(name, set); + cp = StaticData.instance().getVariantCards().getCard(name, set); return cp == null ? StaticData.instance().getCommonCards().getCard(name, set) : cp; } - PaperCard cp = StaticData.instance().getVariantCards().getCard(name); + cp = StaticData.instance().getVariantCards().getCard(name); return cp == null ? StaticData.instance().getCommonCards().getCardFromEdition(name, SetPreference.Latest) : cp; } diff --git a/forge-game/src/main/java/forge/game/card/CardFactory.java b/forge-game/src/main/java/forge/game/card/CardFactory.java index 3f6e2cb8321..8f1157d95df 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactory.java +++ b/forge-game/src/main/java/forge/game/card/CardFactory.java @@ -71,27 +71,13 @@ public class CardFactory { * @return a {@link forge.game.card.Card} object. */ public final static Card copyCard(final Card in, boolean assignNewId) { - final CardCharacteristicName curState = in.getCurState(); - boolean alternate = false; - if (in.isInAlternateState()) { - alternate = true; - in.setState(CardCharacteristicName.Original); - } - Card out = null; + Card out; if (!in.isToken() || in.isCopiedToken()) { out = assignNewId ? getCard(in.getPaperCard(), in.getOwner()) : getCard(in.getPaperCard(), in.getOwner(), in.getUniqueNumber()); } else { // token - out = assignNewId ? new Card(in.getGame().nextCardId()) : new Card(in.getUniqueNumber()); + out = assignNewId ? new Card(in.getGame().nextCardId(), in.getPaperCard()) : new Card(in.getUniqueNumber(), in.getPaperCard()); out = CardFactory.copyStats(in, in.getController()); - - out.setName(in.getName()); - out.setImageKey(in.getImageKey()); - out.setManaCost(in.getManaCost()); - out.setColor(in.getColor()); - out.setType(in.getType()); - out.setBaseAttack(in.getBaseAttack()); - out.setBaseDefense(in.getBaseDefense()); out.setToken(true); CardFactoryUtil.addAbilityFactoryAbilities(out); @@ -99,22 +85,11 @@ public class CardFactory { out.addStaticAbility(s); } } - - CardFactory.copyCharacteristics(in, out); - if (in.hasAlternateState()) { - for (final CardCharacteristicName state : in.getStates()) { - in.setState(state); - if (state == CardCharacteristicName.Cloner) { - out.addAlternateState(state); - } - out.setState(state); - CardFactory.copyCharacteristics(in, out); - } + + for (final CardCharacteristicName state : in.getStates()) { + CardFactory.copyState(in, state, out, state); } - if (alternate) { - in.setState(curState); - } - out.setState(curState); + out.setState(in.getCurState()); // I'm not sure if we really should be copying enchant/equip stuff over. out.setEquipping(in.getEquipping()); @@ -254,7 +229,7 @@ public class CardFactory { public final static Card getCard(final IPaperCard cp, final Player owner, final int cardId) { //System.out.println(cardName); CardRules cardRules = cp.getRules(); - final Card c = readCard(cardRules, cardId); + final Card c = readCard(cardRules, cp, cardId); c.setRules(cardRules); c.setOwner(owner); buildAbilities(c); @@ -383,9 +358,9 @@ public class CardFactory { card.setSVar("DamagePWY", "Count$YourLifeTotal"); } - private static Card readCard(final CardRules rules, int cardId) { + private static Card readCard(final CardRules rules, final IPaperCard paperCard, int cardId) { - final Card card = new Card(cardId); + final Card card = new Card(cardId, paperCard); // 1. The states we may have: CardSplitType st = rules.getSplitType(); @@ -466,81 +441,128 @@ public class CardFactory { c.setBaseDefenseString(face.getToughness()); } } + + /** + * Create a copy of a card, including its copiable characteristics (but not + * abilities). + * @param from + * @param newOwner + * @return + */ + public static Card copyCopiableCharacteristics(final Card from, final Player newOwner) { + int id = newOwner == null ? 0 : newOwner.getGame().nextCardId(); + final Card c = new Card(id, from.getPaperCard()); + c.setOwner(newOwner); + c.setCurSetCode(from.getCurSetCode()); + + copyCopiableCharacteristics(from, c); + return c; + } + + /** + * Copy the copiable characteristics of one card to another, taking the + * states of both cards into account. + * + * @param from the {@link Card} to copy from. + * @param to the {@link Card} to copy to. + */ + public static void copyCopiableCharacteristics(final Card from, final Card to) { + final boolean toIsFaceDown = to.isFaceDown(); + if (toIsFaceDown) { + // If to is face down, copy to its front side + to.setState(CardCharacteristicName.Original); + copyCopiableCharacteristics(from, to); + to.setState(CardCharacteristicName.FaceDown); + return; + } + + final boolean fromIsFlipCard = from.isFlipCard(); + if (fromIsFlipCard) { + if (to.getCurState().equals(CardCharacteristicName.Flipped)) { + copyState(from, CardCharacteristicName.Original, to, CardCharacteristicName.Original); + } else { + copyState(from, CardCharacteristicName.Original, to, to.getCurState()); + } + copyState(from, CardCharacteristicName.Flipped, to, CardCharacteristicName.Flipped); + } else { + copyState(from, from.getCurState(), to, to.getCurState()); + } + } + + /** + * Copy the copiable abilities of one card to another, taking the states of + * both cards into account. + * + * @param from the {@link Card} to copy from. + * @param to the {@link Card} to copy to. + */ + public static void copyCopiableAbilities(final Card from, final Card to) { + final boolean toIsFaceDown = to.isFaceDown(); + if (toIsFaceDown) { + // If to is face down, copy to its front side + to.setState(CardCharacteristicName.Original); + copyCopiableAbilities(from, to); + to.setState(CardCharacteristicName.FaceDown); + return; + } + + final boolean fromIsFlipCard = from.isFlipCard(); + if (fromIsFlipCard) { + copyAbilities(from, CardCharacteristicName.Original, to, to.getCurState()); + copyAbilities(from, CardCharacteristicName.Flipped, to, CardCharacteristicName.Flipped); + } else { + copyAbilities(from, from.getCurState(), to, to.getCurState()); + } + } /** *

- * Copies stats like power, toughness, etc. + * Copy stats like power, toughness, etc. from one card to another. + *

+ *

+ * The copy is made independently for each state of the input {@link Card}. + * This amounts to making a full copy of the card, including the current + * state. *

* - * @param sim - * a {@link java.lang.Object} object. + * @param in + * the {@link forge.game.card.Card} to be copied. * @param newOwner - * @return a {@link forge.game.card.Card} object. + * the {@link forge.game.player.Player} to be the owner of the newly + * created Card. + * @return a new {@link forge.game.card.Card}. */ - public static Card copyStats(final Card sim, Player newOwner) { + public static Card copyStats(final Card in, final Player newOwner) { int id = newOwner == null ? 0 : newOwner.getGame().nextCardId(); - final Card c = new Card(id); + final Card c = new Card(id, in.getPaperCard()); c.setOwner(newOwner); - c.setCurSetCode(sim.getCurSetCode()); + c.setCurSetCode(in.getCurSetCode()); - final CardCharacteristicName origState = sim.getCurState(); - for (final CardCharacteristicName state : sim.getStates()) { - c.addAlternateState(state); - c.setState(state); - sim.setState(state); - CardFactory.copyCharacteristics(sim, c); + for (final CardCharacteristicName state : in.getStates()) { + CardFactory.copyState(in, state, c, state); } - sim.setState(origState); - c.setState(origState); - c.setRules(sim.getRules()); + c.setState(in.getCurState()); + c.setRules(in.getRules()); return c; } // copyStats() /** - * Copy characteristics. + * Copy characteristics of a particular state of one card to those of a + * (possibly different) state of another. * * @param from - * the from + * the {@link Card} to copy from. + * @param fromState + * the {@link CardCharacteristicName} of {@code from} to copy from. * @param to - * the to + * the {@link Card} to copy to. + * @param toState + * the {@link CardCharacteristicName} of {@code to} to copy to. */ - private static void copyCharacteristics(final Card from, final Card to) { - to.setBaseAttack(from.getBaseAttack()); - to.setBaseDefense(from.getBaseDefense()); - to.setBaseLoyalty(from.getBaseLoyalty()); - to.setBaseAttackString(from.getBaseAttackString()); - to.setBaseDefenseString(from.getBaseDefenseString()); - to.setIntrinsicKeyword(from.getIntrinsicKeyword()); - to.setName(from.getName()); - to.setType(from.getCharacteristics().getType()); - to.setText(from.getSpellText()); - to.setManaCost(from.getManaCost()); - to.setColor(from.getColor()); - to.setSVars(from.getSVars()); - to.setIntrinsicAbilities(from.getUnparsedAbilities()); - - to.setImageKey(from.getImageKey()); - to.setTriggers(from.getTriggers(), true); - to.setReplacementEffects(from.getReplacementEffects()); - to.setStaticAbilityStrings(from.getStaticAbilityStrings()); - - } - - /** - * Copy characteristics. - * - * @param from - * the from - * @param stateToCopy - * the state to copy - * @param to - * the to - */ - public static void copyState(final Card from, final CardCharacteristicName stateToCopy, final Card to) { - + public static void copyState(final Card from, final CardCharacteristicName fromState, final Card to, final CardCharacteristicName toState) { // copy characteristics not associated with a state to.setBaseLoyalty(from.getBaseLoyalty()); to.setBaseAttackString(from.getBaseAttackString()); @@ -548,11 +570,41 @@ public class CardFactory { to.setText(from.getSpellText()); // get CardCharacteristics for desired state - CardCharacteristics characteristics = from.getState(stateToCopy); - to.getCharacteristics().copyFrom(characteristics); + if (!to.getStates().contains(toState)) { + to.addAlternateState(toState); + } + final CardCharacteristics toCharacteristics = to.getState(toState), + fromCharacteristics = from.getState(fromState); + toCharacteristics.copyFrom(fromCharacteristics); + } + + /** + * Copy the abilities (including static abilities, triggers, and replacement + * effects) from one card to another. + * + * @param from the {@link Card} to copy from. + * @param fromState the {@link CardCharacteristicName} of {@code from} to copy from. + * @param to the {@link Card} to copy to. + * @param toState the {@link CardCharacteristicName} of {@code to} to copy to. + */ + private static void copyAbilities(final Card from, final CardCharacteristicName fromState, final Card to, final CardCharacteristicName toState) { + final CardCharacteristics fromCharacteristics = from.getState(fromState); + final CardCharacteristicName oldToState = to.getCurState(); + if (!to.getStates().contains(toState)) { + to.addAlternateState(toState); + } + + to.setState(toState); // handle triggers and replacement effect through Card class interface - to.setTriggers(characteristics.getTriggers(), true); - to.setReplacementEffects(characteristics.getReplacementEffects()); + to.setTriggers(fromCharacteristics.getTriggers(), true); + to.setReplacementEffects(fromCharacteristics.getReplacementEffects()); + // add abilities + CardFactoryUtil.addAbilityFactoryAbilities(to); + for (String staticAbility : to.getStaticAbilityStrings()) { + to.addStaticAbility(staticAbility); + } + // reset state + to.setState(oldToState); } public static void copySpellAbility(SpellAbility from, SpellAbility to) { diff --git a/forge-game/src/main/java/forge/game/card/CardUtil.java b/forge-game/src/main/java/forge/game/card/CardUtil.java index 57728231379..2c4b0f03688 100644 --- a/forge-game/src/main/java/forge/game/card/CardUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardUtil.java @@ -139,7 +139,7 @@ public final class CardUtil { */ public static Card getLKICopy(final Card in) { - final Card newCopy = new Card(in.getUniqueNumber()); + final Card newCopy = new Card(in.getUniqueNumber(), in.getPaperCard()); newCopy.setCurSetCode(in.getCurSetCode()); newCopy.setOwner(in.getOwner()); newCopy.setController(in.getController(), 0);