From 0d732e8f86989ce2e2a85ef71cbc1242ed8a839d Mon Sep 17 00:00:00 2001 From: magenoxx Date: Wed, 23 May 2012 20:41:51 +0400 Subject: [PATCH] New way of copying permanents - supports copies of copies. +1 test pass. --- .../mage/sets/magic2012/PhantasmalImage.java | 24 +++++---- .../sets/newphyrexia/PhyrexianMetamorph.java | 23 ++++---- .../test/cards/copy/PhantasmalImageTest.java | 2 +- .../java/org/mage/test/player/TestPlayer.java | 6 +++ .../abilities/effects/ContinuousEffects.java | 2 +- .../abilities/effects/common/CopyEffect.java | 20 ++++++- .../effects/common/CopyPermanentEffect.java | 18 ++++--- Mage/src/mage/game/Game.java | 32 +++++++---- Mage/src/mage/game/GameImpl.java | 53 +++++++++++++++++-- .../mage/game/permanent/PermanentImpl.java | 6 ++- .../mage/util/functions/ApplyToPermanent.java | 12 +++++ 11 files changed, 149 insertions(+), 49 deletions(-) create mode 100644 Mage/src/mage/util/functions/ApplyToPermanent.java diff --git a/Mage.Sets/src/mage/sets/magic2012/PhantasmalImage.java b/Mage.Sets/src/mage/sets/magic2012/PhantasmalImage.java index 2ff140f1b54..269749a2a80 100644 --- a/Mage.Sets/src/mage/sets/magic2012/PhantasmalImage.java +++ b/Mage.Sets/src/mage/sets/magic2012/PhantasmalImage.java @@ -27,8 +27,6 @@ */ package mage.sets.magic2012; -import java.util.UUID; -import mage.Constants; import mage.Constants.CardType; import mage.Constants.Outcome; import mage.Constants.Rarity; @@ -38,7 +36,6 @@ import mage.abilities.common.BecomesTargetTriggeredAbility; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CopyEffect; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.cards.CardImpl; import mage.filter.common.FilterCreaturePermanent; @@ -47,6 +44,9 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.TargetPermanent; +import mage.util.functions.ApplyToPermanent; + +import java.util.UUID; /** * @@ -98,15 +98,17 @@ class PhantasmalImageCopyEffect extends OneShotEffect target.setRequired(true); target.setNotTarget(true); player.choose(Outcome.Copy, target, source.getSourceId(), game); - Permanent permanent = game.getPermanent(target.getFirstTarget()); + UUID targetId = target.getFirstTarget(); + Permanent permanent = game.getPermanent(targetId); if (permanent != null) { - permanent = permanent.copy(); - permanent.reset(game); - permanent.assignNewId(); - permanent.getSubtype().add("Illusion"); - permanent.addAbility(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect()), game); - - game.addEffect(new CopyEffect(permanent), source); + game.copyPermanent(permanent, source, new ApplyToPermanent() { + @Override + public Boolean apply(Game game, Permanent permanent) { + permanent.getSubtype().add("Illusion"); + permanent.addAbility(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect()), game); + return true; + } + }); return true; } diff --git a/Mage.Sets/src/mage/sets/newphyrexia/PhyrexianMetamorph.java b/Mage.Sets/src/mage/sets/newphyrexia/PhyrexianMetamorph.java index cf0560eb28d..28a394040d8 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/PhyrexianMetamorph.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/PhyrexianMetamorph.java @@ -28,8 +28,6 @@ package mage.sets.newphyrexia; -import java.util.UUID; - import mage.Constants.CardType; import mage.Constants.Outcome; import mage.Constants.Rarity; @@ -38,7 +36,6 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CopyEffect; import mage.cards.CardImpl; import mage.filter.Filter; import mage.filter.FilterPermanent; @@ -47,6 +44,9 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.TargetPermanent; +import mage.util.functions.ApplyToPermanent; + +import java.util.UUID; /** * @@ -96,7 +96,6 @@ class PhyrexianMetamorphEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - //TODO: handle copying copies Player player = game.getPlayer(source.getControllerId()); if (player != null) { Target target = new TargetPermanent(filter); @@ -104,12 +103,16 @@ class PhyrexianMetamorphEffect extends OneShotEffect { player.choose(Outcome.Copy, target, source.getSourceId(), game); Permanent perm = game.getPermanent(target.getFirstTarget()); if (perm != null) { - perm = perm.copy(); - perm.reset(game); - perm.assignNewId(); - if (!perm.getCardType().contains(CardType.ARTIFACT)) - perm.getCardType().add(CardType.ARTIFACT); - game.addEffect(new CopyEffect(perm), source); + game.copyPermanent(perm, source, new ApplyToPermanent() { + @Override + public Boolean apply(Game game, Permanent permanent) { + if (!permanent.getCardType().contains(CardType.ARTIFACT)) { + permanent.getCardType().add(CardType.ARTIFACT); + } + return true; + } + }); + return true; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java index 418275c2093..de09c20779a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java @@ -103,7 +103,7 @@ public class PhantasmalImageTest extends CardTestPlayerBase { addCard(Constants.Zone.BATTLEFIELD, playerA, "Illusionary Servant"); setChoice(playerA, "Illusionary Servant"); - setChoice(playerA, "Phantasmal Image"); + setChoice(playerA, "Illusionary Servant-M12"); castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image"); castSpell(1, Constants.PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image"); diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index be579a421b4..3ce4133fe30 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -189,6 +189,12 @@ public class TestPlayer extends ComputerPlayer { choices.remove(choose2); return true; } + } else if ((permanent.getName()+"-"+permanent.getExpansionSetCode()).equals(choose2)) { + if (((TargetPermanent)target).canTarget(playerId, permanent.getId(), null, game) && !target.getTargets().contains(permanent.getId())) { + target.add(permanent.getId(), game); + choices.remove(choose2); + return true; + } } } } diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index d08934d7705..67052d12b62 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -131,7 +131,7 @@ public class ContinuousEffects implements Serializable { } - private List getLayeredEffects(Game game) { + public List getLayeredEffects(Game game) { List layerEffects = new ArrayList(); for (ContinuousEffect effect: layeredEffects) { switch (effect.getDuration()) { diff --git a/Mage/src/mage/abilities/effects/common/CopyEffect.java b/Mage/src/mage/abilities/effects/common/CopyEffect.java index a26ed87f839..67f71f3cdff 100644 --- a/Mage/src/mage/abilities/effects/common/CopyEffect.java +++ b/Mage/src/mage/abilities/effects/common/CopyEffect.java @@ -39,6 +39,8 @@ import mage.abilities.effects.ContinuousEffectImpl; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** * * @author BetaSteward_at_googlemail.com @@ -46,15 +48,18 @@ import mage.game.permanent.Permanent; public class CopyEffect extends ContinuousEffectImpl { private MageObject target; + private UUID sourceId; - public CopyEffect(MageObject target) { + public CopyEffect(Permanent target, UUID sourceId) { super(Duration.WhileOnBattlefield, Layer.CopyEffects_1, SubLayer.NA, Outcome.BecomeCreature); this.target = target; + this.sourceId = sourceId; } public CopyEffect(final CopyEffect effect) { super(effect); this.target = effect.target.copy(); + this.sourceId = effect.sourceId; } @Override @@ -63,7 +68,7 @@ public class CopyEffect extends ContinuousEffectImpl { if (permanent == null) { return false; } - + permanent.setName(target.getName()); permanent.getColor().setColor(target.getColor()); permanent.getManaCost().clear(); @@ -95,4 +100,15 @@ public class CopyEffect extends ContinuousEffectImpl { return new CopyEffect(this); } + public MageObject getTarget() { + return target; + } + + public void setTarget(MageObject target) { + this.target = target; + } + + public UUID getSourceId() { + return sourceId; + } } diff --git a/Mage/src/mage/abilities/effects/common/CopyPermanentEffect.java b/Mage/src/mage/abilities/effects/common/CopyPermanentEffect.java index 20cbdbf7e1c..41899c27244 100644 --- a/Mage/src/mage/abilities/effects/common/CopyPermanentEffect.java +++ b/Mage/src/mage/abilities/effects/common/CopyPermanentEffect.java @@ -27,6 +27,7 @@ */ package mage.abilities.effects.common; +import mage.Constants; import mage.Constants.Outcome; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -37,6 +38,7 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.TargetPermanent; +import mage.util.functions.ApplyToPermanent; /** * @@ -63,7 +65,6 @@ public class CopyPermanentEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - //TODO: handle copying copies Player player = game.getPlayer(source.getControllerId()); if (player != null) { Target target = new TargetPermanent(filter); @@ -71,11 +72,16 @@ public class CopyPermanentEffect extends OneShotEffect { player.choose(Outcome.Copy, target, source.getSourceId(), game); Permanent perm = game.getPermanent(target.getFirstTarget()); if (perm != null) { - perm = perm.copy(); - game.getState().addCard(perm); - perm.reset(game); - perm.assignNewId(); - game.addEffect(new CopyEffect(perm), source); + game.copyPermanent(perm, source, new ApplyToPermanent() { + @Override + public Boolean apply(Game game, Permanent permanent) { + if (!permanent.getCardType().contains(Constants.CardType.ARTIFACT)) { + permanent.getCardType().add(Constants.CardType.ARTIFACT); + } + return true; + } + }); + return true; } } diff --git a/Mage/src/mage/game/Game.java b/Mage/src/mage/game/Game.java index 5f1d3f80aa9..87157d80b7f 100644 --- a/Mage/src/mage/game/Game.java +++ b/Mage/src/mage/game/Game.java @@ -28,42 +28,42 @@ package mage.game; -import mage.actions.impl.MageAction; -import mage.game.match.MatchType; -import mage.cards.Card; -import mage.game.stack.SpellStack; -import mage.MageObject; -import java.io.Serializable; -import java.util.*; - import mage.Constants.MultiplayerAttackOption; import mage.Constants.RangeOfInfluence; import mage.Constants.Zone; import mage.MageItem; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.ActivatedAbility; import mage.abilities.DelayedTriggeredAbility; -import mage.abilities.TriggeredAbilities; import mage.abilities.TriggeredAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffects; +import mage.actions.impl.MageAction; +import mage.cards.Card; import mage.cards.Cards; import mage.cards.decks.Deck; import mage.choices.Choice; import mage.game.combat.Combat; import mage.game.events.GameEvent; -import mage.game.events.TableEvent; import mage.game.events.Listener; import mage.game.events.PlayerQueryEvent; +import mage.game.events.TableEvent; +import mage.game.match.MatchType; import mage.game.permanent.Battlefield; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; +import mage.game.stack.SpellStack; import mage.game.turn.Phase; import mage.game.turn.Step; import mage.game.turn.Turn; import mage.players.Player; import mage.players.PlayerList; import mage.players.Players; +import mage.util.functions.ApplyToPermanent; + +import java.io.Serializable; +import java.util.*; public interface Game extends MageItem, Serializable { @@ -160,7 +160,17 @@ public interface Game extends MageItem, Serializable { public void concede(UUID playerId); public void emptyManaPools(); public void addEffect(ContinuousEffect continuousEffect, Ability source); - public void addTriggeredAbility(TriggeredAbility ability); + + /** + * This version supports copying of copies of any depth. + * + * @param targetPermanent + * @param source + * @param applier + */ + public void copyPermanent(Permanent targetPermanent, Ability source, ApplyToPermanent applier); + + public void addTriggeredAbility(TriggeredAbility ability); public void addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility); public void applyEffects(); public boolean checkStateAndTriggered(); diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index c4fa951aaf1..fb25ca13763 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -37,6 +37,8 @@ import mage.abilities.TriggeredAbility; import mage.abilities.common.ChancellorAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffects; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CopyEffect; import mage.abilities.keyword.LeylineAbility; import mage.abilities.mana.TriggeredManaAbility; import mage.actions.impl.MageAction; @@ -67,6 +69,7 @@ import mage.players.Players; import mage.target.Target; import mage.target.TargetPermanent; import mage.target.TargetPlayer; +import mage.util.functions.ApplyToPermanent; import mage.watchers.common.*; import org.apache.log4j.Logger; @@ -649,15 +652,17 @@ public abstract class GameImpl> implements Game, Serializa if (isPaused() || isGameOver()) return; if (allPassed()) { if (!state.getStack().isEmpty()) { - //20091005 - 115.4 + //20091005 - 115.4 resolve(); applyEffects(); state.getPlayers().resetPassed(); fireUpdatePlayersEvent(); state.getRevealed().reset(); + resetLKI(); break; } else { //removeBookmark(bookmark); + resetLKI(); return; } } @@ -718,14 +723,53 @@ public abstract class GameImpl> implements Game, Serializa @Override public void addEffect(ContinuousEffect continuousEffect, Ability source) { - ContinuousEffect newEffect = (ContinuousEffect)continuousEffect.copy(); - Ability newAbility = source.copy(); + Ability newAbility = source.copy(); + + ContinuousEffect newEffect = (ContinuousEffect)continuousEffect.copy(); newEffect.newId(); newEffect.setTimestamp(); newEffect.init(newAbility, this); - state.addEffect(newEffect, newAbility); + + state.addEffect(newEffect, newAbility); } + @Override + public void copyPermanent(Permanent targetPermanent, Ability source, ApplyToPermanent applier) { + Permanent permanent = targetPermanent.copy(); + //getState().addCard(permanent); + permanent.reset(this); + permanent.assignNewId(); + applier.apply(this, permanent); + + Ability newAbility = source.copy(); + + CopyEffect newEffect = new CopyEffect(permanent, source.getSourceId()); + newEffect.newId(); + newEffect.setTimestamp(); + newEffect.init(newAbility, this); + + // handle copies of copies + for (Effect effect : getState().getContinuousEffects().getLayeredEffects(this)) { + if (effect instanceof CopyEffect) { + CopyEffect copyEffect = (CopyEffect) effect; + // there is another copy effect that our targetPermanent copies stats from + if (copyEffect.getSourceId().equals(targetPermanent.getId())) { + MageObject object = ((CopyEffect) effect).getTarget(); + if (object instanceof Permanent) { + // so we will use original card instead of target + Permanent original = (Permanent)object; + // copy it and apply changes we need + original = original.copy(); + applier.apply(this, original); + newEffect.setTarget(object); + } + } + } + } + + state.addEffect(newEffect, newAbility); + } + @Override public void addTriggeredAbility(TriggeredAbility ability) { if (ability instanceof TriggeredManaAbility) { @@ -758,7 +802,6 @@ public abstract class GameImpl> implements Game, Serializa } somethingHappened = true; } - resetLKI(); return somethingHappened; } diff --git a/Mage/src/mage/game/permanent/PermanentImpl.java b/Mage/src/mage/game/permanent/PermanentImpl.java index b779f416ce4..0c9074a9653 100644 --- a/Mage/src/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/mage/game/permanent/PermanentImpl.java @@ -506,8 +506,10 @@ public abstract class PermanentImpl> extends CardImpl } @Override - public void clearConnectedCards() { - this.connectedCards.clear(); + public void clearConnectedCards(String key) { + if (this.connectedCards.containsKey(key)) { + this.connectedCards.get(key).clear(); + } } @Override diff --git a/Mage/src/mage/util/functions/ApplyToPermanent.java b/Mage/src/mage/util/functions/ApplyToPermanent.java new file mode 100644 index 00000000000..ee814db620f --- /dev/null +++ b/Mage/src/mage/util/functions/ApplyToPermanent.java @@ -0,0 +1,12 @@ +package mage.util.functions; + +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * @author noxx + */ +public abstract class ApplyToPermanent { + + public abstract Boolean apply(Game game, Permanent permanent); +}