From 8105d8b26cf710e6719b7fb03f8de42d666cad7f Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 21 Aug 2020 14:58:22 +0200 Subject: [PATCH] * Improved handling of asThoughtAs approval by abilities that allows a clear and easy assignment of the approving effect. --- .../java/mage/player/ai/ComputerPlayer.java | 19 ++-- .../src/mage/cards/a/AetherworksMarvel.java | 4 +- .../src/mage/cards/a/AllureOfTheUnknown.java | 4 +- .../src/mage/cards/a/AshiokNightmareMuse.java | 4 +- Mage.Sets/src/mage/cards/b/BrainInAJar.java | 4 +- .../src/mage/cards/b/BrilliantUltimatum.java | 4 +- Mage.Sets/src/mage/cards/b/BringToLight.java | 5 +- Mage.Sets/src/mage/cards/c/ChandraAblaze.java | 4 +- .../src/mage/cards/c/ChandraPyromaster.java | 10 +- .../mage/cards/c/ChandraTorchOfDefiance.java | 4 +- Mage.Sets/src/mage/cards/c/ChaosWand.java | 4 +- .../src/mage/cards/c/CollectedConjuring.java | 4 +- Mage.Sets/src/mage/cards/c/Counterlash.java | 4 +- .../src/mage/cards/d/DescendantsPath.java | 4 +- .../src/mage/cards/d/DiluvianPrimordial.java | 4 +- Mage.Sets/src/mage/cards/d/DjinnOfWishes.java | 4 +- .../src/mage/cards/d/DreadhordeArcanist.java | 4 +- Mage.Sets/src/mage/cards/e/EliteArcanist.java | 4 +- .../src/mage/cards/e/EmergentUltimatum.java | 4 +- .../src/mage/cards/e/EpicExperiment.java | 4 +- .../src/mage/cards/e/EtaliPrimalStorm.java | 4 +- Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java | 4 +- .../src/mage/cards/f/FinaleOfPromise.java | 4 +- Mage.Sets/src/mage/cards/g/Galvanoth.java | 4 +- Mage.Sets/src/mage/cards/g/GeodeGolem.java | 4 +- Mage.Sets/src/mage/cards/g/GisaAndGeralf.java | 94 +++++----------- .../src/mage/cards/g/GoblinDarkDwellers.java | 4 +- .../src/mage/cards/g/GodEternalKefnet.java | 4 +- Mage.Sets/src/mage/cards/g/Guile.java | 4 +- .../src/mage/cards/h/HarnessTheStorm.java | 4 +- .../src/mage/cards/h/HazoretsUndyingFury.java | 4 +- .../src/mage/cards/h/HellcarverDemon.java | 4 +- .../src/mage/cards/h/HordeOfNotions.java | 4 +- .../src/mage/cards/i/IdolOfEndurance.java | 2 +- .../src/mage/cards/i/IsochronScepter.java | 4 +- .../src/mage/cards/i/IzzetChemister.java | 4 +- .../mage/cards/j/JaceArchitectOfThought.java | 4 +- .../src/mage/cards/j/JacesMindseeker.java | 4 +- .../mage/cards/j/JelevaNephaliasScourge.java | 4 +- .../src/mage/cards/k/KahoMinamoHistorian.java | 4 +- .../mage/cards/k/KaradorGhostChieftain.java | 37 +++---- .../src/mage/cards/k/KessDissidentMage.java | 17 ++- .../mage/cards/k/KnowledgeExploitation.java | 4 +- Mage.Sets/src/mage/cards/k/KnowledgePool.java | 4 +- .../src/mage/cards/l/LeafCrownedElder.java | 4 +- Mage.Sets/src/mage/cards/l/LivingLore.java | 3 +- .../src/mage/cards/l/LurrusOfTheDreamDen.java | 103 +++++------------- .../src/mage/cards/m/MaelstromArchangel.java | 4 +- .../mage/cards/m/MasterOfPredicaments.java | 4 +- Mage.Sets/src/mage/cards/m/MemoryPlunder.java | 4 +- .../src/mage/cards/m/MindclawShaman.java | 4 +- Mage.Sets/src/mage/cards/m/MindleechMass.java | 4 +- Mage.Sets/src/mage/cards/m/MindsDilation.java | 4 +- .../src/mage/cards/m/MizzixsMastery.java | 6 +- .../mage/cards/m/MuldrothaTheGravetide.java | 13 ++- Mage.Sets/src/mage/cards/m/MythRealized.java | 5 +- Mage.Sets/src/mage/cards/o/OmenMachine.java | 4 +- .../src/mage/cards/o/OmnispellAdept.java | 4 +- Mage.Sets/src/mage/cards/o/OracleOfBones.java | 4 +- .../src/mage/cards/p/PanopticMirror.java | 4 +- .../src/mage/cards/p/PossibilityStorm.java | 4 +- .../mage/cards/r/RashmiEternitiesCrafter.java | 4 +- .../src/mage/cards/r/ReversalOfFortune.java | 4 +- .../mage/cards/s/ScholarOfTheLostTrove.java | 4 +- .../src/mage/cards/s/ShellOfTheLastKappa.java | 3 +- .../src/mage/cards/s/SilentBladeOni.java | 5 +- Mage.Sets/src/mage/cards/s/SpellQueller.java | 4 +- Mage.Sets/src/mage/cards/s/Spellbinder.java | 4 +- Mage.Sets/src/mage/cards/s/Spellshift.java | 4 +- Mage.Sets/src/mage/cards/s/Spelltwine.java | 9 +- .../src/mage/cards/s/SpellweaverHelix.java | 4 +- .../src/mage/cards/s/SpellweaverVolute.java | 4 +- .../src/mage/cards/s/SunbirdsInvocation.java | 4 +- Mage.Sets/src/mage/cards/s/Sunforger.java | 4 +- .../src/mage/cards/t/TalentOfTheTelepath.java | 4 +- .../src/mage/cards/t/ThunderbladeCharge.java | 4 +- .../src/mage/cards/t/TorrentialGearhulk.java | 4 +- .../src/mage/cards/t/ToshiroUmezawa.java | 4 +- .../src/mage/cards/t/TreasureKeeper.java | 5 +- Mage.Sets/src/mage/cards/t/TwinningGlass.java | 4 +- .../src/mage/cards/u/UnexpectedResults.java | 4 +- .../mage/cards/u/UnpredictableCyclone.java | 4 +- .../src/mage/cards/v/VillainousWealth.java | 4 +- Mage.Sets/src/mage/cards/w/WildEvocation.java | 4 +- .../src/mage/cards/w/WildfireDevils.java | 3 +- .../src/mage/cards/w/WildfireEternal.java | 4 +- Mage.Sets/src/mage/cards/w/WordOfCommand.java | 4 +- .../src/mage/cards/w/WrexialTheRisenDeep.java | 4 +- .../mage/cards/y/YennettCrypticSovereign.java | 4 +- .../KaradorGhostChieftainTest.java | 50 ++++++++- .../java/org/mage/test/player/TestPlayer.java | 8 +- .../java/org/mage/test/stub/PlayerStub.java | 5 +- Mage/src/main/java/mage/ApprovingObject.java | 33 ++++++ Mage/src/main/java/mage/MageIdentifier.java | 15 +++ .../src/main/java/mage/abilities/Ability.java | 5 + .../main/java/mage/abilities/AbilityImpl.java | 17 ++- .../java/mage/abilities/ActivatedAbility.java | 20 ++-- .../mage/abilities/ActivatedAbilityImpl.java | 8 +- .../java/mage/abilities/PlayLandAbility.java | 8 +- .../java/mage/abilities/SpellAbility.java | 8 +- .../abilities/effects/ContinuousEffects.java | 7 +- .../CastCardFromOutsideTheGameEffect.java | 3 +- .../effects/common/CipherEffect.java | 3 +- .../effects/common/HideawayPlayEffect.java | 3 +- .../PlayTargetWithoutPayingManaEffect.java | 3 +- .../cost/CastWithoutPayingManaCostEffect.java | 3 +- .../abilities/keyword/CascadeAbility.java | 3 +- .../abilities/keyword/MadnessAbility.java | 4 +- .../abilities/keyword/MiracleAbility.java | 3 +- .../abilities/keyword/ReboundAbility.java | 3 +- .../mage/abilities/keyword/RippleAbility.java | 3 +- .../abilities/keyword/SuspendAbility.java | 4 +- Mage/src/main/java/mage/cards/CardImpl.java | 2 +- .../main/java/mage/game/events/GameEvent.java | 41 +++++-- .../java/mage/game/stack/StackAbility.java | 12 ++ Mage/src/main/java/mage/players/Player.java | 29 ++--- .../main/java/mage/players/PlayerImpl.java | 35 +++--- 117 files changed, 523 insertions(+), 442 deletions(-) create mode 100644 Mage/src/main/java/mage/ApprovingObject.java create mode 100644 Mage/src/main/java/mage/MageIdentifier.java diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index cb0aa7aa541..76b9a7f077a 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.io.Serializable; import java.util.*; import java.util.Map.Entry; +import mage.ApprovingObject; import mage.ConditionalMana; import mage.MageObject; import mage.MageObjectReference; @@ -1400,7 +1401,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { protected boolean playManaHandling(Ability ability, ManaCost unpaid, final Game game) { // log.info("paying for " + unpaid.getText()); - MageObjectReference permittingObject = game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_OTHER_MANA, ability, ability.getControllerId(), game); + ApprovingObject approvingObject = game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_OTHER_MANA, ability, ability.getControllerId(), game); ManaCost cost; List producers; if (unpaid instanceof ManaCosts) { @@ -1444,7 +1445,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ActivatedManaAbilityImpl manaAbility : getManaAbilitiesSortedByManaCount(mageObject, game)) { if (cost instanceof ColoredManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { - if (cost.testPay(netMana) || permittingObject != null) { + if (cost.testPay(netMana) || approvingObject != null) { if (netMana instanceof ConditionalMana && !((ConditionalMana) netMana).apply(ability, game, getId(), cost)) { continue; } @@ -1459,7 +1460,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ActivatedManaAbilityImpl manaAbility : getManaAbilitiesSortedByManaCount(mageObject, game)) { if (cost instanceof SnowManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { - if (cost.testPay(netMana) || permittingObject != null) { + if (cost.testPay(netMana) || approvingObject != null) { if (netMana instanceof ConditionalMana && !((ConditionalMana) netMana).apply(ability, game, getId(), cost)) { continue; } @@ -1474,7 +1475,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ActivatedManaAbilityImpl manaAbility : getManaAbilitiesSortedByManaCount(mageObject, game)) { if (cost instanceof HybridManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { - if (cost.testPay(netMana) || permittingObject != null) { + if (cost.testPay(netMana) || approvingObject != null) { if (netMana instanceof ConditionalMana && !((ConditionalMana) netMana).apply(ability, game, getId(), cost)) { continue; } @@ -1489,7 +1490,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ActivatedManaAbilityImpl manaAbility : getManaAbilitiesSortedByManaCount(mageObject, game)) { if (cost instanceof MonoHybridManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { - if (cost.testPay(netMana) || permittingObject != null) { + if (cost.testPay(netMana) || approvingObject != null) { if (netMana instanceof ConditionalMana && !((ConditionalMana) netMana).apply(ability, game, getId(), cost)) { continue; } @@ -1504,7 +1505,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ActivatedManaAbilityImpl manaAbility : getManaAbilitiesSortedByManaCount(mageObject, game)) { if (cost instanceof ColorlessManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { - if (cost.testPay(netMana) || permittingObject != null) { + if (cost.testPay(netMana) || approvingObject != null) { if (netMana instanceof ConditionalMana && !((ConditionalMana) netMana).apply(ability, game, getId(), cost)) { continue; } @@ -1519,7 +1520,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ActivatedManaAbilityImpl manaAbility : getManaAbilitiesSortedByManaCount(mageObject, game)) { if (cost instanceof GenericManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { - if (cost.testPay(netMana) || permittingObject != null) { + if (cost.testPay(netMana) || approvingObject != null) { if (netMana instanceof ConditionalMana && !((ConditionalMana) netMana).apply(ability, game, getId(), cost)) { continue; } @@ -1534,7 +1535,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { // pay phyrexian life costs if (cost instanceof PhyrexianManaCost) { - return cost.pay(null, game, null, playerId, false, null) || permittingObject != null; + return cost.pay(null, game, null, playerId, false, null) || approvingObject != null; } // pay special mana like convoke cost (tap for pay) @@ -1545,7 +1546,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { ManaOptions specialMana = specialAction == null ? null : specialAction.getManaOptions(ability, game, unpaid); if (specialMana != null) { for (Mana netMana : specialMana) { - if (cost.testPay(netMana) || permittingObject != null) { + if (cost.testPay(netMana) || approvingObject != null) { if (netMana instanceof ConditionalMana && !((ConditionalMana) netMana).apply(ability, game, getId(), cost)) { continue; } diff --git a/Mage.Sets/src/mage/cards/a/AetherworksMarvel.java b/Mage.Sets/src/mage/cards/a/AetherworksMarvel.java index 7d751ce034f..1ebf90d4ca6 100644 --- a/Mage.Sets/src/mage/cards/a/AetherworksMarvel.java +++ b/Mage.Sets/src/mage/cards/a/AetherworksMarvel.java @@ -2,7 +2,7 @@ package mage.cards.a; import java.util.Set; import java.util.UUID; -import mage.MageObjectReference; +import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.common.PutIntoGraveFromBattlefieldAllTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -88,7 +88,7 @@ class AetherworksMarvelEffect extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); if (cardWasCast) { cards.remove(card); diff --git a/Mage.Sets/src/mage/cards/a/AllureOfTheUnknown.java b/Mage.Sets/src/mage/cards/a/AllureOfTheUnknown.java index 168a48842d1..ec7bd69d8f7 100644 --- a/Mage.Sets/src/mage/cards/a/AllureOfTheUnknown.java +++ b/Mage.Sets/src/mage/cards/a/AllureOfTheUnknown.java @@ -1,6 +1,5 @@ package mage.cards.a; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.*; @@ -15,6 +14,7 @@ import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetOpponent; import java.util.UUID; +import mage.ApprovingObject; /** * @author TheElk801 @@ -88,7 +88,7 @@ class AllureOfTheUnknownEffect extends OneShotEffect { if (opponent.chooseUse(outcome, "Cast the exiled card without paying its mana cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); opponent.cast(opponent.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } return true; diff --git a/Mage.Sets/src/mage/cards/a/AshiokNightmareMuse.java b/Mage.Sets/src/mage/cards/a/AshiokNightmareMuse.java index e1ee8dde9eb..6c783fb101d 100644 --- a/Mage.Sets/src/mage/cards/a/AshiokNightmareMuse.java +++ b/Mage.Sets/src/mage/cards/a/AshiokNightmareMuse.java @@ -1,7 +1,7 @@ package mage.cards.a; import java.util.UUID; -import mage.MageObjectReference; +import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; @@ -132,7 +132,7 @@ class AshiokNightmareMuseCastEffect extends OneShotEffect { && controller.chooseUse(outcome, "Cast " + chosenCard.getName() + " without paying its mana cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(chosenCard, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/b/BrainInAJar.java b/Mage.Sets/src/mage/cards/b/BrainInAJar.java index 35f30d72c7e..a9980006c06 100644 --- a/Mage.Sets/src/mage/cards/b/BrainInAJar.java +++ b/Mage.Sets/src/mage/cards/b/BrainInAJar.java @@ -1,7 +1,7 @@ package mage.cards.b; import java.util.UUID; -import mage.MageObjectReference; +import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.RemoveVariableCountersSourceCost; @@ -106,7 +106,7 @@ class BrainInAJarCastEffect extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/b/BrilliantUltimatum.java b/Mage.Sets/src/mage/cards/b/BrilliantUltimatum.java index 4dc433e7c1e..c29a4103d71 100644 --- a/Mage.Sets/src/mage/cards/b/BrilliantUltimatum.java +++ b/Mage.Sets/src/mage/cards/b/BrilliantUltimatum.java @@ -3,8 +3,8 @@ package mage.cards.b; import java.util.ArrayList; import java.util.List; import java.util.UUID; +import mage.ApprovingObject; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.*; @@ -111,7 +111,7 @@ class BrilliantUltimatumEffect extends OneShotEffect { if (controller.chooseTarget(Outcome.PlayForFree, selectedPile, targetExiledCard, source, game)) { Card card = selectedPile.get(targetExiledCard.getFirstTarget(), game); controller.canPlayLand(); - if (controller.playCard(card, game, true, true, new MageObjectReference(source.getSourceObject(game), game))) { + if (controller.playCard(card, game, true, true, new ApprovingObject(source, game))) { selectedPileCards.remove(card); selectedPile.remove(card); } diff --git a/Mage.Sets/src/mage/cards/b/BringToLight.java b/Mage.Sets/src/mage/cards/b/BringToLight.java index 88f7e78a9c0..8f69039e0d0 100644 --- a/Mage.Sets/src/mage/cards/b/BringToLight.java +++ b/Mage.Sets/src/mage/cards/b/BringToLight.java @@ -1,7 +1,7 @@ package mage.cards.b; import java.util.UUID; -import mage.MageObjectReference; +import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.dynamicvalue.common.ColorsOfManaSpentToCastCount; import mage.abilities.effects.OneShotEffect; @@ -18,7 +18,6 @@ import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; -import org.apache.log4j.Logger; /** * @author LevelX2 @@ -84,7 +83,7 @@ class BringToLightEffect extends OneShotEffect { + " without paying its mana cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/c/ChandraAblaze.java b/Mage.Sets/src/mage/cards/c/ChandraAblaze.java index 4128d0687f0..4af1d85d86e 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraAblaze.java +++ b/Mage.Sets/src/mage/cards/c/ChandraAblaze.java @@ -1,6 +1,5 @@ package mage.cards.c; -import mage.MageObjectReference; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; @@ -28,6 +27,7 @@ import mage.target.common.TargetDiscard; import java.util.Set; import java.util.UUID; +import mage.ApprovingObject; /** * @author North @@ -171,7 +171,7 @@ class ChandraAblazeEffect5 extends OneShotEffect { if (player.choose(outcome, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); + player.cast(card.getSpellAbility(), game, true, new ApprovingObject(source, game)); cards.remove(card); } } diff --git a/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java b/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java index 8c526836ac0..50c31a52ebc 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java +++ b/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java @@ -3,8 +3,8 @@ package mage.cards.c; import java.util.HashSet; import java.util.Set; import java.util.UUID; +import mage.ApprovingObject; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; @@ -230,26 +230,26 @@ class ChandraPyromasterEffect3 extends OneShotEffect { if (controller.chooseTarget(Outcome.PlayForFree, cards, target, source, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { - MageObjectReference mor = new MageObjectReference(source.getSourceObject(game), game); + ApprovingObject approvingObject = new ApprovingObject(source, game); if (controller.chooseUse(outcome, "Do you wish to cast copy 1 of " + card.getName(), source, game)) { Card copy1 = game.copyCard(card, source, source.getControllerId()); game.getState().setValue("PlayFromNotOwnHandZone" + copy1.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(copy1, game, true), - game, true, mor); + game, true, approvingObject); game.getState().setValue("PlayFromNotOwnHandZone" + copy1.getId(), null); } if (controller.chooseUse(outcome, "Do you wish to cast copy 2 of " + card.getName(), source, game)) { Card copy2 = game.copyCard(card, source, source.getControllerId()); game.getState().setValue("PlayFromNotOwnHandZone" + copy2.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(copy2, game, true), - game, true, mor); + game, true, approvingObject); game.getState().setValue("PlayFromNotOwnHandZone" + copy2.getId(), null); } if (controller.chooseUse(outcome, "Do you wish to cast copy 3 of " + card.getName(), source, game)) { Card copy3 = game.copyCard(card, source, source.getControllerId()); game.getState().setValue("PlayFromNotOwnHandZone" + copy3.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(copy3, game, true), - game, true, mor); + game, true, approvingObject); game.getState().setValue("PlayFromNotOwnHandZone" + copy3.getId(), null); } return true; diff --git a/Mage.Sets/src/mage/cards/c/ChandraTorchOfDefiance.java b/Mage.Sets/src/mage/cards/c/ChandraTorchOfDefiance.java index 793e0dfe27a..838170a8264 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraTorchOfDefiance.java +++ b/Mage.Sets/src/mage/cards/c/ChandraTorchOfDefiance.java @@ -1,8 +1,8 @@ package mage.cards.c; import java.util.UUID; +import mage.ApprovingObject; import mage.MageObject; -import mage.MageObjectReference; import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; @@ -98,7 +98,7 @@ class ChandraTorchOfDefianceEffect extends OneShotEffect { && (game.getState().getZone(card.getId()) == Zone.EXILED)) { // card must be in the exile zone game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); // enable the card to be cast from the exile zone cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, false), - game, false, new MageObjectReference(sourceObject, game)); + game, false, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); // reset to null } } diff --git a/Mage.Sets/src/mage/cards/c/ChaosWand.java b/Mage.Sets/src/mage/cards/c/ChaosWand.java index e57fc6b87d1..9b6004aab01 100644 --- a/Mage.Sets/src/mage/cards/c/ChaosWand.java +++ b/Mage.Sets/src/mage/cards/c/ChaosWand.java @@ -1,6 +1,5 @@ package mage.cards.c; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; @@ -15,6 +14,7 @@ import mage.players.Player; import mage.target.common.TargetOpponent; import java.util.UUID; +import mage.ApprovingObject; /** * @author TheElk801 @@ -88,7 +88,7 @@ class ChaosWandEffect extends OneShotEffect { + " without paying its mana cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } if (!cardWasCast) { diff --git a/Mage.Sets/src/mage/cards/c/CollectedConjuring.java b/Mage.Sets/src/mage/cards/c/CollectedConjuring.java index c8e10c785d0..3e6ef64ae5d 100644 --- a/Mage.Sets/src/mage/cards/c/CollectedConjuring.java +++ b/Mage.Sets/src/mage/cards/c/CollectedConjuring.java @@ -1,7 +1,6 @@ package mage.cards.c; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.*; @@ -16,6 +15,7 @@ import mage.players.Player; import mage.target.TargetCard; import java.util.UUID; +import mage.ApprovingObject; /** * @author TheElk801 @@ -103,7 +103,7 @@ class CollectedConjuringEffect extends OneShotEffect { } game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); cardsToChoose.remove(card); // remove on non cast too (infinite freeze fix) if (cardWasCast) { diff --git a/Mage.Sets/src/mage/cards/c/Counterlash.java b/Mage.Sets/src/mage/cards/c/Counterlash.java index b6c350b5ac8..1ca9eb23239 100644 --- a/Mage.Sets/src/mage/cards/c/Counterlash.java +++ b/Mage.Sets/src/mage/cards/c/Counterlash.java @@ -3,8 +3,8 @@ package mage.cards.c; import java.util.ArrayList; import java.util.List; import java.util.UUID; +import mage.ApprovingObject; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -87,7 +87,7 @@ class CounterlashEffect extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/d/DescendantsPath.java b/Mage.Sets/src/mage/cards/d/DescendantsPath.java index 9f66411ff2a..92445e71ac8 100644 --- a/Mage.Sets/src/mage/cards/d/DescendantsPath.java +++ b/Mage.Sets/src/mage/cards/d/DescendantsPath.java @@ -1,8 +1,8 @@ package mage.cards.d; import java.util.UUID; +import mage.ApprovingObject; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -89,7 +89,7 @@ class DescendantsPathEffect extends OneShotEffect { if (controller.chooseUse(Outcome.Benefit, "Cast the card?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } else { game.informPlayers(sourceObject.getLogName() + ": " + controller.getLogName() + " canceled casting the card."); diff --git a/Mage.Sets/src/mage/cards/d/DiluvianPrimordial.java b/Mage.Sets/src/mage/cards/d/DiluvianPrimordial.java index 78f0f576fdd..16f99d9ca78 100644 --- a/Mage.Sets/src/mage/cards/d/DiluvianPrimordial.java +++ b/Mage.Sets/src/mage/cards/d/DiluvianPrimordial.java @@ -1,7 +1,6 @@ package mage.cards.d; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.ContinuousEffect; @@ -26,6 +25,7 @@ import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.FixedTarget; import java.util.UUID; +import mage.ApprovingObject; /** * @author LevelX2 @@ -112,7 +112,7 @@ class DiluvianPrimordialEffect extends OneShotEffect { if (controller.chooseUse(Outcome.PlayForFree, "Cast " + targetCard.getLogName() + '?', source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + targetCard.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(targetCard, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + targetCard.getId(), null); if (cardWasCast) { ContinuousEffect effect = new DiluvianPrimordialReplacementEffect(); diff --git a/Mage.Sets/src/mage/cards/d/DjinnOfWishes.java b/Mage.Sets/src/mage/cards/d/DjinnOfWishes.java index 59ced44872e..c5528b7f522 100644 --- a/Mage.Sets/src/mage/cards/d/DjinnOfWishes.java +++ b/Mage.Sets/src/mage/cards/d/DjinnOfWishes.java @@ -2,9 +2,9 @@ package mage.cards.d; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -78,7 +78,7 @@ class DjinnOfWishesEffect extends OneShotEffect { Cards cards = new CardsImpl(card); controller.revealCards(sourceObject.getIdName(), cards, game); if (!controller.chooseUse(Outcome.PlayForFree, "Play " + card.getName() + " without paying its mana cost?", source, game) - || !controller.playCard(card, game, true, true, new MageObjectReference(source.getSourceObject(game), game))) { + || !controller.playCard(card, game, true, true, new ApprovingObject(source, game))) { controller.moveCards(card, Zone.EXILED, source, game); } return true; diff --git a/Mage.Sets/src/mage/cards/d/DreadhordeArcanist.java b/Mage.Sets/src/mage/cards/d/DreadhordeArcanist.java index 94c9c39694d..4808f83bfc6 100644 --- a/Mage.Sets/src/mage/cards/d/DreadhordeArcanist.java +++ b/Mage.Sets/src/mage/cards/d/DreadhordeArcanist.java @@ -1,7 +1,6 @@ package mage.cards.d; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.effects.ContinuousEffect; @@ -25,6 +24,7 @@ import mage.target.common.TargetCardInYourGraveyard; import mage.target.targetpointer.FixedTarget; import java.util.UUID; +import mage.ApprovingObject; /** * @author TheElk801 @@ -109,7 +109,7 @@ class DreadhordeArcanistEffect extends OneShotEffect { && controller.chooseUse(Outcome.PlayForFree, "Cast " + card.getLogName() + '?', source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } ContinuousEffect effect = new DreadhordeArcanistReplacementEffect(card.getId()); diff --git a/Mage.Sets/src/mage/cards/e/EliteArcanist.java b/Mage.Sets/src/mage/cards/e/EliteArcanist.java index 9034df372c2..a0beef69e25 100644 --- a/Mage.Sets/src/mage/cards/e/EliteArcanist.java +++ b/Mage.Sets/src/mage/cards/e/EliteArcanist.java @@ -1,7 +1,6 @@ package mage.cards.e; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -24,6 +23,7 @@ import mage.players.Player; import mage.target.TargetCard; import java.util.UUID; +import mage.ApprovingObject; /** * @author LevelX2 @@ -165,7 +165,7 @@ class EliteArcanistCopyEffect extends OneShotEffect { if (controller.chooseUse(Outcome.PlayForFree, "Cast the copied card without paying mana cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(copiedCard, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), null); return cardWasCast; } diff --git a/Mage.Sets/src/mage/cards/e/EmergentUltimatum.java b/Mage.Sets/src/mage/cards/e/EmergentUltimatum.java index 004297319db..5d5d980c496 100644 --- a/Mage.Sets/src/mage/cards/e/EmergentUltimatum.java +++ b/Mage.Sets/src/mage/cards/e/EmergentUltimatum.java @@ -1,7 +1,6 @@ package mage.cards.e; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileSpellEffect; @@ -19,6 +18,7 @@ import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetOpponent; import java.util.UUID; +import mage.ApprovingObject; /** * @author TheElk801 @@ -109,7 +109,7 @@ class EmergentUltimatumEffect extends OneShotEffect { } game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = player.cast(player.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); cards.remove(card); // remove on non cast too (infinite freeze fix) if (cardWasCast) { diff --git a/Mage.Sets/src/mage/cards/e/EpicExperiment.java b/Mage.Sets/src/mage/cards/e/EpicExperiment.java index 09de3bbd2ff..2ff02cae0f3 100644 --- a/Mage.Sets/src/mage/cards/e/EpicExperiment.java +++ b/Mage.Sets/src/mage/cards/e/EpicExperiment.java @@ -1,7 +1,6 @@ package mage.cards.e; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.*; @@ -18,6 +17,7 @@ import mage.players.Player; import mage.target.TargetCard; import java.util.UUID; +import mage.ApprovingObject; /** * @author LevelX2 @@ -91,7 +91,7 @@ class EpicExperimentEffect extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); if (!cardWasCast) { game.informPlayer(controller, "You're not able to cast " diff --git a/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java b/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java index c54f1c55ab6..e508270d1c2 100644 --- a/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java +++ b/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java @@ -2,7 +2,6 @@ package mage.cards.e; import mage.MageInt; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -17,6 +16,7 @@ import mage.target.TargetCard; import java.util.HashSet; import java.util.Set; import java.util.UUID; +import mage.ApprovingObject; /** * @author ciaccona007 & L_J @@ -110,7 +110,7 @@ class EtaliPrimalStormEffect extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); if (!cardWasCast) { game.informPlayer(controller, "You're not able to cast " diff --git a/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java b/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java index 86e8ba47bf4..45ca1108955 100644 --- a/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java +++ b/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java @@ -1,6 +1,5 @@ package mage.cards.e; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; @@ -22,6 +21,7 @@ import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; import java.util.UUID; +import mage.ApprovingObject; /** * @author spjspj @@ -152,7 +152,7 @@ class EyeOfTheStormEffect1 extends OneShotEffect { if (cardToCopy != null) { Card copy = game.copyCard(cardToCopy, source, source.getControllerId()); if (spellController.chooseUse(outcome, "Cast " + copy.getIdName() + " without paying mana cost?", source, game)) { - spellController.cast(copy.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); + spellController.cast(copy.getSpellAbility(), game, true, new ApprovingObject(source, game)); } } } diff --git a/Mage.Sets/src/mage/cards/f/FinaleOfPromise.java b/Mage.Sets/src/mage/cards/f/FinaleOfPromise.java index 444affb50c6..16ce007ed70 100644 --- a/Mage.Sets/src/mage/cards/f/FinaleOfPromise.java +++ b/Mage.Sets/src/mage/cards/f/FinaleOfPromise.java @@ -1,6 +1,5 @@ package mage.cards.f; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.dynamicvalue.common.ManacostVariableValue; import mage.abilities.effects.ContinuousEffect; @@ -25,6 +24,7 @@ import mage.target.targetpointer.FixedTarget; import java.util.*; import java.util.stream.Collectors; +import mage.ApprovingObject; /** * @author JayDi85 @@ -138,7 +138,7 @@ class FinaleOfPromiseEffect extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); ContinuousEffect effect = new FinaleOfPromiseReplacementEffect(); effect.setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId()))); diff --git a/Mage.Sets/src/mage/cards/g/Galvanoth.java b/Mage.Sets/src/mage/cards/g/Galvanoth.java index a17270fa6ec..dcdce34f1ec 100644 --- a/Mage.Sets/src/mage/cards/g/Galvanoth.java +++ b/Mage.Sets/src/mage/cards/g/Galvanoth.java @@ -1,8 +1,8 @@ package mage.cards.g; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -64,7 +64,7 @@ class GalvanothEffect extends OneShotEffect { if (controller.chooseUse(Outcome.PlayForFree, "Cast " + card.getName() + " without paying its mana cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/g/GeodeGolem.java b/Mage.Sets/src/mage/cards/g/GeodeGolem.java index 01933e084a4..f4f5bd8bd40 100644 --- a/Mage.Sets/src/mage/cards/g/GeodeGolem.java +++ b/Mage.Sets/src/mage/cards/g/GeodeGolem.java @@ -1,7 +1,6 @@ package mage.cards.g; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.costs.mana.ManaCost; @@ -22,6 +21,7 @@ import mage.watchers.common.CommanderPlaysCountWatcher; import java.util.HashSet; import java.util.Set; import java.util.UUID; +import mage.ApprovingObject; /** * @author spjspj, JayDi85 @@ -117,7 +117,7 @@ class GeodeGolemEffect extends OneShotEffect { if (commander.getSpellAbility() != null) { game.getState().setValue("PlayFromNotOwnHandZone" + commander.getId(), Boolean.TRUE); Boolean commanderWasCast = controller.cast(controller.chooseAbilityForCast(commander, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + commander.getId(), null); return commanderWasCast; } else { diff --git a/Mage.Sets/src/mage/cards/g/GisaAndGeralf.java b/Mage.Sets/src/mage/cards/g/GisaAndGeralf.java index eb23546083c..53c0cb93148 100644 --- a/Mage.Sets/src/mage/cards/g/GisaAndGeralf.java +++ b/Mage.Sets/src/mage/cards/g/GisaAndGeralf.java @@ -1,27 +1,25 @@ - package mage.cards.g; +import java.util.HashSet; +import java.util.Set; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.AsThoughEffectImpl; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.stack.Spell; -import mage.players.Player; -import mage.target.targetpointer.FixedTarget; import mage.watchers.Watcher; import java.util.UUID; +import mage.MageIdentifier; +import mage.MageObjectReference; +import mage.game.permanent.Permanent; /** * @@ -41,7 +39,9 @@ public final class GisaAndGeralf extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new PutTopCardOfLibraryIntoGraveControllerEffect(4))); // During each of your turns, you may cast a Zombie creature card from your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GisaAndGeralfContinuousEffect()), new GisaAndGeralfWatcher()); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GisaAndGeralfCastFromGraveyardEffect()) + .setIdentifier(MageIdentifier.GisaAndGeralfWatcher), + new GisaAndGeralfWatcher()); } public GisaAndGeralf(final GisaAndGeralf card) { @@ -54,51 +54,11 @@ public final class GisaAndGeralf extends CardImpl { } } -class GisaAndGeralfContinuousEffect extends ContinuousEffectImpl { - - private static final FilterCreatureCard filter = new FilterCreatureCard("Zombie creature card"); - - static { - filter.add(SubType.ZOMBIE.getPredicate()); - } - - GisaAndGeralfContinuousEffect() { - super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit); - staticText = "During each of your turns, you may cast a Zombie creature card from your graveyard"; - } - - GisaAndGeralfContinuousEffect(final GisaAndGeralfContinuousEffect effect) { - super(effect); - } - - @Override - public GisaAndGeralfContinuousEffect copy() { - return new GisaAndGeralfContinuousEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - if (!game.isActivePlayer(player.getId())) { - return false; - } - for (Card card : player.getGraveyard().getCards(filter, game)) { - ContinuousEffect effect = new GisaAndGeralfCastFromGraveyardEffect(); - effect.setTargetPointer(new FixedTarget(card.getId())); - game.addEffect(effect, source); - } - return true; - } - return false; - } -} - class GisaAndGeralfCastFromGraveyardEffect extends AsThoughEffectImpl { GisaAndGeralfCastFromGraveyardEffect() { - super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); - staticText = "You may cast a Zombie creature card from your graveyard"; + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.PutCreatureInPlay); + staticText = "During each of your turns, you may cast a Zombie creature card from your graveyard"; } GisaAndGeralfCastFromGraveyardEffect(final GisaAndGeralfCastFromGraveyardEffect effect) { @@ -117,10 +77,18 @@ class GisaAndGeralfCastFromGraveyardEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (objectId.equals(getTargetPointer().getFirst(game, source))) { - if (affectedControllerId.equals(source.getControllerId())) { - GisaAndGeralfWatcher watcher = game.getState().getWatcher(GisaAndGeralfWatcher.class, source.getSourceId()); - return watcher != null && !watcher.isAbilityUsed(); + if (source.isControlledBy(affectedControllerId) + && Zone.GRAVEYARD.equals(game.getState().getZone(objectId))) { + Card objectCard = game.getCard(objectId); + Permanent sourceObject = game.getPermanent(source.getSourceId()); + if (sourceObject != null && objectCard != null + && objectCard.isOwnedBy(source.getControllerId()) + && objectCard.isCreature() + && objectCard.hasSubtype(SubType.ZOMBIE, game) + && objectCard.getSpellAbility() != null + && objectCard.getSpellAbility().spellCanBeActivatedRegularlyNow(affectedControllerId, game)) { + GisaAndGeralfWatcher watcher = game.getState().getWatcher(GisaAndGeralfWatcher.class); + return watcher != null && !watcher.isAbilityUsed(new MageObjectReference(sourceObject, game)); } } return false; @@ -129,29 +97,27 @@ class GisaAndGeralfCastFromGraveyardEffect extends AsThoughEffectImpl { class GisaAndGeralfWatcher extends Watcher { - private boolean abilityUsed = false; + private final Set usedFrom = new HashSet<>(); GisaAndGeralfWatcher() { - super(WatcherScope.CARD); + super(WatcherScope.GAME); } @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.SPELL_CAST && event.getZone() == Zone.GRAVEYARD) { - Spell spell = (Spell) game.getObject(event.getTargetId()); - if (spell != null && spell.isCreature() && spell.hasSubtype(SubType.ZOMBIE, game)) { - abilityUsed = true; - } + if (GameEvent.EventType.SPELL_CAST.equals(event.getType()) + && event.hasApprovingIdentifier(MageIdentifier.GisaAndGeralfWatcher)) { + usedFrom.add(event.getAdditionalReference().getApprovingMageObjectReference()); } } @Override public void reset() { super.reset(); - abilityUsed = false; + usedFrom.clear(); } - public boolean isAbilityUsed() { - return abilityUsed; + public boolean isAbilityUsed(MageObjectReference mor) { + return usedFrom.contains(mor); } } diff --git a/Mage.Sets/src/mage/cards/g/GoblinDarkDwellers.java b/Mage.Sets/src/mage/cards/g/GoblinDarkDwellers.java index c2fc8f74ee2..dfd2f655d49 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinDarkDwellers.java +++ b/Mage.Sets/src/mage/cards/g/GoblinDarkDwellers.java @@ -1,8 +1,8 @@ package mage.cards.g; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.ContinuousEffect; @@ -93,7 +93,7 @@ class GoblinDarkDwellersEffect extends OneShotEffect { if (controller.chooseUse(Outcome.PlayForFree, "Cast " + card.getLogName() + '?', source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); if (cardWasCast) { ContinuousEffect effect = new GoblinDarkDwellersReplacementEffect(card.getId()); diff --git a/Mage.Sets/src/mage/cards/g/GodEternalKefnet.java b/Mage.Sets/src/mage/cards/g/GodEternalKefnet.java index 626c5868a0c..9e67a2ee035 100644 --- a/Mage.Sets/src/mage/cards/g/GodEternalKefnet.java +++ b/Mage.Sets/src/mage/cards/g/GodEternalKefnet.java @@ -2,8 +2,8 @@ package mage.cards.g; import java.awt.*; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.GodEternalDiesTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -98,7 +98,7 @@ class GodEternalKefnetDrawCardReplacementEffect extends ReplacementEffectImpl { blueprint.addAbility(new SimpleStaticAbility(Zone.ALL, new SpellCostReductionSourceEffect(2))); Card copiedCard = game.copyCard(blueprint, source, source.getControllerId()); you.moveCardToHandWithInfo(copiedCard, source.getSourceId(), game, true); // The copy is created in and cast from your hand. - you.cast(copiedCard.getSpellAbility(), game, false, new MageObjectReference(source.getSourceObject(game), game)); + you.cast(copiedCard.getSpellAbility(), game, false, new ApprovingObject(source, game)); } // draw (return false for default draw) diff --git a/Mage.Sets/src/mage/cards/g/Guile.java b/Mage.Sets/src/mage/cards/g/Guile.java index 6017b3c4795..16f669b335c 100644 --- a/Mage.Sets/src/mage/cards/g/Guile.java +++ b/Mage.Sets/src/mage/cards/g/Guile.java @@ -2,8 +2,8 @@ package mage.cards.g; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.PutIntoGraveFromAnywhereSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -92,7 +92,7 @@ class GuileReplacementEffect extends ReplacementEffectImpl { Card spellCard = spell.getCard(); if (spellCard != null && controller.chooseUse(Outcome.PlayForFree, "Play " + spellCard.getIdName() + " for free?", source, game)) { - controller.playCard(spellCard, game, true, true, new MageObjectReference(source.getSourceObject(game), game)); + controller.playCard(spellCard, game, true, true, new ApprovingObject(source, game)); } return true; } diff --git a/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java b/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java index 1700cae76a8..5c19ca89234 100644 --- a/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java +++ b/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java @@ -1,7 +1,7 @@ package mage.cards.h; import java.util.UUID; -import mage.MageObjectReference; +import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.Effect; @@ -111,7 +111,7 @@ class HarnessTheStormEffect extends OneShotEffect { if (controller.chooseUse(outcome.Benefit, "Cast " + card.getIdName() + " from your graveyard?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(card, game, false), - game, false, new MageObjectReference(source.getSourceObject(game), game)); + game, false, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java b/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java index e698c85ffd2..0c9f7e396d3 100644 --- a/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java +++ b/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java @@ -1,7 +1,6 @@ package mage.cards.h; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DontUntapInControllersUntapStepAllEffect; @@ -17,6 +16,7 @@ import mage.players.Player; import mage.target.TargetCard; import java.util.UUID; +import mage.ApprovingObject; /** * @author ciaccona007 @@ -105,7 +105,7 @@ class HazoretsUndyingFuryEffect extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); cardsToCast.remove(card); if (!cardWasCast) { diff --git a/Mage.Sets/src/mage/cards/h/HellcarverDemon.java b/Mage.Sets/src/mage/cards/h/HellcarverDemon.java index acfda5a8674..91b8406e33e 100644 --- a/Mage.Sets/src/mage/cards/h/HellcarverDemon.java +++ b/Mage.Sets/src/mage/cards/h/HellcarverDemon.java @@ -1,7 +1,6 @@ package mage.cards.h; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -21,6 +20,7 @@ import java.util.HashSet; import java.util.Objects; import java.util.Set; import java.util.UUID; +import mage.ApprovingObject; /** * @author jeffwadsworth & L_J @@ -103,7 +103,7 @@ class HellcarverDemonEffect extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); cardsToCast.remove(card); if (!cardWasCast) { diff --git a/Mage.Sets/src/mage/cards/h/HordeOfNotions.java b/Mage.Sets/src/mage/cards/h/HordeOfNotions.java index 3d3a1c79b45..eef21492995 100644 --- a/Mage.Sets/src/mage/cards/h/HordeOfNotions.java +++ b/Mage.Sets/src/mage/cards/h/HordeOfNotions.java @@ -2,8 +2,8 @@ package mage.cards.h; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -84,7 +84,7 @@ class HordeOfNotionsEffect extends OneShotEffect { if (controller != null) { Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (card != null && controller.chooseUse(outcome, "Play " + card.getName() + " from your graveyard for free?", source, game)) { - controller.playCard(card, game, true, true, new MageObjectReference(source.getSourceObject(game), game)); + controller.playCard(card, game, true, true, new ApprovingObject(source, game)); } return true; } diff --git a/Mage.Sets/src/mage/cards/i/IdolOfEndurance.java b/Mage.Sets/src/mage/cards/i/IdolOfEndurance.java index 7c6b09e686d..baa1d3366da 100644 --- a/Mage.Sets/src/mage/cards/i/IdolOfEndurance.java +++ b/Mage.Sets/src/mage/cards/i/IdolOfEndurance.java @@ -245,7 +245,7 @@ class IdolOfEnduranceWatcher extends Watcher { if (event.getAdditionalReference() == null) { return; } - morMap.computeIfAbsent(event.getAdditionalReference(), m -> new HashMap<>()) + morMap.computeIfAbsent(event.getAdditionalReference().getApprovingMageObjectReference(), m -> new HashMap<>()) .compute(event.getPlayerId(), (u, i) -> i == null ? 0 : Integer.sum(i, -1)); return; } diff --git a/Mage.Sets/src/mage/cards/i/IsochronScepter.java b/Mage.Sets/src/mage/cards/i/IsochronScepter.java index 1cf3f26366e..8e3e5165c11 100644 --- a/Mage.Sets/src/mage/cards/i/IsochronScepter.java +++ b/Mage.Sets/src/mage/cards/i/IsochronScepter.java @@ -1,7 +1,7 @@ package mage.cards.i; import java.util.UUID; -import mage.MageObjectReference; +import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -149,7 +149,7 @@ class IsochronScepterCopyEffect extends OneShotEffect { if (copiedCard.getSpellAbility() != null) { game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(copiedCard, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), null); } else { Logger.getLogger(IsochronScepterCopyEffect.class).error("Isochron Scepter: " diff --git a/Mage.Sets/src/mage/cards/i/IzzetChemister.java b/Mage.Sets/src/mage/cards/i/IzzetChemister.java index f856e6995d6..305aebf1e90 100644 --- a/Mage.Sets/src/mage/cards/i/IzzetChemister.java +++ b/Mage.Sets/src/mage/cards/i/IzzetChemister.java @@ -1,7 +1,6 @@ package mage.cards.i; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; @@ -25,6 +24,7 @@ import mage.target.TargetCard; import mage.target.common.TargetCardInExile; import java.util.UUID; +import mage.ApprovingObject; /** * @author TheElk801 @@ -118,7 +118,7 @@ class IzzetChemisterCastFromExileEffect extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(card, game, true), game, true, - new MageObjectReference(source.getSourceObject(game), game)); + new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); cardsToExile.remove(card); } else { diff --git a/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java b/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java index 39fbb248248..a5fedec4070 100644 --- a/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java +++ b/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java @@ -1,6 +1,5 @@ package mage.cards.j; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; @@ -29,6 +28,7 @@ import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; import java.util.*; +import mage.ApprovingObject; /** * @author LevelX2 @@ -299,7 +299,7 @@ class JaceArchitectOfThoughtEffect3 extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); cardsToChoose.remove(card); if (cardWasCast) { diff --git a/Mage.Sets/src/mage/cards/j/JacesMindseeker.java b/Mage.Sets/src/mage/cards/j/JacesMindseeker.java index cc4e59d68f7..7916767e513 100644 --- a/Mage.Sets/src/mage/cards/j/JacesMindseeker.java +++ b/Mage.Sets/src/mage/cards/j/JacesMindseeker.java @@ -1,7 +1,6 @@ package mage.cards.j; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -20,6 +19,7 @@ import mage.target.common.TargetOpponent; import java.util.Set; import java.util.UUID; +import mage.ApprovingObject; /** * @author LevelX2 @@ -104,7 +104,7 @@ class JaceMindseekerEffect extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java b/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java index 78836b9dcb2..3c4769bc543 100644 --- a/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java +++ b/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java @@ -3,9 +3,9 @@ package mage.cards.j; import java.util.HashMap; import java.util.Map; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -141,7 +141,7 @@ class JelevaNephaliasCastEffect extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); return cardWasCast; } diff --git a/Mage.Sets/src/mage/cards/k/KahoMinamoHistorian.java b/Mage.Sets/src/mage/cards/k/KahoMinamoHistorian.java index 290b015c427..155e21710b3 100644 --- a/Mage.Sets/src/mage/cards/k/KahoMinamoHistorian.java +++ b/Mage.Sets/src/mage/cards/k/KahoMinamoHistorian.java @@ -1,9 +1,9 @@ package mage.cards.k; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -136,7 +136,7 @@ class KahoMinamoHistorianCastEffect extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/k/KaradorGhostChieftain.java b/Mage.Sets/src/mage/cards/k/KaradorGhostChieftain.java index 271ed678260..958ce26958b 100644 --- a/Mage.Sets/src/mage/cards/k/KaradorGhostChieftain.java +++ b/Mage.Sets/src/mage/cards/k/KaradorGhostChieftain.java @@ -3,6 +3,7 @@ package mage.cards.k; import java.util.HashSet; import java.util.Set; import java.util.UUID; +import mage.MageIdentifier; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; @@ -18,7 +19,6 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.game.stack.Spell; import mage.players.Player; import mage.util.CardUtil; import mage.watchers.Watcher; @@ -44,7 +44,7 @@ public final class KaradorGhostChieftain extends CardImpl { // During each of your turns, you may cast one creature card from your graveyard. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new KaradorGhostChieftainCastFromGraveyardEffect()), + new KaradorGhostChieftainCastFromGraveyardEffect()).setIdentifier(MageIdentifier.KaradorGhostChieftainWatcher), new KaradorGhostChieftainWatcher()); } @@ -118,17 +118,16 @@ class KaradorGhostChieftainCastFromGraveyardEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (source.isControlledBy(affectedControllerId) - && Zone.GRAVEYARD.equals(game.getState().getZone(objectId)) - ) { - Card objectCard = game.getCard(objectId); - Permanent sourceObject = game.getPermanent(source.getSourceId()); // needs to be onto the battlefield - if (objectCard != null - && sourceObject != null - && objectCard.isOwnedBy(source.getControllerId()) - && objectCard.isCreature() - && objectCard.getSpellAbility() != null - && objectCard.getSpellAbility().spellCanBeActivatedRegularlyNow(affectedControllerId, game)) { + if (source.isControlledBy(affectedControllerId) + && Zone.GRAVEYARD.equals(game.getState().getZone(objectId))) { + Card objectCard = game.getCard(objectId); + Permanent sourceObject = game.getPermanent(source.getSourceId()); // needs to be onto the battlefield + if (objectCard != null + && sourceObject != null + && objectCard.isOwnedBy(source.getControllerId()) + && objectCard.isCreature() + && objectCard.getSpellAbility() != null + && objectCard.getSpellAbility().spellCanBeActivatedRegularlyNow(affectedControllerId, game)) { KaradorGhostChieftainWatcher watcher = game.getState().getWatcher(KaradorGhostChieftainWatcher.class); return watcher != null @@ -149,15 +148,9 @@ class KaradorGhostChieftainWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.SPELL_CAST - && event.getZone() == Zone.GRAVEYARD) { - Spell spell = (Spell) game.getObject(event.getTargetId()); - if (spell.isCreature()) { - MageObjectReference mor = event.getAdditionalReference(); // permitting source - if (mor != null) { - usedFrom.add(mor); - } - } + if (GameEvent.EventType.SPELL_CAST.equals(event.getType()) + && event.hasApprovingIdentifier(MageIdentifier.KaradorGhostChieftainWatcher)) { + usedFrom.add(event.getAdditionalReference().getApprovingMageObjectReference()); } } diff --git a/Mage.Sets/src/mage/cards/k/KessDissidentMage.java b/Mage.Sets/src/mage/cards/k/KessDissidentMage.java index 2d78ea91ff3..af71d68ec99 100644 --- a/Mage.Sets/src/mage/cards/k/KessDissidentMage.java +++ b/Mage.Sets/src/mage/cards/k/KessDissidentMage.java @@ -5,6 +5,7 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; +import mage.MageIdentifier; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; @@ -51,7 +52,8 @@ public final class KessDissidentMage extends CardImpl { // During each of your turns, you may cast an instant or sorcery card from your graveyard. If a card cast this way would be put into your graveyard this turn, exile it instead. Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, - new KessDissidentMageCastFromGraveyardEffect()); + new KessDissidentMageCastFromGraveyardEffect()) + .setIdentifier(MageIdentifier.KessDissidentMageWatcher); ability.addEffect(new KessDissidentMageReplacementEffect()); this.addAbility(ability, new KessDissidentMageWatcher()); } @@ -164,16 +166,13 @@ class KessDissidentMageWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.SPELL_CAST - && event.getZone() == Zone.GRAVEYARD) { + if (GameEvent.EventType.SPELL_CAST.equals(event.getType()) + && event.hasApprovingIdentifier(MageIdentifier.KessDissidentMageWatcher)) { Spell spell = (Spell) game.getObject(event.getTargetId()); - if (event.getAdditionalReference() != null - && event.getAdditionalReference().getSourceId() != null - && (spell.isInstant() - || spell.isSorcery())) { - allowingObjects.add(event.getAdditionalReference()); + if (spell != null) { + allowingObjects.add(event.getAdditionalReference().getApprovingMageObjectReference()); castSpells.put(new MageObjectReference(spell.getMainCard().getId(), game), - event.getAdditionalReference().getSourceId()); + event.getAdditionalReference().getApprovingAbility().getSourceId()); } } } diff --git a/Mage.Sets/src/mage/cards/k/KnowledgeExploitation.java b/Mage.Sets/src/mage/cards/k/KnowledgeExploitation.java index e4651f7aab5..f7d6a0f853f 100644 --- a/Mage.Sets/src/mage/cards/k/KnowledgeExploitation.java +++ b/Mage.Sets/src/mage/cards/k/KnowledgeExploitation.java @@ -1,7 +1,7 @@ package mage.cards.k; import java.util.UUID; -import mage.MageObjectReference; +import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.ProwlAbility; @@ -77,7 +77,7 @@ class KnowledgeExploitationEffect extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/k/KnowledgePool.java b/Mage.Sets/src/mage/cards/k/KnowledgePool.java index f9278bec371..734a0107b1f 100644 --- a/Mage.Sets/src/mage/cards/k/KnowledgePool.java +++ b/Mage.Sets/src/mage/cards/k/KnowledgePool.java @@ -1,7 +1,6 @@ package mage.cards.k; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -27,6 +26,7 @@ import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; import java.util.UUID; +import mage.ApprovingObject; /** * @author BetaSteward_at_googlemail.com @@ -156,7 +156,7 @@ class KnowledgePoolEffect2 extends OneShotEffect { if (player.choose(Outcome.PlayForFree, game.getExile().getExileZone(exileZoneId), target, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null && !card.getId().equals(spell.getSourceId())) { - player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); + player.cast(card.getSpellAbility(), game, true, new ApprovingObject(source, game)); } } } diff --git a/Mage.Sets/src/mage/cards/l/LeafCrownedElder.java b/Mage.Sets/src/mage/cards/l/LeafCrownedElder.java index 9bac03ab907..b4e9d0d97d2 100644 --- a/Mage.Sets/src/mage/cards/l/LeafCrownedElder.java +++ b/Mage.Sets/src/mage/cards/l/LeafCrownedElder.java @@ -2,8 +2,8 @@ package mage.cards.l; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.abilityword.KinshipAbility; import mage.abilities.effects.OneShotEffect; @@ -63,7 +63,7 @@ class LeafCrownedElderPlayEffect extends OneShotEffect { Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (controller != null && card != null) { if (controller.chooseUse(Outcome.PlayForFree, "Play " + card.getIdName() + " without paying its mana cost?", source, game)) { - controller.playCard(card, game, true, true, new MageObjectReference(source.getSourceObject(game), game)); + controller.playCard(card, game, true, true, new ApprovingObject(source, game)); } return true; } diff --git a/Mage.Sets/src/mage/cards/l/LivingLore.java b/Mage.Sets/src/mage/cards/l/LivingLore.java index 1b568b8e651..8d945dd089a 100644 --- a/Mage.Sets/src/mage/cards/l/LivingLore.java +++ b/Mage.Sets/src/mage/cards/l/LivingLore.java @@ -1,6 +1,7 @@ package mage.cards.l; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; import mage.MageObject; import mage.MageObjectReference; @@ -185,7 +186,7 @@ class LivingLoreSacrificeEffect extends OneShotEffect { if (exiledCard.getSpellAbility().canChooseTarget(game)) { game.getState().setValue("PlayFromNotOwnHandZone" + exiledCard.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(exiledCard, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + exiledCard.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/l/LurrusOfTheDreamDen.java b/Mage.Sets/src/mage/cards/l/LurrusOfTheDreamDen.java index 5500a93a93a..ccbfd976357 100644 --- a/Mage.Sets/src/mage/cards/l/LurrusOfTheDreamDen.java +++ b/Mage.Sets/src/mage/cards/l/LurrusOfTheDreamDen.java @@ -3,14 +3,13 @@ package mage.cards.l; import java.util.HashSet; import java.util.Set; import java.util.UUID; +import mage.MageIdentifier; import mage.MageInt; import mage.MageObject; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.AsThoughEffectImpl; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.keyword.CompanionAbility; import mage.abilities.keyword.CompanionCondition; import mage.abilities.keyword.LifelinkAbility; @@ -18,15 +17,9 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.FilterCard; -import mage.filter.common.FilterPermanentCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.stack.Spell; -import mage.players.Player; -import mage.target.targetpointer.FixedTarget; +import mage.game.permanent.Permanent; import mage.watchers.Watcher; /** @@ -50,9 +43,9 @@ public final class LurrusOfTheDreamDen extends CardImpl { this.addAbility(LifelinkAbility.getInstance()); // During each of your turns, you may cast one permanent spell with converted mana cost 2 or less from your graveyard. - this.addAbility(new SimpleStaticAbility( - new LurrusOfTheDreamDenContinuousEffect() - ), new LurrusOfTheDreamDenWatcher()); + this.addAbility(new SimpleStaticAbility(new LurrusOfTheDreamDenCastFromGraveyardEffect()) + .setIdentifier(MageIdentifier.LurrusOfTheDreamDenWatcher), + new LurrusOfTheDreamDenWatcher()); } private LurrusOfTheDreamDen(final LurrusOfTheDreamDen card) { @@ -83,57 +76,11 @@ enum LurrusOfTheDreamDenCompanionCondition implements CompanionCondition { } } -class LurrusOfTheDreamDenContinuousEffect extends ContinuousEffectImpl { - - private static final FilterCard filter - = new FilterPermanentCard("permanent spell with converted mana cost 2 or less from your graveyard"); - - static { - filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 3)); - filter.add(Predicates.not(CardType.LAND.getPredicate())); - } - - LurrusOfTheDreamDenContinuousEffect() { - super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit); - staticText = "During each of your turns, you may cast one permanent spell " - + "with converted mana cost 2 or less from your graveyard"; - } - - private LurrusOfTheDreamDenContinuousEffect(final LurrusOfTheDreamDenContinuousEffect effect) { - super(effect); - } - - @Override - public LurrusOfTheDreamDenContinuousEffect copy() { - return new LurrusOfTheDreamDenContinuousEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - if (game.isActivePlayer(player.getId())) { - LurrusOfTheDreamDenWatcher watcher = game.getState().getWatcher(LurrusOfTheDreamDenWatcher.class); - if (watcher != null && !watcher.isAbilityUsed(new MageObjectReference(source.getSourceId(), game))) { - // if not used yet, add effect per card in graveyard to cast it - for (Card card : player.getGraveyard().getCards(filter, game)) { - ContinuousEffect effect = new LurrusOfTheDreamDenCastFromGraveyardEffect(); - effect.setTargetPointer(new FixedTarget(card, game)); - game.addEffect(effect, source); - } - } - } - return true; - } -} - class LurrusOfTheDreamDenCastFromGraveyardEffect extends AsThoughEffectImpl { LurrusOfTheDreamDenCastFromGraveyardEffect() { - super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); - staticText = "You may cast one permanent spell with converted mana cost 2 or less from your graveyard"; + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "During each of your turns, you may cast one permanent spell with converted mana cost 2 or less from your graveyard"; } private LurrusOfTheDreamDenCastFromGraveyardEffect(final LurrusOfTheDreamDenCastFromGraveyardEffect effect) { @@ -152,6 +99,22 @@ class LurrusOfTheDreamDenCastFromGraveyardEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + if (source.isControlledBy(affectedControllerId) + && Zone.GRAVEYARD.equals(game.getState().getZone(objectId))) { + Card objectCard = game.getCard(objectId); + Permanent sourceObject = game.getPermanent(source.getSourceId()); + if (sourceObject != null && objectCard != null + && objectCard.isOwnedBy(source.getControllerId()) + && objectCard.getConvertedManaCost() < 3 + && objectCard.getSpellAbility() != null + && objectCard.getSpellAbility().spellCanBeActivatedRegularlyNow(affectedControllerId, game)) { + LurrusOfTheDreamDenWatcher watcher = game.getState().getWatcher(LurrusOfTheDreamDenWatcher.class); + return watcher != null && !watcher.isAbilityUsed(new MageObjectReference(sourceObject, game)); + } + } + + + if (!objectId.equals(getTargetPointer().getFirst(game, source))) { return false; } @@ -165,7 +128,7 @@ class LurrusOfTheDreamDenCastFromGraveyardEffect extends AsThoughEffectImpl { class LurrusOfTheDreamDenWatcher extends Watcher { - private final Set abilityUsed = new HashSet<>(); + private final Set usedFrom = new HashSet<>(); LurrusOfTheDreamDenWatcher() { super(WatcherScope.GAME); @@ -173,25 +136,19 @@ class LurrusOfTheDreamDenWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { - if (event.getType() != GameEvent.EventType.SPELL_CAST - || event.getZone() != Zone.GRAVEYARD - || event.getAdditionalReference() == null) { // permitting source to cast from graveyard - return; - } - Spell spell = game.getSpell(event.getTargetId()); - if (spell == null || !spell.isPermanent() || spell.getConvertedManaCost() > 2) { - return; - } - abilityUsed.add(event.getAdditionalReference()); + if (GameEvent.EventType.SPELL_CAST.equals(event.getType()) + &&event.hasApprovingIdentifier(MageIdentifier.LurrusOfTheDreamDenWatcher)){ + usedFrom.add(event.getAdditionalReference().getApprovingMageObjectReference()); + } } @Override public void reset() { super.reset(); - abilityUsed.clear(); + usedFrom.clear(); } boolean isAbilityUsed(MageObjectReference mor) { - return abilityUsed.contains(mor); + return usedFrom.contains(mor); } } diff --git a/Mage.Sets/src/mage/cards/m/MaelstromArchangel.java b/Mage.Sets/src/mage/cards/m/MaelstromArchangel.java index a02f430b5d1..df77a05410a 100644 --- a/Mage.Sets/src/mage/cards/m/MaelstromArchangel.java +++ b/Mage.Sets/src/mage/cards/m/MaelstromArchangel.java @@ -1,8 +1,8 @@ package mage.cards.m; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -91,7 +91,7 @@ class MaelstromArchangelCastEffect extends OneShotEffect { if (cardToCast != null) { game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(cardToCast, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/m/MasterOfPredicaments.java b/Mage.Sets/src/mage/cards/m/MasterOfPredicaments.java index 8387d6309ee..bf90f616f61 100644 --- a/Mage.Sets/src/mage/cards/m/MasterOfPredicaments.java +++ b/Mage.Sets/src/mage/cards/m/MasterOfPredicaments.java @@ -1,8 +1,8 @@ package mage.cards.m; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -111,7 +111,7 @@ class MasterOfPredicamentsEffect extends OneShotEffect { + " without paying its mana cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + cardFromHand.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(cardFromHand, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + cardFromHand.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/m/MemoryPlunder.java b/Mage.Sets/src/mage/cards/m/MemoryPlunder.java index 8097b7f54ba..52ad3b97767 100644 --- a/Mage.Sets/src/mage/cards/m/MemoryPlunder.java +++ b/Mage.Sets/src/mage/cards/m/MemoryPlunder.java @@ -1,7 +1,7 @@ package mage.cards.m; import java.util.UUID; -import mage.MageObjectReference; +import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -76,7 +76,7 @@ class MemoryPlunderEffect extends OneShotEffect { && controller.chooseUse(Outcome.PlayForFree, "Cast " + card.getName() + " without paying cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); return cardWasCast; } diff --git a/Mage.Sets/src/mage/cards/m/MindclawShaman.java b/Mage.Sets/src/mage/cards/m/MindclawShaman.java index 19681c2aa79..b1eaacf4774 100644 --- a/Mage.Sets/src/mage/cards/m/MindclawShaman.java +++ b/Mage.Sets/src/mage/cards/m/MindclawShaman.java @@ -2,9 +2,9 @@ package mage.cards.m; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -96,7 +96,7 @@ class MindclawShamanEffect extends OneShotEffect { + "paying its mana cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(chosenCard, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), null); } else { game.informPlayers(sourceObject.getLogName() + ": " diff --git a/Mage.Sets/src/mage/cards/m/MindleechMass.java b/Mage.Sets/src/mage/cards/m/MindleechMass.java index 41704f0e832..2a862315130 100644 --- a/Mage.Sets/src/mage/cards/m/MindleechMass.java +++ b/Mage.Sets/src/mage/cards/m/MindleechMass.java @@ -1,8 +1,8 @@ package mage.cards.m; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -85,7 +85,7 @@ class MindleechMassEffect extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/m/MindsDilation.java b/Mage.Sets/src/mage/cards/m/MindsDilation.java index 05f70814924..7bc7b85a994 100644 --- a/Mage.Sets/src/mage/cards/m/MindsDilation.java +++ b/Mage.Sets/src/mage/cards/m/MindsDilation.java @@ -2,8 +2,8 @@ package mage.cards.m; import java.util.List; import java.util.UUID; +import mage.ApprovingObject; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SpellCastOpponentTriggeredAbility; import mage.abilities.effects.Effect; @@ -123,7 +123,7 @@ class MindsDilationEffect extends OneShotEffect { + " without paying its mana cost from exile?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/m/MizzixsMastery.java b/Mage.Sets/src/mage/cards/m/MizzixsMastery.java index a7a03ea0792..698a42758fc 100644 --- a/Mage.Sets/src/mage/cards/m/MizzixsMastery.java +++ b/Mage.Sets/src/mage/cards/m/MizzixsMastery.java @@ -1,6 +1,5 @@ package mage.cards.m; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; @@ -19,6 +18,7 @@ import mage.target.common.TargetCardInYourGraveyard; import java.util.Set; import java.util.UUID; +import mage.ApprovingObject; /** * @author LevelX2 @@ -84,7 +84,7 @@ class MizzixsMasteryEffect extends OneShotEffect { + card.getName() + " without paying its mana cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + cardCopy.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(cardCopy, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + cardCopy.getId(), null); } } @@ -138,7 +138,7 @@ class MizzixsMasteryOverloadEffect extends OneShotEffect { && selectedCard.getSpellAbility().canChooseTarget(game)) { game.getState().setValue("PlayFromNotOwnHandZone" + selectedCard.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(selectedCard, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + selectedCard.getId(), null); } copiedCards.remove(selectedCard); diff --git a/Mage.Sets/src/mage/cards/m/MuldrothaTheGravetide.java b/Mage.Sets/src/mage/cards/m/MuldrothaTheGravetide.java index 67f5a5ff6d6..7cd525cb39c 100644 --- a/Mage.Sets/src/mage/cards/m/MuldrothaTheGravetide.java +++ b/Mage.Sets/src/mage/cards/m/MuldrothaTheGravetide.java @@ -5,6 +5,7 @@ import java.util.EnumSet; import java.util.HashMap; import java.util.Set; import java.util.UUID; +import mage.MageIdentifier; import mage.MageInt; import mage.MageObject; import mage.MageObjectReference; @@ -47,7 +48,9 @@ public final class MuldrothaTheGravetide extends CardImpl { this.toughness = new MageInt(6); // During each of your turns, you may play up to one permanent card of each permanent type from your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MuldrothaTheGravetideCastFromGraveyardEffect()), new MuldrothaTheGravetideWatcher()); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MuldrothaTheGravetideCastFromGraveyardEffect()) + .setIdentifier(MageIdentifier.MuldrothaTheGravetideWatcher), + new MuldrothaTheGravetideWatcher()); } public MuldrothaTheGravetide(final MuldrothaTheGravetide card) { @@ -142,7 +145,9 @@ class MuldrothaTheGravetideWatcher extends Watcher { } private void addPermanentTypes(GameEvent event, Card mageObject, Game game) { - if (mageObject != null && event.getAdditionalReference() != null) { + if (mageObject != null + && event.getAdditionalReference() != null + && MageIdentifier.MuldrothaTheGravetideWatcher.equals(event.getAdditionalReference().getApprovingAbility().getIdentifier())) { UUID playerId = null; if (mageObject instanceof Spell) { playerId = ((Spell) mageObject).getControllerId(); @@ -150,10 +155,10 @@ class MuldrothaTheGravetideWatcher extends Watcher { playerId = ((Permanent) mageObject).getControllerId(); } if (playerId != null) { - Set permanentTypes = sourcePlayedPermanentTypes.get(event.getAdditionalReference()); + Set permanentTypes = sourcePlayedPermanentTypes.get(event.getAdditionalReference().getApprovingMageObjectReference()); if (permanentTypes == null) { permanentTypes = EnumSet.noneOf(CardType.class); - sourcePlayedPermanentTypes.put(event.getAdditionalReference(), permanentTypes); + sourcePlayedPermanentTypes.put(event.getAdditionalReference().getApprovingMageObjectReference(), permanentTypes); } Set typesNotCast = EnumSet.noneOf(CardType.class); for (CardType cardType : mageObject.getCardType()) { diff --git a/Mage.Sets/src/mage/cards/m/MythRealized.java b/Mage.Sets/src/mage/cards/m/MythRealized.java index 5595d6d2bfd..7f0b81d0b60 100644 --- a/Mage.Sets/src/mage/cards/m/MythRealized.java +++ b/Mage.Sets/src/mage/cards/m/MythRealized.java @@ -47,10 +47,10 @@ public final class MythRealized extends CardImpl { // Whenever you cast a noncreature spell, put a lore counter on Myth Realized. this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.LORE.createInstance()), filterNonCreature, false)); - // 2W: Put a lore counter on Myth Realized. + // {2}{W}: Put a lore counter on Myth Realized. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.LORE.createInstance()), new ManaCostsImpl("{2}{W}"))); - // W: Until end of turn, Myth Realized becomes a Monk Avatar creature in addition to its other types and gains "This creature's power and toughness are each equal to the number of lore counters on it." + // {W}: Until end of turn, Myth Realized becomes a Monk Avatar creature in addition to its other types and gains "This creature's power and toughness are each equal to the number of lore counters on it." Effect effect = new BecomesCreatureSourceEffect(new MythRealizedToken(), null, Duration.EndOfTurn); effect.setText("Until end of turn, {this} becomes a Monk Avatar creature in addition to its other types"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{W}")); @@ -83,6 +83,7 @@ class MythRealizedToken extends TokenImpl { super(token); } + @Override public MythRealizedToken copy() { return new MythRealizedToken(this); } diff --git a/Mage.Sets/src/mage/cards/o/OmenMachine.java b/Mage.Sets/src/mage/cards/o/OmenMachine.java index 3f2b705f07c..88fe95ae9ec 100644 --- a/Mage.Sets/src/mage/cards/o/OmenMachine.java +++ b/Mage.Sets/src/mage/cards/o/OmenMachine.java @@ -2,7 +2,7 @@ package mage.cards.o; import java.util.UUID; -import mage.MageObjectReference; +import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.common.BeginningOfDrawTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -101,7 +101,7 @@ class OmenMachineEffect2 extends OneShotEffect { if (card.isLand()) { player.moveCards(card, Zone.BATTLEFIELD, source, game); } else { - player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); + player.cast(card.getSpellAbility(), game, true, new ApprovingObject(source, game)); } } return true; diff --git a/Mage.Sets/src/mage/cards/o/OmnispellAdept.java b/Mage.Sets/src/mage/cards/o/OmnispellAdept.java index 3ad1e6e4010..848da90f57d 100644 --- a/Mage.Sets/src/mage/cards/o/OmnispellAdept.java +++ b/Mage.Sets/src/mage/cards/o/OmnispellAdept.java @@ -1,7 +1,6 @@ package mage.cards.o; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; @@ -23,6 +22,7 @@ import mage.target.Target; import mage.target.common.TargetCardInHand; import java.util.UUID; +import mage.ApprovingObject; /** * @author TheElk801 @@ -103,7 +103,7 @@ class OmnispellAdeptEffect extends OneShotEffect { game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(cardToCast, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), null); if (cardWasCast) { diff --git a/Mage.Sets/src/mage/cards/o/OracleOfBones.java b/Mage.Sets/src/mage/cards/o/OracleOfBones.java index 7b5e809bed0..bfa2860b608 100644 --- a/Mage.Sets/src/mage/cards/o/OracleOfBones.java +++ b/Mage.Sets/src/mage/cards/o/OracleOfBones.java @@ -1,8 +1,8 @@ package mage.cards.o; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -105,7 +105,7 @@ class OracleOfBonesCastEffect extends OneShotEffect { if (cardToCast != null) { game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(cardToCast, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/p/PanopticMirror.java b/Mage.Sets/src/mage/cards/p/PanopticMirror.java index f911ddb64fe..c0f6193e1dc 100644 --- a/Mage.Sets/src/mage/cards/p/PanopticMirror.java +++ b/Mage.Sets/src/mage/cards/p/PanopticMirror.java @@ -1,7 +1,7 @@ package mage.cards.p; import java.util.UUID; -import mage.MageObjectReference; +import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -150,7 +150,7 @@ class PanopticMirrorCastEffect extends OneShotEffect { if (controller.chooseUse(outcome.PlayForFree, "Cast the copied card without paying mana cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + copy.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(copy, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + copy.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/p/PossibilityStorm.java b/Mage.Sets/src/mage/cards/p/PossibilityStorm.java index 134108fb512..2ccaa9c354d 100644 --- a/Mage.Sets/src/mage/cards/p/PossibilityStorm.java +++ b/Mage.Sets/src/mage/cards/p/PossibilityStorm.java @@ -2,8 +2,8 @@ package mage.cards.p; import java.util.ArrayList; import java.util.UUID; +import mage.ApprovingObject; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; @@ -129,7 +129,7 @@ class PossibilityStormEffect extends OneShotEffect { && !card.isLand() && card.getSpellAbility().canChooseTarget(game)) { if (spellController.chooseUse(Outcome.PlayForFree, "Cast " + card.getLogName() + " without paying cost?", source, game)) { - spellController.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); + spellController.cast(card.getSpellAbility(), game, true, new ApprovingObject(source, game)); } } diff --git a/Mage.Sets/src/mage/cards/r/RashmiEternitiesCrafter.java b/Mage.Sets/src/mage/cards/r/RashmiEternitiesCrafter.java index dee8cc46943..c9fd208d8cb 100644 --- a/Mage.Sets/src/mage/cards/r/RashmiEternitiesCrafter.java +++ b/Mage.Sets/src/mage/cards/r/RashmiEternitiesCrafter.java @@ -2,8 +2,8 @@ package mage.cards.r; import java.util.List; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.Effect; @@ -135,7 +135,7 @@ class RashmiEternitiesCrafterEffect extends OneShotEffect { + " without paying its mana cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } if (!cardWasCast) { diff --git a/Mage.Sets/src/mage/cards/r/ReversalOfFortune.java b/Mage.Sets/src/mage/cards/r/ReversalOfFortune.java index 9d681760b72..6b6fdefe2d1 100644 --- a/Mage.Sets/src/mage/cards/r/ReversalOfFortune.java +++ b/Mage.Sets/src/mage/cards/r/ReversalOfFortune.java @@ -1,7 +1,7 @@ package mage.cards.r; import java.util.UUID; -import mage.MageObjectReference; +import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -84,7 +84,7 @@ class ReversalOfFortuneEffect extends OneShotEffect { if (controller.chooseUse(Outcome.PlayForFree, "Cast the copied card without paying mana cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(copiedCard, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), null); } } else { diff --git a/Mage.Sets/src/mage/cards/s/ScholarOfTheLostTrove.java b/Mage.Sets/src/mage/cards/s/ScholarOfTheLostTrove.java index d518ad24f6e..1b6a6e65fee 100644 --- a/Mage.Sets/src/mage/cards/s/ScholarOfTheLostTrove.java +++ b/Mage.Sets/src/mage/cards/s/ScholarOfTheLostTrove.java @@ -1,7 +1,6 @@ package mage.cards.s; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.ContinuousEffect; @@ -22,6 +21,7 @@ import mage.target.common.TargetCardInYourGraveyard; import mage.target.targetpointer.FixedTarget; import java.util.UUID; +import mage.ApprovingObject; /** * @author TheElk801 @@ -97,7 +97,7 @@ class ScholarOfTheLostTroveEffect extends OneShotEffect { } game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); if (!cardWasCast || !card.isInstantOrSorcery()) { return true; diff --git a/Mage.Sets/src/mage/cards/s/ShellOfTheLastKappa.java b/Mage.Sets/src/mage/cards/s/ShellOfTheLastKappa.java index ca9706cca53..b9901b6a0a4 100644 --- a/Mage.Sets/src/mage/cards/s/ShellOfTheLastKappa.java +++ b/Mage.Sets/src/mage/cards/s/ShellOfTheLastKappa.java @@ -1,6 +1,7 @@ package mage.cards.s; import java.util.UUID; +import mage.ApprovingObject; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -147,7 +148,7 @@ class ShellOfTheLastKappaCastEffect extends OneShotEffect { + sourcePermanent.getLogName() + "?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); return cardWasCast; } diff --git a/Mage.Sets/src/mage/cards/s/SilentBladeOni.java b/Mage.Sets/src/mage/cards/s/SilentBladeOni.java index 3857e2a1c17..f6441df1d54 100644 --- a/Mage.Sets/src/mage/cards/s/SilentBladeOni.java +++ b/Mage.Sets/src/mage/cards/s/SilentBladeOni.java @@ -1,7 +1,6 @@ package mage.cards.s; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -18,7 +17,7 @@ import mage.players.Player; import mage.target.TargetCard; import java.util.UUID; -import mage.MageObject; +import mage.ApprovingObject; /** * @author LevelX2 @@ -96,7 +95,7 @@ class SilentBladeOniEffect extends OneShotEffect { } game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); return cardWasCast; } diff --git a/Mage.Sets/src/mage/cards/s/SpellQueller.java b/Mage.Sets/src/mage/cards/s/SpellQueller.java index 4077e32f870..6b50c1bdeff 100644 --- a/Mage.Sets/src/mage/cards/s/SpellQueller.java +++ b/Mage.Sets/src/mage/cards/s/SpellQueller.java @@ -3,9 +3,9 @@ package mage.cards.s; import java.util.Set; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; @@ -141,7 +141,7 @@ class SpellQuellerLeavesEffect extends OneShotEffect { Player cardOwner = game.getPlayer(card.getOwnerId()); if (cardOwner != null) { if (cardOwner.chooseUse(Outcome.PlayForFree, "Cast " + card.getLogName() + " without paying cost?", source, game)) { - cardOwner.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); + cardOwner.cast(card.getSpellAbility(), game, true, new ApprovingObject(source, game)); } } } diff --git a/Mage.Sets/src/mage/cards/s/Spellbinder.java b/Mage.Sets/src/mage/cards/s/Spellbinder.java index a51bbc6c4e4..8341cd79820 100644 --- a/Mage.Sets/src/mage/cards/s/Spellbinder.java +++ b/Mage.Sets/src/mage/cards/s/Spellbinder.java @@ -1,7 +1,7 @@ package mage.cards.s; import java.util.UUID; -import mage.MageObjectReference; +import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -182,7 +182,7 @@ class SpellbinderCopyEffect extends OneShotEffect { if (copiedCard.getSpellAbility() != null) { game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(copiedCard, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), null); } else { Logger.getLogger(SpellbinderCopyEffect.class).error( diff --git a/Mage.Sets/src/mage/cards/s/Spellshift.java b/Mage.Sets/src/mage/cards/s/Spellshift.java index 686b5920930..16452baa47c 100644 --- a/Mage.Sets/src/mage/cards/s/Spellshift.java +++ b/Mage.Sets/src/mage/cards/s/Spellshift.java @@ -2,7 +2,7 @@ package mage.cards.s; import java.util.UUID; -import mage.MageObjectReference; +import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CounterTargetEffect; @@ -78,7 +78,7 @@ class SpellshiftEffect extends OneShotEffect { } spellController.revealCards(source, cardsToReveal, game); if (toCast != null && spellController.chooseUse(outcome, "Cast " + toCast.getLogName() + " without paying its mana cost?", source, game)) { - spellController.cast(toCast.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); + spellController.cast(toCast.getSpellAbility(), game, true, new ApprovingObject(source, game)); } spellController.shuffleLibrary(source, game); return true; diff --git a/Mage.Sets/src/mage/cards/s/Spelltwine.java b/Mage.Sets/src/mage/cards/s/Spelltwine.java index 604f1708667..41a21a87d3b 100644 --- a/Mage.Sets/src/mage/cards/s/Spelltwine.java +++ b/Mage.Sets/src/mage/cards/s/Spelltwine.java @@ -1,6 +1,7 @@ package mage.cards.s; import java.util.UUID; +import mage.ApprovingObject; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -88,14 +89,14 @@ class SpelltwineEffect extends OneShotEffect { controller.moveCards(cardTwo, Zone.EXILED, source, game); } boolean castCardOne = true; - MageObjectReference mor = new MageObjectReference(source.getSourceObject(game), game); + ApprovingObject approvingObject = new ApprovingObject(source, game); if (cardOne != null && controller.chooseUse(Outcome.Neutral, "Cast the copy of " + cardOne.getName() + " first?", source, game)) { Card copyOne = game.copyCard(cardOne, source, controller.getId()); game.getState().setValue("PlayFromNotOwnHandZone" + copyOne.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(copyOne, game, true), - game, true, mor); + game, true, approvingObject); game.getState().setValue("PlayFromNotOwnHandZone" + copyOne.getId(), null); castCardOne = false; } @@ -103,7 +104,7 @@ class SpelltwineEffect extends OneShotEffect { Card copyTwo = game.copyCard(cardTwo, source, controller.getId()); game.getState().setValue("PlayFromNotOwnHandZone" + copyTwo.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(copyTwo, game, true), - game, true, mor); + game, true, approvingObject); game.getState().setValue("PlayFromNotOwnHandZone" + copyTwo.getId(), null); } if (cardOne != null @@ -111,7 +112,7 @@ class SpelltwineEffect extends OneShotEffect { Card copyOne = game.copyCard(cardOne, source, controller.getId()); game.getState().setValue("PlayFromNotOwnHandZone" + copyOne.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(copyOne, game, true), - game, true, mor); + game, true, approvingObject); game.getState().setValue("PlayFromNotOwnHandZone" + copyOne.getId(), null); } return true; diff --git a/Mage.Sets/src/mage/cards/s/SpellweaverHelix.java b/Mage.Sets/src/mage/cards/s/SpellweaverHelix.java index 5eeed09130b..6c110080fff 100644 --- a/Mage.Sets/src/mage/cards/s/SpellweaverHelix.java +++ b/Mage.Sets/src/mage/cards/s/SpellweaverHelix.java @@ -1,6 +1,5 @@ package mage.cards.s; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -23,6 +22,7 @@ import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; import java.util.UUID; +import mage.ApprovingObject; /** * @author emerald000 @@ -191,7 +191,7 @@ class SpellweaverHelixCastEffect extends OneShotEffect { if (controller.chooseUse(Outcome.PlayForFree, "Cast " + copy.getIdName() + " without paying its mana cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + copy.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(copy, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + copy.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/s/SpellweaverVolute.java b/Mage.Sets/src/mage/cards/s/SpellweaverVolute.java index 7f6b4fd2d0a..c55b0db53ec 100644 --- a/Mage.Sets/src/mage/cards/s/SpellweaverVolute.java +++ b/Mage.Sets/src/mage/cards/s/SpellweaverVolute.java @@ -1,7 +1,7 @@ package mage.cards.s; import java.util.UUID; -import mage.MageObjectReference; +import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -96,7 +96,7 @@ class SpellweaverVoluteEffect extends OneShotEffect { if (copiedCard.getSpellAbility() != null) { game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(copiedCard, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), null); } if (controller.moveCards(enchantedCard, Zone.EXILED, source, game)) { diff --git a/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java b/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java index 29862fe3d39..495671ec071 100644 --- a/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java +++ b/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java @@ -1,8 +1,8 @@ package mage.cards.s; import java.util.UUID; +import mage.ApprovingObject; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.Effect; @@ -137,7 +137,7 @@ class SunbirdsInvocationEffect extends OneShotEffect { if (controller.chooseUse(Outcome.Benefit, "Cast " + card.getLogName() + " without paying its mana cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); if (cardWasCast) { cards.remove(card); diff --git a/Mage.Sets/src/mage/cards/s/Sunforger.java b/Mage.Sets/src/mage/cards/s/Sunforger.java index ceab269a141..d072e1d6e95 100644 --- a/Mage.Sets/src/mage/cards/s/Sunforger.java +++ b/Mage.Sets/src/mage/cards/s/Sunforger.java @@ -1,7 +1,7 @@ package mage.cards.s; import java.util.UUID; -import mage.MageObjectReference; +import mage.ApprovingObject; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.SpellAbility; @@ -113,7 +113,7 @@ class SunforgerEffect extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/t/TalentOfTheTelepath.java b/Mage.Sets/src/mage/cards/t/TalentOfTheTelepath.java index c5dffe8989b..0103cb096aa 100644 --- a/Mage.Sets/src/mage/cards/t/TalentOfTheTelepath.java +++ b/Mage.Sets/src/mage/cards/t/TalentOfTheTelepath.java @@ -1,7 +1,6 @@ package mage.cards.t; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.condition.common.SpellMasteryCondition; import mage.abilities.effects.OneShotEffect; @@ -18,6 +17,7 @@ import mage.target.common.TargetOpponent; import java.util.Set; import java.util.UUID; +import mage.ApprovingObject; /** * @author LevelX2 @@ -106,7 +106,7 @@ class TalentOfTheTelepathEffect extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); cardsToCast.remove(card); if (cardWasCast) { diff --git a/Mage.Sets/src/mage/cards/t/ThunderbladeCharge.java b/Mage.Sets/src/mage/cards/t/ThunderbladeCharge.java index 96867d1be13..b898548566b 100644 --- a/Mage.Sets/src/mage/cards/t/ThunderbladeCharge.java +++ b/Mage.Sets/src/mage/cards/t/ThunderbladeCharge.java @@ -1,7 +1,7 @@ package mage.cards.t; import java.util.UUID; -import mage.MageObjectReference; +import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.common.ControlledCreaturesDealCombatDamagePlayerTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -75,7 +75,7 @@ class ThunderbladeChargeCastEffect extends OneShotEffect { && Zone.GRAVEYARD == game.getState().getZone(sourceCard.getId())) { game.getState().setValue("PlayFromNotOwnHandZone" + sourceCard.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(sourceCard, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + sourceCard.getId(), null); return cardWasCast; } diff --git a/Mage.Sets/src/mage/cards/t/TorrentialGearhulk.java b/Mage.Sets/src/mage/cards/t/TorrentialGearhulk.java index 620293fb1b9..cab0783a4aa 100644 --- a/Mage.Sets/src/mage/cards/t/TorrentialGearhulk.java +++ b/Mage.Sets/src/mage/cards/t/TorrentialGearhulk.java @@ -1,8 +1,8 @@ package mage.cards.t; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.ContinuousEffect; @@ -91,7 +91,7 @@ class TorrentialGearhulkEffect extends OneShotEffect { if (controller.chooseUse(outcome, "Cast " + card.getLogName() + '?', source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); if (cardWasCast) { ContinuousEffect effect = new TorrentialGearhulkReplacementEffect(card.getId()); diff --git a/Mage.Sets/src/mage/cards/t/ToshiroUmezawa.java b/Mage.Sets/src/mage/cards/t/ToshiroUmezawa.java index 4cdb286fa20..796dda650dc 100644 --- a/Mage.Sets/src/mage/cards/t/ToshiroUmezawa.java +++ b/Mage.Sets/src/mage/cards/t/ToshiroUmezawa.java @@ -1,8 +1,8 @@ package mage.cards.t; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -94,7 +94,7 @@ class ToshiroUmezawaEffect extends OneShotEffect { && controller.getGraveyard().contains(card.getId())) { // must be in graveyard game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(card, game, false), - game, false, new MageObjectReference(source.getSourceObject(game), game)); + game, false, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); game.addEffect(new ToshiroUmezawaReplacementEffect(card.getId()), source); } diff --git a/Mage.Sets/src/mage/cards/t/TreasureKeeper.java b/Mage.Sets/src/mage/cards/t/TreasureKeeper.java index cd6019caeed..65c7eb293bd 100644 --- a/Mage.Sets/src/mage/cards/t/TreasureKeeper.java +++ b/Mage.Sets/src/mage/cards/t/TreasureKeeper.java @@ -1,7 +1,6 @@ package mage.cards.t; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -16,7 +15,7 @@ import mage.game.Game; import mage.players.Player; import java.util.UUID; -import mage.MageObject; +import mage.ApprovingObject; /** * @author fireshoes @@ -78,7 +77,7 @@ class TreasureKeeperEffect extends OneShotEffect { && controller.chooseUse(Outcome.PlayForFree, "Cast " + nonLandCard.getLogName() + " without paying its mana cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + nonLandCard.getId(), Boolean.TRUE); cardWasCast = controller.cast(controller.chooseAbilityForCast(nonLandCard, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + nonLandCard.getId(), null); if (cardWasCast) { toReveal.remove(nonLandCard); diff --git a/Mage.Sets/src/mage/cards/t/TwinningGlass.java b/Mage.Sets/src/mage/cards/t/TwinningGlass.java index 64d64806033..a89d9321ba4 100644 --- a/Mage.Sets/src/mage/cards/t/TwinningGlass.java +++ b/Mage.Sets/src/mage/cards/t/TwinningGlass.java @@ -1,7 +1,6 @@ package mage.cards.t; import java.util.ArrayList; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; @@ -22,6 +21,7 @@ import mage.watchers.common.SpellsCastWatcher; import java.util.List; import java.util.UUID; import java.util.stream.Collectors; +import mage.ApprovingObject; import mage.filter.common.FilterNonlandCard; import mage.filter.predicate.mageobject.NamePredicate; import mage.target.TargetCard; @@ -108,7 +108,7 @@ class TwinningGlassEffect extends OneShotEffect { + chosenCard.getName() + " without paying its mana cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(chosenCard, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), null); return cardWasCast; } diff --git a/Mage.Sets/src/mage/cards/u/UnexpectedResults.java b/Mage.Sets/src/mage/cards/u/UnexpectedResults.java index 4b8fe86e52f..d507ef08696 100644 --- a/Mage.Sets/src/mage/cards/u/UnexpectedResults.java +++ b/Mage.Sets/src/mage/cards/u/UnexpectedResults.java @@ -1,7 +1,7 @@ package mage.cards.u; import java.util.UUID; -import mage.MageObjectReference; +import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -109,7 +109,7 @@ class UnexpectedResultEffect extends OneShotEffect { + " without paying its mana cost?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); return cardWasCast; } diff --git a/Mage.Sets/src/mage/cards/u/UnpredictableCyclone.java b/Mage.Sets/src/mage/cards/u/UnpredictableCyclone.java index c6cb82b273e..c513f051cb1 100644 --- a/Mage.Sets/src/mage/cards/u/UnpredictableCyclone.java +++ b/Mage.Sets/src/mage/cards/u/UnpredictableCyclone.java @@ -1,6 +1,5 @@ package mage.cards.u; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -17,6 +16,7 @@ import mage.game.stack.StackObject; import mage.players.Player; import java.util.UUID; +import mage.ApprovingObject; /** * @author TheElk801 @@ -91,7 +91,7 @@ class UnpredictableCycloneReplacementEffect extends ReplacementEffectImpl { if (toCast != null && player.chooseUse(outcome, "Cast the exiled card?", source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + toCast.getId(), Boolean.TRUE); Boolean cardWasCast = player.cast(player.chooseAbilityForCast(toCast, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + toCast.getId(), null); if (cardWasCast) { cards.remove(toCast); diff --git a/Mage.Sets/src/mage/cards/v/VillainousWealth.java b/Mage.Sets/src/mage/cards/v/VillainousWealth.java index 8b8366c1860..cb05ed77a4f 100644 --- a/Mage.Sets/src/mage/cards/v/VillainousWealth.java +++ b/Mage.Sets/src/mage/cards/v/VillainousWealth.java @@ -1,7 +1,6 @@ package mage.cards.v; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.*; @@ -19,6 +18,7 @@ import mage.target.common.TargetOpponent; import mage.util.CardUtil; import java.util.UUID; +import mage.ApprovingObject; /** * @author LevelX2 @@ -92,7 +92,7 @@ class VillainousWealthEffect extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); if (cardWasCast) { cardsToExile.remove(card); diff --git a/Mage.Sets/src/mage/cards/w/WildEvocation.java b/Mage.Sets/src/mage/cards/w/WildEvocation.java index b85bb8f9084..7e01b4abd73 100644 --- a/Mage.Sets/src/mage/cards/w/WildEvocation.java +++ b/Mage.Sets/src/mage/cards/w/WildEvocation.java @@ -1,8 +1,8 @@ package mage.cards.w; import java.util.UUID; +import mage.ApprovingObject; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -75,7 +75,7 @@ class WildEvocationEffect extends OneShotEffect { } else if (card.getSpellAbility() != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); player.cast(player.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } else { game.informPlayers(GameLog.getColoredObjectName(card) diff --git a/Mage.Sets/src/mage/cards/w/WildfireDevils.java b/Mage.Sets/src/mage/cards/w/WildfireDevils.java index 61c3c3719dc..a74a17fe54f 100644 --- a/Mage.Sets/src/mage/cards/w/WildfireDevils.java +++ b/Mage.Sets/src/mage/cards/w/WildfireDevils.java @@ -15,6 +15,7 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import java.util.UUID; +import mage.ApprovingObject; import mage.players.PlayerList; import mage.target.common.TargetCardInGraveyard; import mage.util.RandomUtil; @@ -108,7 +109,7 @@ class WildfireDevilsEffect extends OneShotEffect { } game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(copiedCard, game, true), game, true, - new MageObjectReference(source.getSourceObject(game), game)); + new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), null); return cardWasCast; } diff --git a/Mage.Sets/src/mage/cards/w/WildfireEternal.java b/Mage.Sets/src/mage/cards/w/WildfireEternal.java index 295a70471a1..034c708b8fd 100644 --- a/Mage.Sets/src/mage/cards/w/WildfireEternal.java +++ b/Mage.Sets/src/mage/cards/w/WildfireEternal.java @@ -1,8 +1,8 @@ package mage.cards.w; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -83,7 +83,7 @@ class WildfireEternalCastEffect extends OneShotEffect { if (card != null) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } } diff --git a/Mage.Sets/src/mage/cards/w/WordOfCommand.java b/Mage.Sets/src/mage/cards/w/WordOfCommand.java index 8dbd48ff5c6..cc90a8c2959 100644 --- a/Mage.Sets/src/mage/cards/w/WordOfCommand.java +++ b/Mage.Sets/src/mage/cards/w/WordOfCommand.java @@ -1,7 +1,6 @@ package mage.cards.w; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -25,6 +24,7 @@ import mage.target.common.TargetOpponent; import mage.target.targetpointer.FixedTarget; import java.util.UUID; +import mage.ApprovingObject; /** * @author L_J @@ -119,7 +119,7 @@ class WordOfCommandEffect extends OneShotEffect { boolean canPlay = checkPlayability(card, targetPlayer, game, source); while (canPlay && targetPlayer.canRespond() - && !targetPlayer.playCard(card, game, false, true, new MageObjectReference(source.getSourceObject(game), game))) { + && !targetPlayer.playCard(card, game, false, true, new ApprovingObject(source, game))) { SpellAbility spellAbility = card.getSpellAbility(); if (spellAbility != null) { spellAbility.getManaCostsToPay().clear(); diff --git a/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java b/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java index 96e6872fc19..17f7e6cccbc 100644 --- a/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java +++ b/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java @@ -1,8 +1,8 @@ package mage.cards.w; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.OneShotEffect; @@ -141,7 +141,7 @@ class WrexialTheRisenDeepEffect extends OneShotEffect { } game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); game.addEffect(new WrexialReplacementEffect(card.getId()), source); return true; diff --git a/Mage.Sets/src/mage/cards/y/YennettCrypticSovereign.java b/Mage.Sets/src/mage/cards/y/YennettCrypticSovereign.java index 7aa8e4e55fa..ffe1e9160e7 100644 --- a/Mage.Sets/src/mage/cards/y/YennettCrypticSovereign.java +++ b/Mage.Sets/src/mage/cards/y/YennettCrypticSovereign.java @@ -1,8 +1,8 @@ package mage.cards.y; import java.util.UUID; +import mage.ApprovingObject; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -92,7 +92,7 @@ class YennettCrypticSovereignEffect extends OneShotEffect { player.revealCards(source, new CardsImpl(card), game); if (card.getConvertedManaCost() % 2 == 1) { if (player.chooseUse(outcome, "Cast " + card.getLogName() + " without paying its mana cost?", source, game)) { - player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); + player.cast(card.getSpellAbility(), game, true, new ApprovingObject(source, game)); } else { /* 7/13/2018 | If the revealed card doesn’t have an odd converted mana cost or if that card does but you diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/KaradorGhostChieftainTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/KaradorGhostChieftainTest.java index 3c5ab55aad2..216a9d4faf1 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/KaradorGhostChieftainTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/KaradorGhostChieftainTest.java @@ -3,6 +3,7 @@ package org.mage.test.cards.cost.modification; import mage.constants.PhaseStep; import mage.constants.Zone; +import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -61,7 +62,7 @@ public class KaradorGhostChieftainTest extends CardTestPlayerBase { } @Test - public void castCastTwiceFromGraveyard() { + public void castCastMultipleFromGraveyard() { setStrictChooseMode(true); addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); @@ -93,4 +94,51 @@ public class KaradorGhostChieftainTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Karador, Ghost Chieftain", 1); } + + @Test + @Ignore // It's not possible yet to select which ability to use to allow a asThoughtAs effect + public void test_castFromGraveyardWithDifferentApprovers() { + setStrictChooseMode(true); + + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + + // {1}{B}: Target attacking Zombie gains indestructible until end of turn. + addCard(Zone.LIBRARY, playerA, "Accursed Horde", 1); // Creature Zombie {2}{B}{B} + skipInitShuffling(); + + addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 5); + + // Karador, Ghost Chieftain costs {1} less to cast for each creature card in your graveyard. + // During each of your turns, you may cast one creature card from your graveyard. + addCard(Zone.HAND, playerA, "Karador, Ghost Chieftain");// {5}{B}{G}{W} + + // When Gisa and Geralf enters the battlefield, put the top four cards of your library into your graveyard. + // During each of your turns, you may cast a Zombie creature card from your graveyard. + addCard(Zone.HAND, playerA, "Gisa and Geralf"); // CREATURE {2}{U}{B} (4/4) + + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Karador, Ghost Chieftain"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gisa and Geralf"); + + + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Accursed Horde"); + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion"); + + + setStopAt(3, PhaseStep.BEGIN_COMBAT); + execute(); + + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Karador, Ghost Chieftain", 1); + assertPermanentCount(playerA, "Gisa and Geralf", 1); + + assertPermanentCount(playerA, "Silvercoat Lion", 1); + assertPermanentCount(playerA, "Accursed Horde", 1); + } + + } 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 87a259bd185..25f281d8426 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 @@ -2833,15 +2833,15 @@ public class TestPlayer implements Player { } @Override - public boolean cast(SpellAbility ability, Game game, boolean noMana, MageObjectReference reference) { + public boolean cast(SpellAbility ability, Game game, boolean noMana, ApprovingObject approvingObject) { // TestPlayer, ComputerPlayer always call inherited cast() from PlayerImpl // that's why chooseSpellAbilityForCast will be ignored in TestPlayer, see workaround with TestComputerPlayerXXX - return computerPlayer.cast(ability, game, noMana, reference); + return computerPlayer.cast(ability, game, noMana, approvingObject); } @Override - public boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming, MageObjectReference reference) { - return computerPlayer.playCard(card, game, noMana, ignoreTiming, reference); + public boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming, ApprovingObject approvingObject) { + return computerPlayer.playCard(card, game, noMana, ignoreTiming, approvingObject); } @Override diff --git a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java index 0a4dad592d7..0c2f498db4c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java +++ b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java @@ -41,6 +41,7 @@ import mage.target.common.TargetCardInLibrary; import java.io.Serializable; import java.util.*; +import mage.ApprovingObject; import mage.Mana; /** @@ -535,7 +536,7 @@ public class PlayerStub implements Player { } @Override - public boolean cast(SpellAbility ability, Game game, boolean noMana, MageObjectReference reference) { + public boolean cast(SpellAbility ability, Game game, boolean noMana, ApprovingObject approvingObject) { return false; } @@ -599,7 +600,7 @@ public class PlayerStub implements Player { } @Override - public boolean playCard(Card card, Game game, boolean noMana, boolean checkTiming, MageObjectReference reference) { + public boolean playCard(Card card, Game game, boolean noMana, boolean checkTiming, ApprovingObject approvingObject) { return false; } diff --git a/Mage/src/main/java/mage/ApprovingObject.java b/Mage/src/main/java/mage/ApprovingObject.java new file mode 100644 index 00000000000..afc12f332e5 --- /dev/null +++ b/Mage/src/main/java/mage/ApprovingObject.java @@ -0,0 +1,33 @@ +/* + * 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; + +import mage.abilities.Ability; +import mage.game.Game; + +/** + * + * @author LevelX2 + */ +public class ApprovingObject { + + private final Ability approvingAbility; + private final MageObjectReference approvingMageObjectReference; + + public ApprovingObject(Ability source, Game game) { + this.approvingAbility = source; + this.approvingMageObjectReference = new MageObjectReference(source.getSourceId(), game); + } + + public Ability getApprovingAbility() { + return approvingAbility; + } + + public MageObjectReference getApprovingMageObjectReference() { + return approvingMageObjectReference; + } + +} diff --git a/Mage/src/main/java/mage/MageIdentifier.java b/Mage/src/main/java/mage/MageIdentifier.java new file mode 100644 index 00000000000..7a50d469882 --- /dev/null +++ b/Mage/src/main/java/mage/MageIdentifier.java @@ -0,0 +1,15 @@ +package mage; + +/** + * Used to identify specific actions/events and to be able to assign them to the + * correct watcher or other processing. + * + * @author LevelX2 + */ +public enum MageIdentifier { + GisaAndGeralfWatcher, + KaradorGhostChieftainWatcher, + KessDissidentMageWatcher, + LurrusOfTheDreamDenWatcher, + MuldrothaTheGravetideWatcher +} diff --git a/Mage/src/main/java/mage/abilities/Ability.java b/Mage/src/main/java/mage/abilities/Ability.java index 66dd169e6a9..829c1f3c2b3 100644 --- a/Mage/src/main/java/mage/abilities/Ability.java +++ b/Mage/src/main/java/mage/abilities/Ability.java @@ -23,6 +23,7 @@ import mage.watchers.Watcher; import java.io.Serializable; import java.util.List; import java.util.UUID; +import mage.MageIdentifier; import mage.abilities.costs.common.TapSourceCost; /** @@ -550,4 +551,8 @@ public interface Ability extends Controllable, Serializable { * @return */ boolean isSameInstance(Ability ability); + + MageIdentifier getIdentifier(); + + AbilityImpl setIdentifier(MageIdentifier mageIdentifier); } diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index 8defb58adc5..29a18df91ce 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -35,7 +35,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.UUID; -import mage.abilities.costs.common.TapSourceCost; +import mage.MageIdentifier; /** * @author BetaSteward_at_googlemail.com @@ -73,7 +73,8 @@ public abstract class AbilityImpl implements Ability { protected CostAdjuster costAdjuster = null; protected List hints = new ArrayList<>(); protected Outcome customOutcome = null; // uses for AI decisions instead effects - + protected MageIdentifier identifier; // used to identify specific ability (e.g. to match with corresponding watcher) + public AbilityImpl(AbilityType abilityType, Zone zone) { this.id = UUID.randomUUID(); this.originalId = id; @@ -123,6 +124,7 @@ public abstract class AbilityImpl implements Ability { this.hints.add(hint.copy()); } this.customOutcome = ability.customOutcome; + this.identifier = ability.identifier; } @Override @@ -1306,4 +1308,15 @@ public abstract class AbilityImpl implements Ability { || (this.getOriginalId().equals(ability.getOriginalId())) || (this.getClass() == ability.getClass() && this.getRule(true).equals(ability.getRule(true))); } + + @Override + public MageIdentifier getIdentifier() { + return identifier; + } + + @Override + public AbilityImpl setIdentifier(MageIdentifier identifier) { + this.identifier = identifier; + return this; + } } diff --git a/Mage/src/main/java/mage/abilities/ActivatedAbility.java b/Mage/src/main/java/mage/abilities/ActivatedAbility.java index 95e97d2bfd8..a7e79789506 100644 --- a/Mage/src/main/java/mage/abilities/ActivatedAbility.java +++ b/Mage/src/main/java/mage/abilities/ActivatedAbility.java @@ -7,6 +7,7 @@ import mage.constants.TargetController; import mage.game.Game; import java.util.UUID; +import mage.ApprovingObject; /** * @author BetaSteward_at_googlemail.com @@ -16,19 +17,19 @@ public interface ActivatedAbility extends Ability { final class ActivationStatus { private final boolean canActivate; - private final MageObjectReference permittingObject; + private final ApprovingObject approvingObject; - public ActivationStatus(boolean canActivate, MageObjectReference permittingObject) { + public ActivationStatus(boolean canActivate, ApprovingObject approvingObject) { this.canActivate = canActivate; - this.permittingObject = permittingObject; + this.approvingObject = approvingObject; } public boolean canActivate() { return canActivate; } - public MageObjectReference getPermittingObject() { - return permittingObject; + public ApprovingObject getApprovingObject() { + return approvingObject; } public static ActivationStatus getFalse() { @@ -36,12 +37,11 @@ public interface ActivatedAbility extends Ability { } /** - * @param permittingObjectAbility card or permanent that allows to activate current ability + * @param approvingObjectAbility ability that allows to activate/use current ability */ - public static ActivationStatus getTrue(Ability permittingObjectAbility, Game game) { - MageObject object = permittingObjectAbility == null ? null : permittingObjectAbility.getSourceObject(game); - MageObjectReference ref = object == null ? null : new MageObjectReference(object, game); - return new ActivationStatus(true, ref); + public static ActivationStatus getTrue(Ability approvingObjectAbility, Game game) { + ApprovingObject approvingObject = approvingObjectAbility == null ? null : new ApprovingObject(approvingObjectAbility, game); + return new ActivationStatus(true, approvingObject); } } diff --git a/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java b/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java index 4f98229b5b5..dc87003fe5c 100644 --- a/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java @@ -1,7 +1,6 @@ package mage.abilities; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.condition.Condition; import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; @@ -20,6 +19,7 @@ import mage.game.permanent.Permanent; import mage.util.CardUtil; import java.util.UUID; +import mage.ApprovingObject; /** * @author BetaSteward_at_googlemail.com @@ -184,7 +184,7 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa return ActivationStatus.getFalse(); } //20091005 - 602.5d/602.5e - MageObjectReference permittingObject = game.getContinuousEffects() + ApprovingObject approvingObject = game.getContinuousEffects() .asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, @@ -192,11 +192,11 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa game); if (timing == TimingRule.INSTANT || game.canPlaySorcery(playerId) - || null != permittingObject) { + || null != approvingObject) { if (costs.canPay(this, sourceId, playerId, game) && canChooseTarget(game)) { this.activatorId = playerId; - return new ActivationStatus(true, permittingObject); + return new ActivationStatus(true, approvingObject); } } return ActivationStatus.getFalse(); diff --git a/Mage/src/main/java/mage/abilities/PlayLandAbility.java b/Mage/src/main/java/mage/abilities/PlayLandAbility.java index 4fc440012e3..8fa143d8fc9 100644 --- a/Mage/src/main/java/mage/abilities/PlayLandAbility.java +++ b/Mage/src/main/java/mage/abilities/PlayLandAbility.java @@ -1,7 +1,7 @@ package mage.abilities; import java.util.UUID; -import mage.MageObjectReference; +import mage.ApprovingObject; import mage.constants.AbilityType; import mage.constants.AsThoughEffectType; import mage.constants.Zone; @@ -25,15 +25,15 @@ public class PlayLandAbility extends ActivatedAbilityImpl { @Override public ActivationStatus canActivate(UUID playerId, Game game) { - MageObjectReference permittingObject = game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, playerId, game); - if (!controlsAbility(playerId, game) && null == permittingObject) { + ApprovingObject approvingObject = game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, playerId, game); + if (!controlsAbility(playerId, game) && null == approvingObject) { return ActivationStatus.getFalse(); } //20091005 - 114.2a return new ActivationStatus(game.isActivePlayer(playerId) && game.getPlayer(playerId).canPlayLand() && game.canPlaySorcery(playerId), - permittingObject); + approvingObject); } @Override diff --git a/Mage/src/main/java/mage/abilities/SpellAbility.java b/Mage/src/main/java/mage/abilities/SpellAbility.java index d8afd6ef6bc..6ad7cdaf62d 100644 --- a/Mage/src/main/java/mage/abilities/SpellAbility.java +++ b/Mage/src/main/java/mage/abilities/SpellAbility.java @@ -1,7 +1,6 @@ package mage.abilities; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.costs.Cost; import mage.abilities.costs.VariableCost; import mage.abilities.costs.mana.ManaCost; @@ -16,6 +15,7 @@ import mage.players.Player; import java.util.Optional; import java.util.UUID; +import mage.ApprovingObject; /** * @author BetaSteward_at_googlemail.com @@ -82,8 +82,8 @@ public class SpellAbility extends ActivatedAbilityImpl { return ActivationStatus.getFalse(); } // fix for Gitaxian Probe and casting opponent's spells - MageObjectReference permittingSource = game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, playerId, game); - if (permittingSource == null) { + ApprovingObject approvingObject = game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, playerId, game); + if (approvingObject == null) { Card card = game.getCard(sourceId); if (!(card != null && card.isOwnedBy(playerId))) { return ActivationStatus.getFalse(); @@ -118,7 +118,7 @@ public class SpellAbility extends ActivatedAbilityImpl { return ActivationStatus.getFalse(); } else { - return new ActivationStatus(canChooseTarget(game), permittingSource); + return new ActivationStatus(canChooseTarget(game), approvingObject); } } } diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java index 6e85bc4e22c..9e1d89bd8f2 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java @@ -30,6 +30,7 @@ import java.io.Serializable; import java.util.*; import java.util.Map.Entry; import java.util.stream.Collectors; +import mage.ApprovingObject; /** * @author BetaSteward_at_googlemail.com @@ -507,7 +508,7 @@ public class ContinuousEffects implements Serializable { * @return sourceId of the permitting effect if any exists otherwise returns * null */ - public MageObjectReference asThough(UUID objectId, AsThoughEffectType type, Ability affectedAbility, UUID controllerId, Game game) { + public ApprovingObject asThough(UUID objectId, AsThoughEffectType type, Ability affectedAbility, UUID controllerId, Game game) { List asThoughEffectsList = getApplicableAsThoughEffects(type, game); if (!asThoughEffectsList.isEmpty()) { UUID idToCheck; @@ -536,7 +537,7 @@ public class ContinuousEffects implements Serializable { if (affectedAbility == null) { // applies to own ability (one effect can be used in multiple abilities) if (effect.applies(idToCheck, ability, controllerId, game)) { - return new MageObjectReference(ability.getSourceObject(game), game); + return new ApprovingObject(ability, game); } } else { // applies to affected ability @@ -547,7 +548,7 @@ public class ContinuousEffects implements Serializable { } if (effect.applies(idToCheck, affectedAbility, ability, game, controllerId)) { - return new MageObjectReference(ability.getSourceObject(game), game); + return new ApprovingObject(ability, game); } } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java index c51b17ab5c4..b44f1dbddef 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java @@ -2,6 +2,7 @@ package mage.abilities.effects.common; import java.util.Set; +import mage.ApprovingObject; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -73,7 +74,7 @@ public class CastCardFromOutsideTheGameEffect extends OneShotEffect { if (player.choose(Outcome.Benefit, filteredCards, target, game)) { Card card = player.getSideboard().get(target.getFirstTarget(), game); if (card != null) { - player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); + player.cast(card.getSpellAbility(), game, true, new ApprovingObject(source, game)); } } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java index 72b22fc266e..b652ddc203f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java @@ -20,6 +20,7 @@ import mage.target.common.TargetControlledCreaturePermanent; import mage.target.targetpointer.FixedTarget; import java.util.UUID; +import mage.ApprovingObject; /** * FAQ 2013/01/11 @@ -120,7 +121,7 @@ class CipherStoreEffect extends OneShotEffect { SpellAbility ability = copyCard.getSpellAbility(); // remove the cipher effect from the copy ability.getEffects().removeIf(effect -> effect instanceof CipherEffect); - controller.cast(ability, game, true, new MageObjectReference(source.getSourceObject(game), game)); + controller.cast(ability, game, true, new ApprovingObject(source, game)); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/HideawayPlayEffect.java b/Mage/src/main/java/mage/abilities/effects/common/HideawayPlayEffect.java index 82e095daec1..8c44e739525 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/HideawayPlayEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/HideawayPlayEffect.java @@ -13,6 +13,7 @@ import mage.util.CardUtil; import java.util.Set; import java.util.UUID; +import mage.ApprovingObject; /** * @author LevelX2 @@ -67,7 +68,7 @@ public class HideawayPlayEffect extends OneShotEffect { } } - if (!controller.playCard(card, game, true, true, new MageObjectReference(source.getSourceObject(game), game))) { + if (!controller.playCard(card, game, true, true, new ApprovingObject(source, game))) { if (card.getZoneChangeCounter(game) == zcc) { card.setFaceDown(true, game); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/PlayTargetWithoutPayingManaEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PlayTargetWithoutPayingManaEffect.java index 35d3a114f0b..452e375bc46 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PlayTargetWithoutPayingManaEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PlayTargetWithoutPayingManaEffect.java @@ -1,5 +1,6 @@ package mage.abilities.effects.common; +import mage.ApprovingObject; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.Mode; @@ -38,7 +39,7 @@ public class PlayTargetWithoutPayingManaEffect extends OneShotEffect { && target != null) { game.getState().setValue("PlayFromNotOwnHandZone" + target.getId(), Boolean.TRUE); Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(target, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + target.getId(), null); return cardWasCast; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/CastWithoutPayingManaCostEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/CastWithoutPayingManaCostEffect.java index 4c36466ddfb..1e4c79248f7 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/cost/CastWithoutPayingManaCostEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/cost/CastWithoutPayingManaCostEffect.java @@ -1,5 +1,6 @@ package mage.abilities.effects.common.cost; +import mage.ApprovingObject; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; @@ -87,7 +88,7 @@ public class CastWithoutPayingManaCostEffect extends OneShotEffect { if (cardToCast != null) { game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(cardToCast, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), null); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java b/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java index cb51ee3156a..90ea3976bd8 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java @@ -1,5 +1,6 @@ package mage.abilities.keyword; +import mage.ApprovingObject; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; @@ -109,7 +110,7 @@ class CascadeEffect extends OneShotEffect { if (controller.chooseUse(outcome, "Use cascade effect on " + card.getLogName() + '?', source, game)) { game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java b/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java index 91b58c68e9e..cf05bd4fea4 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java @@ -1,7 +1,6 @@ package mage.abilities.keyword; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.StaticAbility; @@ -20,6 +19,7 @@ import mage.game.stack.Spell; import mage.players.Player; import java.util.UUID; +import mage.ApprovingObject; /** * 702.33. Madness @@ -219,7 +219,7 @@ class MadnessCastEffect extends OneShotEffect { castByMadness.setSpellAbilityCastMode(SpellAbilityCastMode.MADNESS); costRef.clear(); costRef.add(madnessCost); - return owner.cast(castByMadness, game, false, new MageObjectReference(source.getSourceObject(game), game)); + return owner.cast(castByMadness, game, false, new ApprovingObject(source, game)); } @Override diff --git a/Mage/src/main/java/mage/abilities/keyword/MiracleAbility.java b/Mage/src/main/java/mage/abilities/keyword/MiracleAbility.java index 99b6ce2b42f..8b40b0b533c 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MiracleAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MiracleAbility.java @@ -1,5 +1,6 @@ package mage.abilities.keyword; +import mage.ApprovingObject; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.SpellAbility; @@ -144,7 +145,7 @@ class MiracleEffect extends OneShotEffect { // replace with the new cost costRef.clear(); costRef.add(miracleCosts); - controller.cast(abilityToCast, game, false, new MageObjectReference(source.getSourceObject(game), game)); + controller.cast(abilityToCast, game, false, new ApprovingObject(source, game)); return true; } return false; diff --git a/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java b/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java index e64e119dd67..049dc6d6938 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java @@ -19,6 +19,7 @@ import mage.game.stack.Spell; import mage.players.Player; import java.util.UUID; +import mage.ApprovingObject; /** * This ability has no effect by default and will always return false on the @@ -189,7 +190,7 @@ class ReboundCastSpellFromExileEffect extends OneShotEffect { && reboundCard != null) { game.getState().setValue("PlayFromNotOwnHandZone" + reboundCard.getId(), Boolean.TRUE); Boolean cardWasCast = player.cast(player.chooseAbilityForCast(reboundCard, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + reboundCard.getId(), null); return cardWasCast; } diff --git a/Mage/src/main/java/mage/abilities/keyword/RippleAbility.java b/Mage/src/main/java/mage/abilities/keyword/RippleAbility.java index 8dbd4b8e92f..7b0a6847701 100644 --- a/Mage/src/main/java/mage/abilities/keyword/RippleAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/RippleAbility.java @@ -1,5 +1,6 @@ package mage.abilities.keyword; +import mage.ApprovingObject; import mage.MageObject; import mage.MageObjectReference; import mage.abilities.Ability; @@ -104,7 +105,7 @@ class RippleEffect extends OneShotEffect { while (player.canRespond() && cards.count(sameNameFilter, game) > 0 && player.choose(Outcome.PlayForFree, cards, target1, game)) { Card card = cards.get(target1.getFirstTarget(), game); if (card != null) { - player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); + player.cast(card.getSpellAbility(), game, true, new ApprovingObject(source, game)); cards.remove(card); } target1.clearChosen(); diff --git a/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java b/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java index df6ca1b3ff9..5d88a299c1b 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java @@ -1,7 +1,6 @@ package mage.abilities.keyword; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.SpecialAction; import mage.abilities.TriggeredAbilityImpl; @@ -27,6 +26,7 @@ import mage.target.targetpointer.FixedTarget; import java.util.ArrayList; import java.util.List; import java.util.UUID; +import mage.ApprovingObject; /** * 502.59. Suspend @@ -369,7 +369,7 @@ class SuspendPlayCardEffect extends OneShotEffect { // cast the card for free game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); Boolean cardWasCast = player.cast(player.chooseAbilityForCast(card, game, true), - game, true, new MageObjectReference(source.getSourceObject(game), game)); + game, true, new ApprovingObject(source, game)); game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); if (cardWasCast) { if (card.isCreature()) { diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java index 24f34599fe5..b0546be8a92 100644 --- a/Mage/src/main/java/mage/cards/CardImpl.java +++ b/Mage/src/main/java/mage/cards/CardImpl.java @@ -971,5 +971,5 @@ public abstract class CardImpl extends MageObjectImpl implements Card { } } return false; - } + } } diff --git a/Mage/src/main/java/mage/game/events/GameEvent.java b/Mage/src/main/java/mage/game/events/GameEvent.java index 24a483f82a6..e5d26b2e924 100644 --- a/Mage/src/main/java/mage/game/events/GameEvent.java +++ b/Mage/src/main/java/mage/game/events/GameEvent.java @@ -1,12 +1,14 @@ package mage.game.events; -import mage.MageObjectReference; + import mage.constants.Zone; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.UUID; +import mage.ApprovingObject; +import mage.MageIdentifier; /** * @author BetaSteward_at_googlemail.com @@ -27,7 +29,7 @@ public class GameEvent implements Serializable { protected String data; protected Zone zone; protected List appliedEffects = new ArrayList<>(); - protected MageObjectReference reference; // e.g. the permitting object for casting a spell from non hand zone + protected ApprovingObject approvingObject; // e.g. the approving object for casting a spell from non hand zone protected UUID customEventType = null; public enum EventType { @@ -359,8 +361,8 @@ public class GameEvent implements Serializable { this(type, null, targetId, sourceId, playerId, 0, false); } - public GameEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId, MageObjectReference reference) { - this(type, null, targetId, sourceId, playerId, 0, false, reference); + public GameEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId, ApprovingObject approvingObject) { + this(type, null, targetId, sourceId, playerId, 0, false, approvingObject); } public GameEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag) { @@ -383,8 +385,8 @@ public class GameEvent implements Serializable { return new GameEvent(type, targetId, sourceId, playerId); } - public static GameEvent getEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId, MageObjectReference reference) { - return new GameEvent(type, targetId, sourceId, playerId, reference); + public static GameEvent getEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId, ApprovingObject approvingObject) { + return new GameEvent(type, targetId, sourceId, playerId, approvingObject); } public static GameEvent getEvent(EventType type, UUID targetId, UUID playerId) { @@ -423,7 +425,7 @@ public class GameEvent implements Serializable { } private GameEvent(EventType type, UUID customEventType, - UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag, MageObjectReference reference) { + UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag, ApprovingObject approvingObject) { this.type = type; this.customEventType = customEventType; this.targetId = targetId; @@ -431,7 +433,7 @@ public class GameEvent implements Serializable { this.amount = amount; this.playerId = playerId; this.flag = flag; - this.reference = reference; + this.approvingObject = approvingObject; } public EventType getType() { @@ -501,12 +503,17 @@ public class GameEvent implements Serializable { this.zone = zone; } - public MageObjectReference getAdditionalReference() { - return reference; + /** + * Returns possibly approving object that allowed the creation of the event. + * + * @return + */ + public ApprovingObject getAdditionalReference() { + return approvingObject; } - public void setAdditionalReference(MageObjectReference additionalReference) { - this.reference = additionalReference; + public void setAdditionalReference(ApprovingObject approvingObject) { + this.approvingObject = approvingObject; } /** @@ -546,4 +553,14 @@ public class GameEvent implements Serializable { } } } + + public boolean hasApprovingIdentifier(MageIdentifier identifier) { + if (approvingObject == null) { + return false; + } + if (identifier == null) { + return false; + } + return identifier.equals(approvingObject.getApprovingAbility().getIdentifier()); + } } diff --git a/Mage/src/main/java/mage/game/stack/StackAbility.java b/Mage/src/main/java/mage/game/stack/StackAbility.java index 1060db5318c..d394c607337 100644 --- a/Mage/src/main/java/mage/game/stack/StackAbility.java +++ b/Mage/src/main/java/mage/game/stack/StackAbility.java @@ -34,6 +34,7 @@ import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import java.util.UUID; +import mage.MageIdentifier; /** * @author BetaSteward_at_googlemail.com @@ -690,4 +691,15 @@ public class StackAbility extends StackObjImpl implements Ability { || (this.getOriginalId().equals(ability.getOriginalId())) || (this.getClass() == ability.getClass() && this.getRule().equals(ability.getRule())); } + + @Override + public MageIdentifier getIdentifier() { + return ability.getIdentifier(); + } + + @Override + public AbilityImpl setIdentifier(MageIdentifier identifier) { + throw new UnsupportedOperationException("Not supported."); + } + } diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index 1da17ef95f0..51249a27bb4 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -2,6 +2,7 @@ package mage.players; import java.io.Serializable; import java.util.*; +import mage.ApprovingObject; import mage.MageItem; import mage.MageObject; import mage.MageObjectReference; @@ -105,9 +106,9 @@ public interface Player extends MageItem, Copyable { /** * Can the player pay life for spells or activated abilities - * + * * @param Ability - * @return + * @return */ boolean canPayLifeCost(Ability Ability); @@ -319,7 +320,7 @@ public interface Player extends MageItem, Copyable { int drawCards(int num, UUID sourceId, Game game, List appliedEffects); - boolean cast(SpellAbility ability, Game game, boolean noMana, MageObjectReference reference); + boolean cast(SpellAbility ability, Game game, boolean noMana, ApprovingObject approvingObject); SpellAbility chooseAbilityForCast(Card card, Game game, boolean noMana); @@ -367,17 +368,17 @@ public interface Player extends MageItem, Copyable { /** * Plays a card if possible * - * @param card the card that can be cast + * @param card the card that can be cast * @param game - * @param noMana if it's a spell i can be cast without paying mana - * @param ignoreTiming if it's cast during the resolution of another spell - * no sorcery or play land timing restriction are - * checked. For a land it has to be the turn of the - * player playing that card. - * @param reference mage object that allows to play the card + * @param noMana if it's a spell i can be cast without paying mana + * @param ignoreTiming if it's cast during the resolution of another + * spell no sorcery or play land timing restriction + * are checked. For a land it has to be the turn of + * the player playing that card. + * @param approvingObject reference to the ability that allows to play the card * @return */ - boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming, MageObjectReference reference); + boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming, ApprovingObject approvingObject); /** * @param card the land card to play @@ -941,13 +942,15 @@ public interface Player extends MageItem, Copyable { /** * Set the mana colors the user can pay with 2 life instead - * @param colors + * + * @param colors */ void addPhyrexianToColors(FilterMana colors); /** * Mana colors the player can pay instead with 2 life - * @return + * + * @return */ FilterMana getPhyrexianColors(); diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 0e36019cb61..a25e83b03f4 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -70,6 +70,7 @@ import java.io.Serializable; import java.util.*; import java.util.Map.Entry; import java.util.stream.Collectors; +import mage.ApprovingObject; public abstract class PlayerImpl implements Player, Serializable { @@ -1136,7 +1137,7 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming, MageObjectReference reference) { + public boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming, ApprovingObject approvingObject) { if (card == null) { return false; } @@ -1144,7 +1145,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (card.isLand()) { result = playLand(card, game, ignoreTiming); } else { - result = cast(card.getSpellAbility(), game, noMana, reference); + result = cast(card.getSpellAbility(), game, noMana, approvingObject); } if (!result) { game.informPlayer(this, "You can't play " + card.getIdName() + '.'); @@ -1156,11 +1157,11 @@ public abstract class PlayerImpl implements Player, Serializable { * @param originalAbility * @param game * @param noMana cast it without paying mana costs - * @param permittingObject which object permitted the cast + * @param approvingObject which object approved the cast * @return */ @Override - public boolean cast(SpellAbility originalAbility, Game game, boolean noMana, MageObjectReference permittingObject) { + public boolean cast(SpellAbility originalAbility, Game game, boolean noMana, ApprovingObject approvingObject) { if (game == null || originalAbility == null) { return false; } @@ -1178,7 +1179,7 @@ public abstract class PlayerImpl implements Player, Serializable { Card card = game.getCard(ability.getSourceId()); if (card != null) { if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, - ability.getId(), ability.getSourceId(), playerId, permittingObject), ability)) { + ability.getId(), ability.getSourceId(), playerId, approvingObject), ability)) { int bookmark = game.bookmarkState(); setStoredBookmark(bookmark); // move global bookmark to current state (if you activated mana before then you can't rollback it) Zone fromZone = game.getState().getZone(card.getMainCard().getId()); @@ -1213,11 +1214,11 @@ public abstract class PlayerImpl implements Player, Serializable { clearCastSourceIdManaCosts(); // TODO: test multiple alternative cost for different cards as same time GameEvent event = GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, - spell.getSpellAbility().getId(), spell.getSpellAbility().getSourceId(), playerId, permittingObject); + spell.getSpellAbility().getId(), spell.getSpellAbility().getSourceId(), playerId, approvingObject); game.fireEvent(event); if (spell.activate(game, noMana)) { event = GameEvent.getEvent(GameEvent.EventType.SPELL_CAST, - spell.getSpellAbility().getId(), spell.getSpellAbility().getSourceId(), playerId, permittingObject); + spell.getSpellAbility().getId(), spell.getSpellAbility().getSourceId(), playerId, approvingObject); event.setZone(fromZone); game.fireEvent(event); if (!game.isSimulation()) { @@ -1281,19 +1282,19 @@ public abstract class PlayerImpl implements Player, Serializable { //20091005 - 305.1 if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, - card.getId(), card.getId(), playerId, activationStatus.getPermittingObject()))) { + card.getId(), card.getId(), playerId, activationStatus.getApprovingObject()))) { // int bookmark = game.bookmarkState(); // land events must return original zone (uses for commander watcher) Zone cardZoneBefore = game.getState().getZone(card.getId()); GameEvent landEventBefore = GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, - card.getId(), card.getId(), playerId, activationStatus.getPermittingObject()); + card.getId(), card.getId(), playerId, activationStatus.getApprovingObject()); landEventBefore.setZone(cardZoneBefore); game.fireEvent(landEventBefore); if (moveCards(card, Zone.BATTLEFIELD, playLandAbility, game, false, false, false, null)) { landsPlayed++; GameEvent landEventAfter = GameEvent.getEvent(GameEvent.EventType.LAND_PLAYED, - card.getId(), card.getId(), playerId, activationStatus.getPermittingObject()); + card.getId(), card.getId(), playerId, activationStatus.getApprovingObject()); landEventAfter.setZone(cardZoneBefore); game.fireEvent(landEventAfter); game.fireInformEvent(getLogName() + " plays " + card.getLogName()); @@ -1439,7 +1440,7 @@ public abstract class PlayerImpl implements Player, Serializable { result = playManaAbility((ActivatedManaAbilityImpl) ability.copy(), game); break; case SPELL: - result = cast((SpellAbility) ability, game, false, activationStatus.getPermittingObject()); + result = cast((SpellAbility) ability, game, false, activationStatus.getApprovingObject()); break; default: result = playAbility(ability.copy(), game); @@ -3145,7 +3146,7 @@ public abstract class PlayerImpl implements Player, Serializable { addPhyrexianLikePayOptions(abilityOptions, availableMana, game); } - MageObjectReference permittingObject = game.getContinuousEffects().asThough(ability.getSourceId(), + ApprovingObject approvingObject = game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_OTHER_MANA, ability, ability.getControllerId(), game); for (Mana mana : abilityOptions) { if (mana.count() == 0) { @@ -3158,7 +3159,7 @@ public abstract class PlayerImpl implements Player, Serializable { // // add tests for non any color like Sunglasses of Urza - if (permittingObject != null && mana.count() <= avail.count()) { + if (approvingObject != null && mana.count() <= avail.count()) { return true; } if (avail instanceof ConditionalMana && !((ConditionalMana) avail).apply(ability, game, getId(), ability.getManaCosts())) { @@ -3427,17 +3428,17 @@ public abstract class PlayerImpl implements Player, Serializable { continue; } - MageObjectReference permittingObject; + ApprovingObject approvingObject; if (isPlaySpell || isPlayLand) { // play hand from non hand zone - permittingObject = game.getContinuousEffects().asThough(object.getId(), + approvingObject = game.getContinuousEffects().asThough(object.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, ability, this.getId(), game); } else { // other abilities from direct zones - permittingObject = null; + approvingObject = null; } - boolean canActivateAsHandZone = permittingObject != null + boolean canActivateAsHandZone = approvingObject != null || (fromZone == Zone.GRAVEYARD && canPlayCardsFromGraveyard()); boolean possibleToPlay = false;