From 59bda7f1d53a03c8deb47d166a077d05974d7061 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Thu, 29 Nov 2018 19:29:39 +0400 Subject: [PATCH] Refactor: added copyFrom info for all objects (original card used for copy, copy of copy and etc); --- .../mage/cards/a/ApproachOfTheSecondSun.java | 9 ++- .../src/mage/cards/c/CopyEnchantment.java | 3 + .../src/mage/cards/k/KheruSpellsnatcher.java | 17 ++---- .../src/mage/cards/s/SoulfireGrandMaster.java | 18 ++---- .../abilities/activated/LicidAbilityTest.java | 2 +- .../test/lki/LastKnownInformationTest.java | 2 +- Mage/src/main/java/mage/MageObject.java | 16 ++--- Mage/src/main/java/mage/MageObjectImpl.java | 26 ++++---- .../abilities/effects/common/CopyEffect.java | 10 +++- .../effects/common/ExileSpellEffect.java | 4 +- .../abilities/keyword/ReboundAbility.java | 6 +- Mage/src/main/java/mage/cards/SplitCard.java | 18 +++--- .../java/mage/designations/CitysBlessing.java | 11 +++- .../java/mage/designations/Designation.java | 50 ++++++++-------- .../main/java/mage/designations/Monarch.java | 11 +++- .../main/java/mage/filter/FilterPlayer.java | 6 +- .../filter/predicate/ObjectSourcePlayer.java | 4 +- Mage/src/main/java/mage/game/GameImpl.java | 4 ++ Mage/src/main/java/mage/game/GameState.java | 20 +++---- .../java/mage/game/command/Commander.java | 42 ++++++++----- .../main/java/mage/game/command/Emblem.java | 36 +++++++---- .../main/java/mage/game/command/Plane.java | 29 ++++++--- Mage/src/main/java/mage/game/stack/Spell.java | 47 ++++++++------- .../java/mage/game/stack/StackAbility.java | 39 +++++++----- .../main/java/mage/players/PlayerImpl.java | 59 ++++++++++--------- 25 files changed, 269 insertions(+), 220 deletions(-) diff --git a/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java b/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java index 1877fee325f..574c2ce7b7c 100644 --- a/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java +++ b/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java @@ -1,6 +1,5 @@ package mage.cards.a; -import java.util.*; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -16,6 +15,10 @@ import mage.game.stack.Spell; import mage.players.Player; import mage.watchers.Watcher; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** * @author stravant */ @@ -64,7 +67,7 @@ class ApproachOfTheSecondSunEffect extends OneShotEffect { ApproachOfTheSecondSunWatcher watcher = (ApproachOfTheSecondSunWatcher) game.getState().getWatchers().get(ApproachOfTheSecondSunWatcher.class.getSimpleName()); if (watcher != null - && !spell.isCopiedSpell() + && !spell.isCopy() && watcher.getApproachesCast(controller.getId()) > 1 && spell.getFromZone() == Zone.HAND) { // Win the game @@ -74,7 +77,7 @@ class ApproachOfTheSecondSunEffect extends OneShotEffect { controller.gainLife(7, game, source); // Put this into the library as the 7th from the top - if (spell.isCopiedSpell()) { + if (spell.isCopy()) { return true; } Card spellCard = game.getStack().getSpell(source.getSourceId()).getCard(); diff --git a/Mage.Sets/src/mage/cards/c/CopyEnchantment.java b/Mage.Sets/src/mage/cards/c/CopyEnchantment.java index f84ee371ddd..53ecbe3072a 100644 --- a/Mage.Sets/src/mage/cards/c/CopyEnchantment.java +++ b/Mage.Sets/src/mage/cards/c/CopyEnchantment.java @@ -2,6 +2,8 @@ package mage.cards.c; import java.util.UUID; + +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.common.EntersBattlefieldAbility; @@ -17,6 +19,7 @@ import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentCard; import mage.players.Player; import mage.target.Target; import mage.util.functions.EmptyApplyToPermanent; diff --git a/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java b/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java index 1576cc697bf..d5e5bf5a3d8 100644 --- a/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java +++ b/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java @@ -1,7 +1,5 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -14,13 +12,7 @@ import mage.abilities.keyword.MorphAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AsThoughEffectType; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.constants.ZoneDetail; +import mage.constants.*; import mage.game.Game; import mage.game.stack.Spell; import mage.game.stack.StackObject; @@ -28,14 +20,15 @@ import mage.players.Player; import mage.target.TargetSpell; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author emerald000 */ public final class KheruSpellsnatcher extends CardImpl { public KheruSpellsnatcher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.NAGA); this.subtype.add(SubType.WIZARD); @@ -85,7 +78,7 @@ class KheruSpellsnatcherEffect extends OneShotEffect { StackObject stackObject = game.getStack().getStackObject(objectId); if (stackObject != null && game.getStack().counter(targetPointer.getFirst(game, source), source.getSourceId(), game, Zone.EXILED, false, ZoneDetail.NONE)) { - if (!((Spell) stackObject).isCopiedSpell()) { + if (!((Spell) stackObject).isCopy()) { MageObject card = game.getObject(stackObject.getSourceId()); if (card instanceof Card) { ((Card) card).moveToZone(Zone.EXILED, sourceId, game, true); diff --git a/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java b/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java index abd70447d89..c7b36889d63 100644 --- a/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java +++ b/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java @@ -1,14 +1,11 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.GainAbilitySpellsEffect; import mage.abilities.effects.ReplacementEffectImpl; @@ -16,13 +13,7 @@ import mage.abilities.keyword.LifelinkAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.FilterObject; import mage.filter.predicate.Predicates; @@ -30,13 +21,12 @@ import mage.filter.predicate.mageobject.CardTypePredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; -import mage.game.permanent.Permanent; import mage.game.stack.Spell; -import mage.game.stack.StackObject; import mage.players.Player; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SoulfireGrandMaster extends CardImpl { @@ -111,7 +101,7 @@ class SoulfireGrandMasterCastFromHandReplacementEffect extends ReplacementEffect @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { MageObject mageObject = game.getObject(spellId); - if (!(mageObject instanceof Spell) || ((Spell) mageObject).isCopiedSpell()) { + if (!(mageObject instanceof Spell) || ((Spell) mageObject).isCopy()) { return false; } else { Card sourceCard = game.getCard(spellId); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/LicidAbilityTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/LicidAbilityTest.java index 5d4eca287e1..62f5cef1457 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/LicidAbilityTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/LicidAbilityTest.java @@ -59,7 +59,7 @@ public class LicidAbilityTest extends CardTestPlayerBase { execute(); - assertActionCount(playerA, 0); + assertActionsCount(playerA, 0); assertAbility(playerA, "Pillarfield Ox", HasteAbility.getInstance(), false); assertAbility(playerA, "Enraging Licid", new LicidAbility(new ColoredManaCost(ColoredManaSymbol.R), new ColoredManaCost(ColoredManaSymbol.R)), true); assertType("Enraging Licid", CardType.ENCHANTMENT, false); diff --git a/Mage.Tests/src/test/java/org/mage/test/lki/LastKnownInformationTest.java b/Mage.Tests/src/test/java/org/mage/test/lki/LastKnownInformationTest.java index ef914921778..352ec36de59 100644 --- a/Mage.Tests/src/test/java/org/mage/test/lki/LastKnownInformationTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/lki/LastKnownInformationTest.java @@ -58,7 +58,7 @@ public class LastKnownInformationTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Soldier", 2); assertGraveyardCount(playerB, "Lightning Bolt", 2); - assertActionCount(playerB, 0); + assertActionsCount(playerB, 0); } diff --git a/Mage/src/main/java/mage/MageObject.java b/Mage/src/main/java/mage/MageObject.java index b65f1721739..cb1812c44fb 100644 --- a/Mage/src/main/java/mage/MageObject.java +++ b/Mage/src/main/java/mage/MageObject.java @@ -64,20 +64,14 @@ public interface MageObject extends MageItem, Serializable { void adjustTargets(Ability ability, Game game); + // memory object copy (not mtg) MageObject copy(); - /** - * Defines that MageObject is a copy of another object - * - * @param isCopy - */ - void setCopy(boolean isCopy); + // copied card info (mtg) + void setCopy(boolean isCopy, MageObject copiedFrom); + + MageObject getCopyFrom(); - /** - * Checks if current MageObject is a copy of another object - * - * @return - */ boolean isCopy(); int getZoneChangeCounter(Game game); diff --git a/Mage/src/main/java/mage/MageObjectImpl.java b/Mage/src/main/java/mage/MageObjectImpl.java index 051b9584573..7592cb770f3 100644 --- a/Mage/src/main/java/mage/MageObjectImpl.java +++ b/Mage/src/main/java/mage/MageObjectImpl.java @@ -1,11 +1,5 @@ - package mage; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.Iterator; -import java.util.List; -import java.util.UUID; import mage.abilities.Abilities; import mage.abilities.AbilitiesImpl; import mage.abilities.Ability; @@ -20,16 +14,14 @@ import mage.abilities.mana.ActivatedManaAbilityImpl; import mage.abilities.text.TextPart; import mage.abilities.text.TextPartSubType; import mage.cards.FrameStyle; -import mage.constants.CardType; -import mage.constants.SubLayer; -import mage.constants.SubType; -import mage.constants.SubTypeSet; -import mage.constants.SuperType; +import mage.constants.*; import mage.game.Game; import mage.game.events.ZoneChangeEvent; import mage.util.GameLog; import mage.util.SubTypeList; +import java.util.*; + public abstract class MageObjectImpl implements MageObject { protected UUID objectId; @@ -48,6 +40,7 @@ public abstract class MageObjectImpl implements MageObject { protected MageInt power; protected MageInt toughness; protected boolean copy; + protected MageObject copyFrom; // copied card INFO (used to call original adjusters) protected List textParts; public MageObjectImpl() { @@ -82,6 +75,7 @@ public abstract class MageObjectImpl implements MageObject { isAllCreatureTypes = object.isAllCreatureTypes; supertype.addAll(object.supertype); this.copy = object.copy; + this.copyFrom = (object.copyFrom != null ? object.copyFrom.copy() : null); textParts = new ArrayList<>(); textParts.addAll(object.textParts); } @@ -263,8 +257,14 @@ public abstract class MageObjectImpl implements MageObject { } @Override - public void setCopy(boolean isCopy) { + public void setCopy(boolean isCopy, MageObject copyFrom) { this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; } @Override @@ -322,7 +322,7 @@ public abstract class MageObjectImpl implements MageObject { */ @Override public void removePTCDA() { - for (Iterator iter = this.getAbilities().iterator(); iter.hasNext();) { + for (Iterator iter = this.getAbilities().iterator(); iter.hasNext(); ) { Ability ability = iter.next(); for (Effect effect : ability.getEffects()) { if (effect instanceof ContinuousEffect && ((ContinuousEffect) effect).getSublayer() == SubLayer.CharacteristicDefining_7a) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java index b582f291303..da0131ace96 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import mage.MageObject; @@ -16,7 +15,6 @@ import mage.util.functions.ApplyToPermanent; import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public class CopyEffect extends ContinuousEffectImpl { @@ -90,7 +88,13 @@ public class CopyEffect extends ContinuousEffectImpl { } protected boolean copyToPermanent(Permanent permanent, Game game, Ability source) { - permanent.setCopy(true); + if (copyFromObject.getCopyFrom() != null) { + // copy from temp blueprints (they are already copies) + permanent.setCopy(true, copyFromObject.getCopyFrom()); + } else { + // copy object to object + permanent.setCopy(true, copyFromObject); + } permanent.setName(copyFromObject.getName()); permanent.getColor(game).setColor(copyFromObject.getColor(game)); permanent.getManaCost().clear(); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileSpellEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileSpellEffect.java index 08100530054..f828e713ef8 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileSpellEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileSpellEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -12,7 +11,6 @@ import mage.game.stack.Spell; import mage.players.Player; /** - * * @author BetaSteward_at_googlemail.com */ public class ExileSpellEffect extends OneShotEffect implements MageSingleton { @@ -38,7 +36,7 @@ public class ExileSpellEffect extends OneShotEffect implements MageSingleton { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Spell spell = game.getStack().getSpell(source.getId()); - if (spell != null && !spell.isCopiedSpell()) { + if (spell != null && !spell.isCopy()) { Card spellCard = spell.getCard(); if (spellCard != null) { controller.moveCards(spellCard, Zone.EXILED, source, game); diff --git a/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java b/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java index 885d0a3b662..6afa7afdf0c 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java @@ -1,7 +1,5 @@ - package mage.abilities.keyword; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; @@ -21,6 +19,8 @@ import mage.game.events.ZoneChangeEvent; import mage.game.stack.Spell; import mage.players.Player; +import java.util.UUID; + /** * This ability has no effect by default and will always return false on the * call to apply. This is because of how the {@link ReboundEffect} works. It @@ -93,7 +93,7 @@ class ReboundCastFromHandReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Spell sourceSpell = game.getStack().getSpell(source.getSourceId()); - if (sourceSpell != null && sourceSpell.isCopiedSpell()) { + if (sourceSpell != null && sourceSpell.isCopy()) { return false; } else { Card sourceCard = game.getCard(source.getSourceId()); diff --git a/Mage/src/main/java/mage/cards/SplitCard.java b/Mage/src/main/java/mage/cards/SplitCard.java index b8102f7ae4c..a602c2a6635 100644 --- a/Mage/src/main/java/mage/cards/SplitCard.java +++ b/Mage/src/main/java/mage/cards/SplitCard.java @@ -1,9 +1,6 @@ - package mage.cards; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import mage.MageObject; import mage.abilities.Abilities; import mage.abilities.AbilitiesImpl; import mage.abilities.Ability; @@ -13,8 +10,11 @@ import mage.constants.SpellAbilityType; import mage.constants.Zone; import mage.game.Game; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author LevelX2 */ public abstract class SplitCard extends CardImpl { @@ -58,10 +58,10 @@ public abstract class SplitCard extends CardImpl { } @Override - public void setCopy(boolean isCopy) { - super.setCopy(isCopy); - leftHalfCard.setCopy(isCopy); - rightHalfCard.setCopy(isCopy); + public void setCopy(boolean isCopy, MageObject copiedFrom) { + super.setCopy(isCopy, copiedFrom); + leftHalfCard.setCopy(isCopy, copiedFrom); + rightHalfCard.setCopy(isCopy, copiedFrom); } @Override diff --git a/Mage/src/main/java/mage/designations/CitysBlessing.java b/Mage/src/main/java/mage/designations/CitysBlessing.java index ca5aaa74766..9e803a6b676 100644 --- a/Mage/src/main/java/mage/designations/CitysBlessing.java +++ b/Mage/src/main/java/mage/designations/CitysBlessing.java @@ -1,8 +1,6 @@ - package mage.designations; /** - * * @author LevelX2 */ public class CitysBlessing extends Designation { @@ -10,4 +8,13 @@ public class CitysBlessing extends Designation { public CitysBlessing() { super(DesignationType.CITYS_BLESSING, "RIX"); } + + private CitysBlessing(final CitysBlessing card) { + super(card); + } + + @Override + public CitysBlessing copy() { + return new CitysBlessing(this); + } } diff --git a/Mage/src/main/java/mage/designations/Designation.java b/Mage/src/main/java/mage/designations/Designation.java index 44d7ba62ab7..943e757e778 100644 --- a/Mage/src/main/java/mage/designations/Designation.java +++ b/Mage/src/main/java/mage/designations/Designation.java @@ -1,14 +1,5 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package mage.designations; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.ObjectColor; @@ -28,8 +19,12 @@ import mage.game.events.ZoneChangeEvent; import mage.util.GameLog; import mage.util.SubTypeList; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.UUID; + /** - * * @author LevelX2 */ public abstract class Designation implements MageObject { @@ -43,6 +38,8 @@ public abstract class Designation implements MageObject { private DesignationType designationType; private UUID id; private FrameStyle frameStyle; + private boolean copy; + private MageObject copyFrom; // copied card INFO (used to call original adjusters) private Abilities abilites = new AbilitiesImpl<>(); private String expansionSetCodeForImage; private final boolean unique; // can a designation be added multiple times (false) or only once to an object (true) @@ -65,6 +62,8 @@ public abstract class Designation implements MageObject { this.name = designation.name; this.designationType = designation.designationType; this.frameStyle = designation.frameStyle; + this.copy = designation.copy; + this.copyFrom = (designation.copyFrom != null ? designation.copyFrom.copy() : null); this.abilites = designation.abilites.copy(); this.unique = designation.unique; } @@ -78,6 +77,22 @@ public abstract class Designation implements MageObject { this.id = UUID.randomUUID(); } + @Override + public void setCopy(boolean isCopy, MageObject copyFrom) { + this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); + } + + @Override + public boolean isCopy() { + return this.copy; + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; + } + @Override public String getName() { return name; @@ -198,20 +213,6 @@ public abstract class Designation implements MageObject { public void adjustTargets(Ability ability, Game game) { } - @Override - public void setCopy(boolean isCopy) { - } - - @Override - public boolean isCopy() { - return false; - } - - @Override - public Designation copy() { - return this; - } - @Override public int getZoneChangeCounter(Game game) { return 1; // Emblems can't move zones until now so return always 1 @@ -232,7 +233,6 @@ public abstract class Designation implements MageObject { } /** - * * @param game * @param controllerId */ diff --git a/Mage/src/main/java/mage/designations/Monarch.java b/Mage/src/main/java/mage/designations/Monarch.java index 0281b3c4590..d178838970e 100644 --- a/Mage/src/main/java/mage/designations/Monarch.java +++ b/Mage/src/main/java/mage/designations/Monarch.java @@ -1,4 +1,3 @@ - package mage.designations; import mage.MageObject; @@ -15,7 +14,6 @@ import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; /** - * * @author LevelX2 */ public class Monarch extends Designation { @@ -25,6 +23,15 @@ public class Monarch extends Designation { addAbility(new MonarchDrawTriggeredAbility()); addAbility(new MonarchDealsCombatDamageToAPlayerTriggeredAbility()); } + + private Monarch(final Monarch monarch) { + super(monarch); + } + + @Override + public Monarch copy() { + return new Monarch(this); + } } // At the beginning of the monarch's end step, that player draws a card diff --git a/Mage/src/main/java/mage/filter/FilterPlayer.java b/Mage/src/main/java/mage/filter/FilterPlayer.java index 907dfb34340..8f085ddd67c 100644 --- a/Mage/src/main/java/mage/filter/FilterPlayer.java +++ b/Mage/src/main/java/mage/filter/FilterPlayer.java @@ -44,12 +44,12 @@ public class FilterPlayer extends FilterImpl { return object instanceof Player; } - public boolean match(Player player, UUID sourceId, UUID playerId, Game game) { - if (!this.match(player, game)) { + public boolean match(Player checkPlayer, UUID sourceId, UUID sourceControllerId, Game game) { + if (!this.match(checkPlayer, game)) { return false; } - return Predicates.and(extraPredicates).apply(new ObjectSourcePlayer(player, sourceId, playerId), game); + return Predicates.and(extraPredicates).apply(new ObjectSourcePlayer(checkPlayer, sourceId, sourceControllerId), game); } @Override diff --git a/Mage/src/main/java/mage/filter/predicate/ObjectSourcePlayer.java b/Mage/src/main/java/mage/filter/predicate/ObjectSourcePlayer.java index aa73a7d466f..671c8abf0ca 100644 --- a/Mage/src/main/java/mage/filter/predicate/ObjectSourcePlayer.java +++ b/Mage/src/main/java/mage/filter/predicate/ObjectSourcePlayer.java @@ -12,8 +12,8 @@ public class ObjectSourcePlayer extends ObjectPlayer { protected final UUID sourceId; - public ObjectSourcePlayer(T object, UUID sourceId, UUID playerId) { - super(object, playerId); + public ObjectSourcePlayer(T object, UUID sourceId, UUID sourceControllerId) { + super(object, sourceControllerId); this.sourceId = sourceId; } diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index c0fa488e204..a6eb99e1415 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1638,6 +1638,7 @@ public abstract class GameImpl implements Game, Serializable { if (newBluePrint == null) { newBluePrint = copyFromPermanent.copy(); newBluePrint.reset(this); + //getState().addCard(permanent); if (copyFromPermanent.isMorphed() || copyFromPermanent.isManifested()) { MorphAbility.setPermanentToFaceDownCreature(newBluePrint); @@ -1651,6 +1652,9 @@ public abstract class GameImpl implements Game, Serializable { applier.apply(this, newBluePrint, source, copyToPermanentId); } + // save original copy link (handle copy of copies too) + newBluePrint.setCopy(true, (copyFromPermanent.getCopyFrom() != null ? copyFromPermanent.getCopyFrom() : copyFromPermanent)); + CopyEffect newEffect = new CopyEffect(duration, newBluePrint, copyToPermanentId); newEffect.newId(); newEffect.setApplier(applier); diff --git a/Mage/src/main/java/mage/game/GameState.java b/Mage/src/main/java/mage/game/GameState.java index e18fc41b72f..b98810d1794 100644 --- a/Mage/src/main/java/mage/game/GameState.java +++ b/Mage/src/main/java/mage/game/GameState.java @@ -1,8 +1,5 @@ package mage.game; -import java.io.Serializable; -import java.util.*; -import java.util.stream.Collectors; import mage.MageObject; import mage.abilities.*; import mage.abilities.effects.ContinuousEffect; @@ -35,15 +32,17 @@ import mage.util.ThreadLocalStringBuilder; import mage.watchers.Watcher; import mage.watchers.Watchers; +import java.io.Serializable; +import java.util.*; +import java.util.stream.Collectors; + /** - * * @author BetaSteward_at_googlemail.com - * + *

* since at any time the game state may be copied and restored you cannot rely * on any object maintaining it's instance it then becomes necessary to only * refer to objects by their ids since these will always remain constant * throughout its lifetime - * */ public class GameState implements Serializable, Copyable { @@ -590,6 +589,7 @@ public class GameState implements Serializable, Copyable { // public void addMessage(String message) { // this.messages.add(message); // } + /** * Returns a list of all players of the game ignoring range or if a player * has lost or left the game. @@ -758,7 +758,7 @@ public class GameState implements Serializable, Copyable { } for (Map.Entry> entry : eventsByKey.entrySet()) { Set movedCards = new LinkedHashSet<>(); - for (Iterator it = entry.getValue().iterator(); it.hasNext();) { + for (Iterator it = entry.getValue().iterator(); it.hasNext(); ) { GameEvent event = it.next(); ZoneChangeEvent castEvent = (ZoneChangeEvent) event; UUID targetId = castEvent.getTargetId(); @@ -943,7 +943,7 @@ public class GameState implements Serializable, Copyable { /** * Other abilities are used to implement some special kind of continuous * effects that give abilities to non permanents. - * + *

* Crucible of Worlds - You may play land cards from your graveyard. Past in * Flames - Each instant and sorcery card in your graveyard gains flashback * until end of turn. The flashback cost is equal to its mana cost. Varolz, @@ -984,7 +984,7 @@ public class GameState implements Serializable, Copyable { * @param attachedTo * @param ability * @param copyAbility copies non MageSingleton abilities before adding to - * state + * state */ public void addOtherAbility(Card attachedTo, Ability ability, boolean copyAbility) { Ability newAbility; @@ -1134,7 +1134,7 @@ public class GameState implements Serializable, Copyable { Card copiedCard = cardToCopy.copy(); copiedCard.assignNewId(); copiedCard.setOwnerId(source.getControllerId()); - copiedCard.setCopy(true); + copiedCard.setCopy(true, cardToCopy); copiedCards.put(copiedCard.getId(), copiedCard); addCard(copiedCard); if (copiedCard.isSplitCard()) { diff --git a/Mage/src/main/java/mage/game/command/Commander.java b/Mage/src/main/java/mage/game/command/Commander.java index 966133e5dd4..7163f8683ef 100644 --- a/Mage/src/main/java/mage/game/command/Commander.java +++ b/Mage/src/main/java/mage/game/command/Commander.java @@ -1,10 +1,7 @@ - package mage.game.command; -import java.util.EnumSet; -import java.util.List; -import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.ObjectColor; import mage.abilities.Abilities; import mage.abilities.AbilitiesImpl; @@ -24,9 +21,15 @@ import mage.game.events.ZoneChangeEvent; import mage.util.GameLog; import mage.util.SubTypeList; +import java.util.EnumSet; +import java.util.List; +import java.util.UUID; + public class Commander implements CommandObject { private final Card sourceObject; + private boolean copy; + private MageObject copyFrom; // copied card INFO (used to call original adjusters) private final Abilities abilities = new AbilitiesImpl<>(); public Commander(Card card) { @@ -40,8 +43,10 @@ public class Commander implements CommandObject { } } - private Commander(Commander copy) { - this.sourceObject = copy.sourceObject; + private Commander(final Commander commander) { + this.sourceObject = commander.sourceObject; + this.copy = commander.copy; + this.copyFrom = (commander.copyFrom != null ? commander.copyFrom.copy() : null); } @Override @@ -68,6 +73,22 @@ public class Commander implements CommandObject { return new Commander(this); } + @Override + public void setCopy(boolean isCopy, MageObject copyFrom) { + this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); + } + + @Override + public boolean isCopy() { + return this.copy; + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; + } + @Override public String getName() { return sourceObject.getName(); @@ -170,15 +191,6 @@ public class Commander implements CommandObject { public void adjustTargets(Ability ability, Game game) { } - @Override - public void setCopy(boolean isCopy) { - } - - @Override - public boolean isCopy() { - return false; - } - @Override public UUID getId() { return sourceObject.getId(); diff --git a/Mage/src/main/java/mage/game/command/Emblem.java b/Mage/src/main/java/mage/game/command/Emblem.java index d95cfb659d6..7a4a8896aa7 100644 --- a/Mage/src/main/java/mage/game/command/Emblem.java +++ b/Mage/src/main/java/mage/game/command/Emblem.java @@ -1,8 +1,5 @@ package mage.game.command; -import java.util.EnumSet; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.ObjectColor; @@ -25,6 +22,10 @@ import mage.game.events.ZoneChangeEvent; import mage.util.GameLog; import mage.util.SubTypeList; +import java.util.EnumSet; +import java.util.List; +import java.util.UUID; + /** * @author nantuko */ @@ -38,6 +39,8 @@ public class Emblem implements CommandObject { private UUID id; private UUID controllerId; private MageObject sourceObject; + private boolean copy; + private MageObject copyFrom; // copied card INFO (used to call original adjusters) private FrameStyle frameStyle; private Abilities abilites = new AbilitiesImpl<>(); private String expansionSetCodeForImage = ""; @@ -52,6 +55,8 @@ public class Emblem implements CommandObject { this.frameStyle = emblem.frameStyle; this.controllerId = emblem.controllerId; this.sourceObject = emblem.sourceObject; + this.copy = emblem.copy; + this.copyFrom = (emblem.copyFrom != null ? emblem.copyFrom : null); this.abilites = emblem.abilites.copy(); this.expansionSetCodeForImage = emblem.expansionSetCodeForImage; } @@ -101,6 +106,22 @@ public class Emblem implements CommandObject { this.abilites.setControllerId(controllerId); } + @Override + public void setCopy(boolean isCopy, MageObject copyFrom) { + this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); + } + + @Override + public boolean isCopy() { + return this.copy; + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; + } + @Override public String getName() { return name; @@ -204,15 +225,6 @@ public class Emblem implements CommandObject { return this.id; } - @Override - public void setCopy(boolean isCopy) { - } - - @Override - public boolean isCopy() { - return false; - } - @Override public Emblem copy() { return new Emblem(this); diff --git a/Mage/src/main/java/mage/game/command/Plane.java b/Mage/src/main/java/mage/game/command/Plane.java index ae34edade03..d05b0ceed36 100644 --- a/Mage/src/main/java/mage/game/command/Plane.java +++ b/Mage/src/main/java/mage/game/command/Plane.java @@ -41,6 +41,8 @@ public class Plane implements CommandObject { private UUID id; private UUID controllerId; private MageObject sourceObject; + private boolean copy; + private MageObject copyFrom; // copied card INFO (used to call original adjusters) private FrameStyle frameStyle; private Abilities abilites = new AbilitiesImpl<>(); private String expansionSetCodeForImage = ""; @@ -56,6 +58,8 @@ public class Plane implements CommandObject { this.frameStyle = plane.frameStyle; this.controllerId = plane.controllerId; this.sourceObject = plane.sourceObject; + this.copy = plane.copy; + this.copyFrom = (plane.copyFrom != null ? plane.copyFrom.copy() : null); this.abilites = plane.abilites.copy(); this.expansionSetCodeForImage = plane.expansionSetCodeForImage; } @@ -105,6 +109,22 @@ public class Plane implements CommandObject { this.abilites.setControllerId(controllerId); } + @Override + public void setCopy(boolean isCopy, MageObject copyFrom) { + this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); + } + + @Override + public boolean isCopy() { + return this.copy; + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; + } + @Override public String getName() { return name; @@ -208,15 +228,6 @@ public class Plane implements CommandObject { return this.id; } - @Override - public void setCopy(boolean isCopy) { - } - - @Override - public boolean isCopy() { - return false; - } - @Override public Plane copy() { return new Plane(this); diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index 281a6485dd7..bfc8fce81c2 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -1,10 +1,5 @@ - package mage.game.stack; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.Mana; @@ -39,8 +34,12 @@ import mage.players.Player; import mage.util.GameLog; import mage.util.SubTypeList; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class Spell extends StackObjImpl implements Card { @@ -63,7 +62,8 @@ public class Spell extends StackObjImpl implements Card { private final UUID id; private UUID controllerId; - private boolean copiedSpell; + private boolean copy; + private MageObject copyFrom; // copied card INFO (used to call original adjusters) private boolean faceDown; private boolean countered; private boolean resolving = false; @@ -118,7 +118,8 @@ public class Spell extends StackObjImpl implements Card { this.frameStyle = spell.frameStyle; this.controllerId = spell.controllerId; - this.copiedSpell = spell.copiedSpell; + this.copy = spell.copy; + this.copyFrom = (spell.copyFrom != null ? spell.copyFrom.copy() : null); this.faceDown = spell.faceDown; this.countered = spell.countered; this.resolving = spell.resolving; @@ -155,7 +156,7 @@ public class Spell extends StackObjImpl implements Card { public String getActivatedMessage(Game game) { StringBuilder sb = new StringBuilder(); - if (isCopiedSpell()) { + if (isCopy()) { sb.append(" copies "); } else { sb.append(" casts "); @@ -362,7 +363,7 @@ public class Spell extends StackObjImpl implements Card { @Override public void counter(UUID sourceId, Game game, Zone zone, boolean owner, ZoneDetail zoneDetail) { this.countered = true; - if (!isCopiedSpell()) { + if (!isCopy()) { Player player = game.getPlayer(game.getControllerId(sourceId)); if (player == null) { player = game.getPlayer(getControllerId()); @@ -706,7 +707,7 @@ public class Spell extends StackObjImpl implements Card { newAbility.newId(); copy.addSpellAbility(newAbility); } - copy.setCopy(true); + copy.setCopy(true, this); copy.setControllerId(newController); return copy; } @@ -740,7 +741,7 @@ public class Spell extends StackObjImpl implements Card { // 706.10a If a copy of a spell is in a zone other than the stack, it ceases to exist. // If a copy of a card is in any zone other than the stack or the battlefield, it ceases to exist. // These are state-based actions. See rule 704. - if (this.isCopiedSpell() && zone != Zone.STACK) { + if (this.isCopy() && zone != Zone.STACK) { return true; } return card.moveToZone(zone, sourceId, game, flag, appliedEffects); @@ -753,7 +754,7 @@ public class Spell extends StackObjImpl implements Card { @Override public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List appliedEffects) { - if (this.isCopiedSpell()) { + if (this.isCopy()) { game.getStack().remove(this, game); return true; } @@ -835,26 +836,24 @@ public class Spell extends StackObjImpl implements Card { // do nothing } - public void setCopiedSpell(boolean isCopied) { - this.copiedSpell = isCopied; - } - - public boolean isCopiedSpell() { - return this.copiedSpell; - } - public Zone getFromZone() { return this.fromZone; } @Override - public void setCopy(boolean isCopy) { - setCopiedSpell(isCopy); + public void setCopy(boolean isCopy, MageObject copyFrom) { + this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); } @Override public boolean isCopy() { - return isCopiedSpell(); + return this.copy; + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; } @Override diff --git a/Mage/src/main/java/mage/game/stack/StackAbility.java b/Mage/src/main/java/mage/game/stack/StackAbility.java index 02546c99c23..2fcadf1147b 100644 --- a/Mage/src/main/java/mage/game/stack/StackAbility.java +++ b/Mage/src/main/java/mage/game/stack/StackAbility.java @@ -1,9 +1,5 @@ package mage.game.stack; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.ObjectColor; @@ -32,8 +28,12 @@ import mage.util.GameLog; import mage.util.SubTypeList; import mage.watchers.Watcher; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class StackAbility extends StackObjImpl implements Ability { @@ -47,6 +47,8 @@ public class StackAbility extends StackObjImpl implements Ability { private final Ability ability; private UUID controllerId; + private boolean copy; + private MageObject copyFrom; // copied card INFO (used to call original adjusters) private String name; private String expansionSetCode; private TargetAdjuster targetAdjuster = null; @@ -60,6 +62,8 @@ public class StackAbility extends StackObjImpl implements Ability { public StackAbility(final StackAbility stackAbility) { this.ability = stackAbility.ability.copy(); this.controllerId = stackAbility.controllerId; + this.copy = stackAbility.copy; + this.copyFrom = (stackAbility.copyFrom != null ? stackAbility.copyFrom.copy() : null); this.name = stackAbility.name; this.expansionSetCode = stackAbility.expansionSetCode; this.targetAdjuster = stackAbility.targetAdjuster; @@ -104,6 +108,22 @@ public class StackAbility extends StackObjImpl implements Ability { } } + @Override + public void setCopy(boolean isCopy, MageObject copyFrom) { + this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); + } + + @Override + public boolean isCopy() { + return this.copy; + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; + } + @Override public String getName() { return name; @@ -408,15 +428,6 @@ public class StackAbility extends StackObjImpl implements Ability { throw new UnsupportedOperationException("Not supported."); } - @Override - public void setCopy(boolean isCopy) { - } - - @Override - public boolean isCopy() { - return false; - } - @Override public boolean getRuleAtTheTop() { return this.ability.getRuleAtTheTop(); diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index ec355521d91..cfb0f1ac702 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -1,9 +1,5 @@ package mage.players; -import java.io.Serializable; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.Map.Entry; import mage.ConditionalMana; import mage.MageObject; import mage.MageObjectReference; @@ -72,6 +68,11 @@ import mage.util.GameLog; import mage.util.RandomUtil; import org.apache.log4j.Logger; +import java.io.Serializable; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.Map.Entry; + public abstract class PlayerImpl implements Player, Serializable { private static final Logger logger = Logger.getLogger(PlayerImpl.class); @@ -2573,7 +2574,7 @@ public abstract class PlayerImpl implements Player, Serializable { /** * @param game * @param appliedEffects - * @param numSides Number of sides the dice has + * @param numSides Number of sides the dice has * @return the number that the player rolled */ @Override @@ -2607,10 +2608,10 @@ public abstract class PlayerImpl implements Player, Serializable { /** * @param game * @param appliedEffects - * @param numberChaosSides The number of chaos sides the planar die - * currently has (normally 1 but can be 5) + * @param numberChaosSides The number of chaos sides the planar die + * currently has (normally 1 but can be 5) * @param numberPlanarSides The number of chaos sides the planar die - * currently has (normally 1) + * currently has (normally 1) * @return the outcome that the player rolled. Either ChaosRoll, PlanarRoll * or NilRoll */ @@ -2767,7 +2768,7 @@ public abstract class PlayerImpl implements Player, Serializable { /** * @param ability - * @param available if null, it won't be checked if enough mana is available + * @param available if null, it won't be checked if enough mana is available * @param sourceObject * @param game * @return @@ -3319,7 +3320,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean canPaySacrificeCost(Permanent permanent, UUID sourceId, - UUID controllerId, Game game + UUID controllerId, Game game ) { return sacrificeCostFilter == null || !sacrificeCostFilter.match(permanent, sourceId, controllerId, game); } @@ -3467,8 +3468,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCards(Card card, Zone toZone, - Ability source, Game game, - boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects ) { Set cardList = new HashSet<>(); if (card != null) { @@ -3479,22 +3480,22 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCards(Cards cards, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return moveCards(cards.getCards(game), toZone, source, game); } @Override public boolean moveCards(Set cards, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return moveCards(cards, toZone, source, game, false, false, false, null); } @Override public boolean moveCards(Set cards, Zone toZone, - Ability source, Game game, - boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects ) { if (cards.isEmpty()) { return true; @@ -3580,8 +3581,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardsToExile(Card card, Ability source, - Game game, boolean withName, UUID exileId, - String exileZoneName + Game game, boolean withName, UUID exileId, + String exileZoneName ) { Set cards = new HashSet<>(); cards.add(card); @@ -3590,8 +3591,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardsToExile(Set cards, Ability source, - Game game, boolean withName, UUID exileId, - String exileZoneName + Game game, boolean withName, UUID exileId, + String exileZoneName ) { if (cards.isEmpty()) { return true; @@ -3606,14 +3607,14 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToHandWithInfo(Card card, UUID sourceId, - Game game + Game game ) { return this.moveCardToHandWithInfo(card, sourceId, game, true); } @Override public boolean moveCardToHandWithInfo(Card card, UUID sourceId, - Game game, boolean withName + Game game, boolean withName ) { boolean result = false; Zone fromZone = game.getState().getZone(card.getId()); @@ -3638,7 +3639,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public Set moveCardsToGraveyardWithInfo(Set allCards, Ability source, - Game game, Zone fromZone + Game game, Zone fromZone ) { UUID sourceId = source == null ? null : source.getSourceId(); Set movedCards = new LinkedHashSet<>(); @@ -3646,7 +3647,7 @@ public abstract class PlayerImpl implements Player, Serializable { // identify cards from one owner Cards cards = new CardsImpl(); UUID ownerId = null; - for (Iterator it = allCards.iterator(); it.hasNext();) { + for (Iterator it = allCards.iterator(); it.hasNext(); ) { Card card = it.next(); if (cards.isEmpty()) { ownerId = card.getOwnerId(); @@ -3707,7 +3708,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId, - Game game, Zone fromZone + Game game, Zone fromZone ) { if (card == null) { return false; @@ -3736,8 +3737,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, - Game game, Zone fromZone, - boolean toTop, boolean withName + Game game, Zone fromZone, + boolean toTop, boolean withName ) { if (card == null) { return false; @@ -3771,7 +3772,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToExileWithInfo(Card card, UUID exileId, String exileName, UUID sourceId, - Game game, Zone fromZone, boolean withName) { + Game game, Zone fromZone, boolean withName) { if (card == null) { return false; } @@ -3786,7 +3787,7 @@ public abstract class PlayerImpl implements Player, Serializable { } } else if (card instanceof Spell) { final Spell spell = (Spell) card; - if (spell.isCopiedSpell()) { + if (spell.isCopy()) { // Copied spell, only remove from stack game.getStack().remove(spell, game); }