Fix a number of problems with copying permanents.

Copying between face-down permanents, flip cards and transform cards wasn't always working as described in rule 706. This should fix most of those problems.
This commit is contained in:
elcnesh
2014-06-14 22:29:14 +00:00
parent ac6a2965f7
commit 8efc6bda85
7 changed files with 234 additions and 239 deletions

View File

@@ -288,7 +288,7 @@ public class Match {
if (!lostOwnership.isEmpty()) { if (!lostOwnership.isEmpty()) {
List<PaperCard> lostPaperOwnership = new ArrayList<>(); List<PaperCard> lostPaperOwnership = new ArrayList<>();
for(Card c : lostOwnership) { for(Card c : lostOwnership) {
lostPaperOwnership.add(c.getPaperCard()); lostPaperOwnership.add((PaperCard)c.getPaperCard());
} }
if (outcome.anteResult.containsKey(fromGame)) { if (outcome.anteResult.containsKey(fromGame)) {
outcome.anteResult.get(fromGame).addLost(lostPaperOwnership); outcome.anteResult.get(fromGame).addLost(lostPaperOwnership);
@@ -300,7 +300,7 @@ public class Match {
if (!gainedOwnership.isEmpty()) { if (!gainedOwnership.isEmpty()) {
List<PaperCard> gainedPaperOwnership = new ArrayList<>(); List<PaperCard> gainedPaperOwnership = new ArrayList<>();
for(Card c : gainedOwnership) { for(Card c : gainedOwnership) {
gainedPaperOwnership.add(c.getPaperCard()); gainedPaperOwnership.add((PaperCard)c.getPaperCard());
} }
if (outcome.anteResult.containsKey(fromGame)) { if (outcome.anteResult.containsKey(fromGame)) {
outcome.anteResult.get(fromGame).addWon(gainedPaperOwnership); outcome.anteResult.get(fromGame).addWon(gainedPaperOwnership);

View File

@@ -6,6 +6,7 @@ import forge.game.Game;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCharacteristics;
import forge.game.card.CardFactory; import forge.game.card.CardFactory;
import forge.game.card.CardFactoryUtil; import forge.game.card.CardFactoryUtil;
import forge.game.card.CardUtil; import forge.game.card.CardUtil;
@@ -105,8 +106,7 @@ public class CloneEffect extends SpellAbilityEffect {
tgtCard.addAlternateState(CardCharacteristicName.Cloner); tgtCard.addAlternateState(CardCharacteristicName.Cloner);
tgtCard.switchStates(CardCharacteristicName.Original, CardCharacteristicName.Cloner); tgtCard.switchStates(CardCharacteristicName.Original, CardCharacteristicName.Cloner);
tgtCard.setState(CardCharacteristicName.Original); tgtCard.setState(CardCharacteristicName.Original);
} } else {
else {
//copy Original state to Cloned //copy Original state to Cloned
tgtCard.addAlternateState(CardCharacteristicName.Cloned); tgtCard.addAlternateState(CardCharacteristicName.Cloned);
tgtCard.switchStates(CardCharacteristicName.Original, CardCharacteristicName.Cloned); tgtCard.switchStates(CardCharacteristicName.Original, CardCharacteristicName.Cloned);
@@ -115,50 +115,33 @@ public class CloneEffect extends SpellAbilityEffect {
} }
} }
CardCharacteristicName stateToCopy = null; final CardCharacteristicName origState = cardToCopy.getCurState();
if (copyingSelf) { if (copyingSelf) {
stateToCopy = CardCharacteristicName.Cloned; cardToCopy.setState(CardCharacteristicName.Cloned);
} }
else if (cardToCopy.isFlipCard()) { CardFactory.copyCopiableCharacteristics(cardToCopy, tgtCard);
stateToCopy = CardCharacteristicName.Original; if (copyingSelf) {
} cardToCopy.setState(origState);
else {
stateToCopy = cardToCopy.getCurState();
} }
CardFactory.copyState(cardToCopy, stateToCopy, tgtCard);
// must call this before addAbilityFactoryAbilities so cloned added abilities are handled correctly // must call this before addAbilityFactoryAbilities so cloned added abilities are handled correctly
addExtraCharacteristics(tgtCard, sa, origSVars); addExtraCharacteristics(tgtCard, sa, origSVars);
CardFactoryUtil.addAbilityFactoryAbilities(tgtCard); CardFactory.copyCopiableAbilities(cardToCopy, tgtCard);
for (int i = 0; i < tgtCard.getStaticAbilityStrings().size(); i++) {
tgtCard.addStaticAbility(tgtCard.getStaticAbilityStrings().get(i)); // restore name if it should be unchanged
}
if (keepName) { 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. // state.
if (cardToCopy.isFlipCard()) { if (cardToCopy.isFlipCard()) {
if (!copyingSelf) { final CardCharacteristics flippedState = tgtCard.getState(CardCharacteristicName.Flipped);
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));
}
if (keepName) { if (keepName) {
tgtCard.setName(originalName); flippedState.setName(originalName);
} }
//keep the Clone card image for the cloned card //keep the Clone card image for the cloned card
tgtCard.setImageKey(imageFileName); flippedState.setImageKey(imageFileName);
if (tgtCard.getCurState() != CardCharacteristicName.Flipped) {
tgtCard.setState(CardCharacteristicName.Original);
}
} }
//Clean up copy of cloned state //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")) { if (sa.hasParam("IntoPlayTapped")) {
tgtCard.setTapped(true); tgtCard.setTapped(true);
} }

View File

@@ -6,7 +6,6 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.StaticData; import forge.StaticData;
import forge.card.CardCharacteristicName;
import forge.card.CardRulesPredicates; import forge.card.CardRulesPredicates;
import forge.game.Game; import forge.game.Game;
import forge.game.GameEntity; import forge.game.GameEntity;
@@ -15,7 +14,6 @@ import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardFactory; import forge.game.card.CardFactory;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
@@ -148,102 +146,13 @@ public class CopyPermanentEffect extends SpellAbilityEffect {
for (final Card c : tgtCards) { for (final Card c : tgtCards) {
if ((tgt == null) || c.canBeTargetedBy(sa)) { 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(); int multiplier = numCopies * hostCard.getController().getTokenDoublersMagnitude();
final List<Card> crds = new ArrayList<Card>(multiplier); final List<Card> crds = new ArrayList<Card>(multiplier);
for (int i = 0; i < multiplier; i++) { for (int i = 0; i < multiplier; i++) {
// TODO Use central copy methods final Card copy = CardFactory.copyCopiableCharacteristics(c, sa.getActivatingPlayer());
Card copy; copy.setToken(true);
if (!c.isToken() || c.isCopiedToken()) { copy.setCopiedToken(true);
// 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<Card> 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;
}
}
// add keywords from sa // add keywords from sa
for (final String kw : keywords) { for (final String kw : keywords) {
copy.addIntrinsicKeyword(kw); copy.addIntrinsicKeyword(kw);
@@ -260,20 +169,55 @@ public class CopyPermanentEffect extends SpellAbilityEffect {
final Trigger parsedTrigger = TriggerHandler.parseTrigger(actualTrigger, copy, false); final Trigger parsedTrigger = TriggerHandler.parseTrigger(actualTrigger, copy, false);
copy.addTrigger(parsedTrigger); copy.addTrigger(parsedTrigger);
} }
copy = game.getAction().moveToPlay(copy); CardFactory.copyCopiableAbilities(c, copy);
copy.setCloneOrigin(hostCard); final Card copyInPlay = game.getAction().moveToPlay(copy);
sa.getHostCard().addClone(copy);
crds.add(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")) { if (sa.hasParam("RememberCopied")) {
hostCard.addRemembered(copy); hostCard.addRemembered(copyInPlay);
} }
if (sa.hasParam("Tapped")) { if (sa.hasParam("Tapped")) {
copy.setTapped(true); copyInPlay.setTapped(true);
} }
if (sa.hasParam("CopyAttacking") && game.getPhaseHandler().inCombat()) { if (sa.hasParam("CopyAttacking") && game.getPhaseHandler().inCombat()) {
final GameEntity defender = AbilityUtils.getDefinedPlayers(hostCard, sa.getParam("CopyAttacking"), sa).get(0); 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<Card> 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"); final String location = sa.getParam("AtEOT");
registerDelayedTrigger(sa, location, crds); registerDelayedTrigger(sa, location, crds);
} }
if (wasInAlt) {
c.setState(stateName);
}
} // end canBeTargetedBy } // end canBeTargetedBy
} // end foreach Card } // end foreach Card
} // end resolve } // end resolve

View File

@@ -79,7 +79,7 @@ public class PlayLandVariantEffect extends SpellAbilityEffect {
source.switchStates(CardCharacteristicName.Original, CardCharacteristicName.Cloner); source.switchStates(CardCharacteristicName.Original, CardCharacteristicName.Cloner);
source.setState(CardCharacteristicName.Original); source.setState(CardCharacteristicName.Original);
CardCharacteristicName stateToCopy = random.getCurState(); CardCharacteristicName stateToCopy = random.getCurState();
CardFactory.copyState(random, stateToCopy, source); CardFactory.copyState(random, stateToCopy, source, source.getCurState());
source.setImageKey(imageFileName); source.setImageKey(imageFileName);
source.setController(activator, 0); source.setController(activator, 0);

View File

@@ -82,6 +82,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
*/ */
public class Card extends GameEntity implements Comparable<Card> { public class Card extends GameEntity implements Comparable<Card> {
private final int uniqueNumber; private final int uniqueNumber;
private final IPaperCard paperCard;
private final Map<CardCharacteristicName, CardCharacteristics> characteristicsMap private final Map<CardCharacteristicName, CardCharacteristics> characteristicsMap
= new EnumMap<CardCharacteristicName, CardCharacteristics>(CardCharacteristicName.class); = new EnumMap<CardCharacteristicName, CardCharacteristics>(CardCharacteristicName.class);
@@ -242,10 +243,24 @@ public class Card extends GameEntity implements Comparable<Card> {
} }
/** /**
* 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.uniqueNumber = id;
this.paperCard = paperCard;
this.characteristicsMap.put(CardCharacteristicName.Original, new CardCharacteristics()); this.characteristicsMap.put(CardCharacteristicName.Original, new CardCharacteristics());
this.characteristicsMap.put(CardCharacteristicName.FaceDown, CardUtil.getFaceDownCharacteristic()); this.characteristicsMap.put(CardCharacteristicName.FaceDown, CardUtil.getFaceDownCharacteristic());
} }
@@ -8911,15 +8926,20 @@ public class Card extends GameEntity implements Comparable<Card> {
return fromPaperCard(pc, null); 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 name = getName();
final String set = getCurSetCode(); final String set = getCurSetCode();
if (StringUtils.isNotBlank(set)) { 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; 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; return cp == null ? StaticData.instance().getCommonCards().getCardFromEdition(name, SetPreference.Latest) : cp;
} }

View File

@@ -71,27 +71,13 @@ public class CardFactory {
* @return a {@link forge.game.card.Card} object. * @return a {@link forge.game.card.Card} object.
*/ */
public final static Card copyCard(final Card in, boolean assignNewId) { public final static Card copyCard(final Card in, boolean assignNewId) {
final CardCharacteristicName curState = in.getCurState(); Card out;
boolean alternate = false;
if (in.isInAlternateState()) {
alternate = true;
in.setState(CardCharacteristicName.Original);
}
Card out = null;
if (!in.isToken() || in.isCopiedToken()) { if (!in.isToken() || in.isCopiedToken()) {
out = assignNewId ? getCard(in.getPaperCard(), in.getOwner()) out = assignNewId ? getCard(in.getPaperCard(), in.getOwner())
: getCard(in.getPaperCard(), in.getOwner(), in.getUniqueNumber()); : getCard(in.getPaperCard(), in.getOwner(), in.getUniqueNumber());
} else { // token } 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 = 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); out.setToken(true);
CardFactoryUtil.addAbilityFactoryAbilities(out); CardFactoryUtil.addAbilityFactoryAbilities(out);
@@ -100,21 +86,10 @@ public class CardFactory {
} }
} }
CardFactory.copyCharacteristics(in, out); for (final CardCharacteristicName state : in.getStates()) {
if (in.hasAlternateState()) { CardFactory.copyState(in, state, out, state);
for (final CardCharacteristicName state : in.getStates()) {
in.setState(state);
if (state == CardCharacteristicName.Cloner) {
out.addAlternateState(state);
}
out.setState(state);
CardFactory.copyCharacteristics(in, out);
}
} }
if (alternate) { out.setState(in.getCurState());
in.setState(curState);
}
out.setState(curState);
// I'm not sure if we really should be copying enchant/equip stuff over. // I'm not sure if we really should be copying enchant/equip stuff over.
out.setEquipping(in.getEquipping()); 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) { public final static Card getCard(final IPaperCard cp, final Player owner, final int cardId) {
//System.out.println(cardName); //System.out.println(cardName);
CardRules cardRules = cp.getRules(); CardRules cardRules = cp.getRules();
final Card c = readCard(cardRules, cardId); final Card c = readCard(cardRules, cp, cardId);
c.setRules(cardRules); c.setRules(cardRules);
c.setOwner(owner); c.setOwner(owner);
buildAbilities(c); buildAbilities(c);
@@ -383,9 +358,9 @@ public class CardFactory {
card.setSVar("DamagePWY", "Count$YourLifeTotal"); 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: // 1. The states we may have:
CardSplitType st = rules.getSplitType(); CardSplitType st = rules.getSplitType();
@@ -467,80 +442,127 @@ public class CardFactory {
} }
} }
/**
* 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());
}
}
/** /**
* <p> * <p>
* Copies stats like power, toughness, etc. * Copy stats like power, toughness, etc. from one card to another.
* </p>
* <p>
* 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.
* </p> * </p>
* *
* @param sim * @param in
* a {@link java.lang.Object} object. * the {@link forge.game.card.Card} to be copied.
* @param newOwner * @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(); 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.setOwner(newOwner);
c.setCurSetCode(sim.getCurSetCode()); c.setCurSetCode(in.getCurSetCode());
final CardCharacteristicName origState = sim.getCurState(); for (final CardCharacteristicName state : in.getStates()) {
for (final CardCharacteristicName state : sim.getStates()) { CardFactory.copyState(in, state, c, state);
c.addAlternateState(state);
c.setState(state);
sim.setState(state);
CardFactory.copyCharacteristics(sim, c);
} }
sim.setState(origState); c.setState(in.getCurState());
c.setState(origState); c.setRules(in.getRules());
c.setRules(sim.getRules());
return c; return c;
} // copyStats() } // copyStats()
/** /**
* Copy characteristics. * Copy characteristics of a particular state of one card to those of a
* (possibly different) state of another.
* *
* @param from * @param from
* the from * the {@link Card} to copy from.
* @param fromState
* the {@link CardCharacteristicName} of {@code from} to copy from.
* @param to * @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) { public static void copyState(final Card from, final CardCharacteristicName fromState, final Card to, final CardCharacteristicName toState) {
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) {
// copy characteristics not associated with a state // copy characteristics not associated with a state
to.setBaseLoyalty(from.getBaseLoyalty()); to.setBaseLoyalty(from.getBaseLoyalty());
to.setBaseAttackString(from.getBaseAttackString()); to.setBaseAttackString(from.getBaseAttackString());
@@ -548,11 +570,41 @@ public class CardFactory {
to.setText(from.getSpellText()); to.setText(from.getSpellText());
// get CardCharacteristics for desired state // get CardCharacteristics for desired state
CardCharacteristics characteristics = from.getState(stateToCopy); if (!to.getStates().contains(toState)) {
to.getCharacteristics().copyFrom(characteristics); 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 // handle triggers and replacement effect through Card class interface
to.setTriggers(characteristics.getTriggers(), true); to.setTriggers(fromCharacteristics.getTriggers(), true);
to.setReplacementEffects(characteristics.getReplacementEffects()); 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) { public static void copySpellAbility(SpellAbility from, SpellAbility to) {

View File

@@ -139,7 +139,7 @@ public final class CardUtil {
*/ */
public static Card getLKICopy(final Card in) { 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.setCurSetCode(in.getCurSetCode());
newCopy.setOwner(in.getOwner()); newCopy.setOwner(in.getOwner());
newCopy.setController(in.getController(), 0); newCopy.setController(in.getController(), 0);