From ec7c8880441c0970915e94c3c9d5e97e5924e80d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 19 Nov 2015 15:52:45 +0100 Subject: [PATCH] Some fixes to put token onto battlefield handling of cards. Some minor reworks. --- .../sets/avacynrestored/ThatcherRevolt.java | 21 ++-- .../battleforzendikar/AkoumStonewaker.java | 17 ++-- .../commander2014/NahiriTheLithomancer.java | 28 +++--- .../mage/sets/commander2015/MirrorMatch.java | 33 ++++--- .../mage/sets/dissension/RakdosGuildmage.java | 24 ++--- .../sets/gatecrash/RapidHybridization.java | 12 +-- .../src/mage/sets/guildpact/Thunderheads.java | 20 ++-- .../sets/innistrad/GeistOfSaintTraft.java | 16 ++-- .../mage/sets/journeyintonyx/BrainMaggot.java | 2 +- .../src/mage/sets/magic2014/AjanisChosen.java | 41 ++++---- .../mage/sets/magic2014/DevoutInvocation.java | 13 +-- Mage.Sets/src/mage/sets/mirage/TidalWave.java | 22 ++--- .../phyrexiavsthecoalition/HornetCannon.java | 28 +++--- .../sets/planechase2012/ErraticExplosion.java | 57 ++++++----- .../mage/sets/prophecy/InfernalGenesis.java | 6 +- .../mage/sets/scourge/DayOfTheDragons.java | 56 ++++++----- .../sets/shadowmoor/ElementalMastery.java | 21 ++-- .../mage/sets/shadowmoor/Giantbaiting.java | 17 ++-- .../mage/sets/worldwake/StoneIdolTrap.java | 22 ++--- .../mage/sets/zendikar/ElementalAppeal.java | 22 ++--- .../sets/zendikar/ZektarShrineExpedition.java | 29 +++--- .../cards/triggers/DayOfTheDragonsTest.java | 96 +++++++++++++++++++ .../triggers/GoldnightCommanderTest.java | 12 +-- .../ReturnFromExileForSourceEffect.java | 2 +- Mage/src/mage/game/Game.java | 2 + Mage/src/mage/game/GameImpl.java | 8 ++ 26 files changed, 356 insertions(+), 271 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/triggers/DayOfTheDragonsTest.java diff --git a/Mage.Sets/src/mage/sets/avacynrestored/ThatcherRevolt.java b/Mage.Sets/src/mage/sets/avacynrestored/ThatcherRevolt.java index c2fc5802c1..3e3518eebd 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/ThatcherRevolt.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/ThatcherRevolt.java @@ -31,7 +31,6 @@ import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.SacrificeTargetEffect; @@ -87,18 +86,14 @@ class ThatcherRevoltEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (int i = 0; i < 3; i++) { - RedHumanToken token = new RedHumanToken(); - token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId()); - Permanent permanent = game.getPermanent(token.getLastAddedToken()); - if (permanent != null) { - SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice this token", source.getControllerId()); - sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game)); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + RedHumanToken token = new RedHumanToken(); + token.putOntoBattlefield(3, game, source.getSourceId(), source.getControllerId()); + for (UUID tokenId : token.getLastAddedTokenIds()) { + Permanent tokenPermanent = game.getPermanent(tokenId); + if (tokenPermanent != null) { + SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect(); + sacrificeEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect), source); } } return true; diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/AkoumStonewaker.java b/Mage.Sets/src/mage/sets/battleforzendikar/AkoumStonewaker.java index 8d17a17c4d..66d3ca61ff 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/AkoumStonewaker.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/AkoumStonewaker.java @@ -30,7 +30,6 @@ package mage.sets.battleforzendikar; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.LandfallAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -44,6 +43,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; import mage.target.targetpointer.FixedTarget; @@ -97,13 +97,14 @@ class AkoumStonewakerEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Token token = new AkoumStonewakerElementalToken(); if (token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId())) { - ExileTargetEffect exileEffect = new ExileTargetEffect(); - exileEffect.setTargetPointer(new FixedTarget(token.getLastAddedToken())); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + for (UUID tokenId : token.getLastAddedTokenIds()) { + Permanent tokenPermanent = game.getPermanent(tokenId); + if (tokenPermanent != null) { + ExileTargetEffect exileEffect = new ExileTargetEffect(); + exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect), source); + } + } return true; } return false; diff --git a/Mage.Sets/src/mage/sets/commander2014/NahiriTheLithomancer.java b/Mage.Sets/src/mage/sets/commander2014/NahiriTheLithomancer.java index eb48023361..0e303f39bc 100644 --- a/Mage.Sets/src/mage/sets/commander2014/NahiriTheLithomancer.java +++ b/Mage.Sets/src/mage/sets/commander2014/NahiriTheLithomancer.java @@ -129,20 +129,22 @@ class NahiriTheLithomancerFirstAbilityEffect extends OneShotEffect { if (controller != null) { Token token = new KorSoldierToken(); if (token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId())) { - Permanent tokenPermanent = game.getPermanent(token.getLastAddedToken()); - if (tokenPermanent != null) { - //TODO: Make sure the Equipment can legally enchant the token, preferably on targetting. - Target target = new TargetControlledPermanent(0, 1, filter, true); - if (target.canChoose(source.getSourceId(), controller.getId(), game) - && controller.chooseUse(outcome, "Attach an Equipment you control to the created Token?", source, game)) { - if (target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), game)) { - Permanent equipmentPermanent = game.getPermanent(target.getFirstTarget()); - if (equipmentPermanent != null) { - Permanent attachedTo = game.getPermanent(equipmentPermanent.getAttachedTo()); - if (attachedTo != null) { - attachedTo.removeAttachment(equipmentPermanent.getId(), game); + for (UUID tokenId : token.getLastAddedTokenIds()) { + Permanent tokenPermanent = game.getPermanent(tokenId); + if (tokenPermanent != null) { + //TODO: Make sure the Equipment can legally enchant the token, preferably on targetting. + Target target = new TargetControlledPermanent(0, 1, filter, true); + if (target.canChoose(source.getSourceId(), controller.getId(), game) + && controller.chooseUse(outcome, "Attach an Equipment you control to the created " + tokenPermanent.getIdName() + "?", source, game)) { + if (target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), game)) { + Permanent equipmentPermanent = game.getPermanent(target.getFirstTarget()); + if (equipmentPermanent != null) { + Permanent attachedTo = game.getPermanent(equipmentPermanent.getAttachedTo()); + if (attachedTo != null) { + attachedTo.removeAttachment(equipmentPermanent.getId(), game); + } + tokenPermanent.addAttachment(equipmentPermanent.getId(), game); } - tokenPermanent.addAttachment(equipmentPermanent.getId(), game); } } } diff --git a/Mage.Sets/src/mage/sets/commander2015/MirrorMatch.java b/Mage.Sets/src/mage/sets/commander2015/MirrorMatch.java index 7ce33e3fc0..dcff7fbe25 100644 --- a/Mage.Sets/src/mage/sets/commander2015/MirrorMatch.java +++ b/Mage.Sets/src/mage/sets/commander2015/MirrorMatch.java @@ -29,7 +29,6 @@ package mage.sets.commander2015; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; @@ -137,25 +136,25 @@ class MirrorMatchEffect extends OneShotEffect { if (controller != null) { for (UUID attackerId : game.getCombat().getAttackers()) { Permanent attacker = game.getPermanent(attackerId); - if (attacker != null) { - if (source.getControllerId().equals(game.getCombat().getDefendingPlayerId(attackerId, game))) { - PutTokenOntoBattlefieldCopyTargetEffect effect = new PutTokenOntoBattlefieldCopyTargetEffect(source.getControllerId(), null, false); - effect.setTargetPointer(new FixedTarget(attacker, game)); - effect.apply(game, source); + if (attacker != null + && source.getControllerId().equals(game.getCombat().getDefendingPlayerId(attackerId, game))) { + PutTokenOntoBattlefieldCopyTargetEffect effect = new PutTokenOntoBattlefieldCopyTargetEffect(source.getControllerId(), null, false); + effect.setTargetPointer(new FixedTarget(attacker, game)); + effect.apply(game, source); + CombatGroup group = game.getCombat().findGroup(attacker.getId()); + boolean isCreature = false; + if (group != null) { for (Permanent addedToken : effect.getAddedPermanent()) { if (addedToken.getCardType().contains(CardType.CREATURE)) { - CombatGroup group = game.getCombat().findGroup(attacker.getId()); - if (group != null) { - group.addBlockerToGroup(addedToken.getId(), attackerId, game); - } + group.addBlockerToGroup(addedToken.getId(), attackerId, game); + isCreature = true; } - ExileTargetEffect sacrificeEffect = new ExileTargetEffect("Exile the token at end of combat"); - sacrificeEffect.setTargetPointer(new FixedTarget(addedToken, game)); - DelayedTriggeredAbility delayedAbility = new AtTheEndOfCombatDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + ExileTargetEffect exileEffect = new ExileTargetEffect("Exile the token at end of combat"); + exileEffect.setTargetPointer(new FixedTarget(addedToken, game)); + game.addDelayedTriggeredAbility(new AtTheEndOfCombatDelayedTriggeredAbility(exileEffect), source); + } + if (isCreature) { + group.pickBlockerOrder(attacker.getControllerId(), game); } } } diff --git a/Mage.Sets/src/mage/sets/dissension/RakdosGuildmage.java b/Mage.Sets/src/mage/sets/dissension/RakdosGuildmage.java index b4a6247fbe..0de01f222a 100644 --- a/Mage.Sets/src/mage/sets/dissension/RakdosGuildmage.java +++ b/Mage.Sets/src/mage/sets/dissension/RakdosGuildmage.java @@ -30,7 +30,6 @@ package mage.sets.dissension; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.costs.common.DiscardCardCost; @@ -46,6 +45,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -66,11 +66,11 @@ public class RakdosGuildmage extends CardImpl { // ({BR} can be paid with either {B} or {R}.) // {3}{B}, Discard a card: Target creature gets -2/-2 until end of turn. - SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(-2,-2, Duration.EndOfTurn), new ManaCostsImpl("{3}{B}")); + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(-2, -2, Duration.EndOfTurn), new ManaCostsImpl("{3}{B}")); ability.addTarget(new TargetCreaturePermanent()); ability.addCost(new DiscardCardCost()); this.addAbility(ability); - + // {3}{R}: Put a 2/1 red Goblin creature token with haste onto the battlefield. Exile it at the beginning of the next end step. SimpleActivatedAbility ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RakdosGuildmageEffect(), new ManaCostsImpl("{3}{R}")); this.addAbility(ability2); @@ -86,7 +86,6 @@ public class RakdosGuildmage extends CardImpl { } } - class RakdosGuildmageEffect extends OneShotEffect { public RakdosGuildmageEffect() { @@ -107,13 +106,14 @@ class RakdosGuildmageEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Token token = new RakdosGuildmageGoblinToken(); if (token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId())) { - ExileTargetEffect exileEffect = new ExileTargetEffect(); - exileEffect.setTargetPointer(new FixedTarget(token.getLastAddedToken())); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + for (UUID tokenId : token.getLastAddedTokenIds()) { + Permanent tokenPermanent = game.getPermanent(tokenId); + if (tokenPermanent != null) { + ExileTargetEffect exileEffect = new ExileTargetEffect(); + exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect), source); + } + } return true; } return false; @@ -131,4 +131,4 @@ class RakdosGuildmageGoblinToken extends Token { toughness = new MageInt(1); this.addAbility(HasteAbility.getInstance()); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/gatecrash/RapidHybridization.java b/Mage.Sets/src/mage/sets/gatecrash/RapidHybridization.java index e78fd5d41f..42d9aa8bbf 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/RapidHybridization.java +++ b/Mage.Sets/src/mage/sets/gatecrash/RapidHybridization.java @@ -29,7 +29,6 @@ package mage.sets.gatecrash; import java.util.UUID; import mage.MageInt; -import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; @@ -52,7 +51,6 @@ public class RapidHybridization extends CardImpl { super(ownerId, 44, "Rapid Hybridization", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{U}"); this.expansionSetCode = "GTC"; - // Destroy target creature. It can't be regenerated. That creature's controller puts a 3/3 green Frog Lizard creature token onto the battlefield. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); @@ -87,7 +85,7 @@ class RapidHybridizationEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) game.getPermanentOrLKIBattlefield(targetPointer.getFirst(game, source)); + Permanent permanent = game.getPermanentOrLKIBattlefield(targetPointer.getFirst(game, source)); if (permanent != null) { RapidHybridizationToken token = new RapidHybridizationToken(); token.putOntoBattlefield(1, game, source.getSourceId(), permanent.getControllerId()); @@ -103,14 +101,14 @@ class RapidHybridizationToken extends Token { super("Frog Lizard", "3/3 green Frog Lizard creature token onto the battlefield"); this.setOriginalExpansionSetCode("GTC"); cardType.add(CardType.CREATURE); - + color.setGreen(true); - + subtype.add("Frog"); subtype.add("Lizard"); - + power = new MageInt(3); toughness = new MageInt(3); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/guildpact/Thunderheads.java b/Mage.Sets/src/mage/sets/guildpact/Thunderheads.java index 41b45a4d2e..4cca565432 100644 --- a/Mage.Sets/src/mage/sets/guildpact/Thunderheads.java +++ b/Mage.Sets/src/mage/sets/guildpact/Thunderheads.java @@ -28,12 +28,9 @@ package mage.sets.guildpact; import java.util.UUID; - import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.keyword.DefenderAbility; @@ -44,6 +41,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; import mage.target.targetpointer.FixedTarget; @@ -93,13 +91,14 @@ class ThunderheadsEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Token token = new WeirdToken(); if (token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId())) { - ExileTargetEffect exileEffect = new ExileTargetEffect(); - exileEffect.setTargetPointer(new FixedTarget(token.getLastAddedToken())); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + for (UUID tokenId : token.getLastAddedTokenIds()) { + Permanent tokenPermanent = game.getPermanent(tokenId); + if (tokenPermanent != null) { + ExileTargetEffect exileEffect = new ExileTargetEffect(); + exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect), source); + } + } return true; } return false; @@ -107,6 +106,7 @@ class ThunderheadsEffect extends OneShotEffect { } class WeirdToken extends Token { + WeirdToken() { super("Weird", "3/3 blue Weird create token with defender and flying"); cardType.add(CardType.CREATURE); diff --git a/Mage.Sets/src/mage/sets/innistrad/GeistOfSaintTraft.java b/Mage.Sets/src/mage/sets/innistrad/GeistOfSaintTraft.java index 121a77b270..ca4bb6e65c 100644 --- a/Mage.Sets/src/mage/sets/innistrad/GeistOfSaintTraft.java +++ b/Mage.Sets/src/mage/sets/innistrad/GeistOfSaintTraft.java @@ -35,14 +35,13 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.keyword.HexproofAbility; import mage.cards.CardImpl; import mage.constants.Outcome; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.AngelToken; import mage.players.Player; import mage.target.targetpointer.FixedTarget; @@ -79,6 +78,7 @@ public class GeistOfSaintTraft extends CardImpl { } class GeistOfSaintTraftEffect extends OneShotEffect { + GeistOfSaintTraftEffect() { super(Outcome.PutCreatureInPlay); staticText = "put a 4/4 white Angel creature token with flying onto the battlefield tapped and attacking. Exile that token at end of combat"; @@ -93,10 +93,14 @@ class GeistOfSaintTraftEffect extends OneShotEffect { AngelToken token = new AngelToken(); Player controller = game.getPlayer(source.getControllerId()); if (controller != null && token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId(), true, true)) { - Effect effect = new ExileTargetEffect(); - effect.setTargetPointer(new FixedTarget(token.getLastAddedToken())); - CreateDelayedTriggeredAbilityEffect createEffect = new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(effect), false); - createEffect.apply(game, source); + for (UUID tokenId : token.getLastAddedTokenIds()) { + Permanent tokenPermanent = game.getPermanent(tokenId); + if (tokenPermanent != null) { + ExileTargetEffect exileEffect = new ExileTargetEffect(); + exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); + game.addDelayedTriggeredAbility(new AtTheEndOfCombatDelayedTriggeredAbility(exileEffect), source); + } + } return true; } return false; diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/BrainMaggot.java b/Mage.Sets/src/mage/sets/journeyintonyx/BrainMaggot.java index 3f758c3321..db20609309 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/BrainMaggot.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/BrainMaggot.java @@ -192,7 +192,7 @@ class BrainMaggotReturnExiledCardEffect extends OneShotEffect { ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter)); Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (exile != null && sourcePermanent != null) { - controller.moveCards(exile, null, Zone.HAND, source, game); + controller.moveCards(exile, Zone.HAND, source, game); return true; } } diff --git a/Mage.Sets/src/mage/sets/magic2014/AjanisChosen.java b/Mage.Sets/src/mage/sets/magic2014/AjanisChosen.java index 1728e7f1f4..fbf9d88f79 100644 --- a/Mage.Sets/src/mage/sets/magic2014/AjanisChosen.java +++ b/Mage.Sets/src/mage/sets/magic2014/AjanisChosen.java @@ -29,7 +29,6 @@ package mage.sets.magic2014; import java.util.UUID; import mage.MageInt; -import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -39,8 +38,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SetTargetPointer; import mage.constants.Zone; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.common.FilterControlledEnchantmentPermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.CatToken; @@ -53,11 +51,6 @@ import mage.players.Player; */ public class AjanisChosen extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent(); - static { - filter.add(new CardTypePredicate(CardType.ENCHANTMENT)); - } - public AjanisChosen(UUID ownerId) { super(ownerId, 2, "Ajani's Chosen", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); this.expansionSetCode = "M14"; @@ -69,7 +62,7 @@ public class AjanisChosen extends CardImpl { // Whenever an enchantment enters the battlefield under your control, put a 2/2 white Cat creature token onto the battlefield. If that enchantment is an Aura, you may attach it to the token. this.addAbility(new EntersBattlefieldAllTriggeredAbility( - Zone.BATTLEFIELD, new AjanisChosenEffect(), filter, false, SetTargetPointer.PERMANENT, + Zone.BATTLEFIELD, new AjanisChosenEffect(), new FilterControlledEnchantmentPermanent(), false, SetTargetPointer.PERMANENT, "Whenever an enchantment enters the battlefield under your control, put a 2/2 white Cat creature token onto the battlefield. If that enchantment is an Aura, you may attach it to the token")); } @@ -85,7 +78,6 @@ public class AjanisChosen extends CardImpl { class AjanisChosenEffect extends OneShotEffect { - public AjanisChosenEffect() { super(Outcome.PutCreatureInPlay); staticText = "put a 2/2 white Cat creature token onto the battlefield. If that enchantment is an Aura, you may attach it to the token"; @@ -102,19 +94,22 @@ class AjanisChosenEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Token token = new CatToken(); - if(token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId())){ - Player player = game.getPlayer(source.getControllerId()); - Permanent enchantement = game.getPermanent(this.getTargetPointer().getFirst(game, source)); - Permanent tokenPermanent = game.getPermanent(token.getLastAddedToken()); - if(player != null && enchantement != null && tokenPermanent != null && enchantement.getSubtype().contains("Aura")) - { - Permanent oldCreature = game.getPermanent(enchantement.getAttachedTo()); - - if(oldCreature != null && enchantement.getSpellAbility().getTargets().get(0).canTarget(tokenPermanent.getId(), game) && player.chooseUse(Outcome.Neutral, "Attach " + enchantement.getName() + " to the token ?", source, game)) - { - if(oldCreature.removeAttachment(enchantement.getId(), game)){ - tokenPermanent.addAttachment(enchantement.getId(), game); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Token token = new CatToken(); + if (token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId())) { + Permanent enchantment = game.getPermanent(this.getTargetPointer().getFirst(game, source)); + if (enchantment != null && enchantment.getSubtype().contains("Aura")) { + for (UUID tokenId : token.getLastAddedTokenIds()) { + Permanent tokenPermanent = game.getPermanent(tokenId); + if (tokenPermanent != null) { + Permanent oldCreature = game.getPermanent(enchantment.getAttachedTo()); + if (oldCreature != null && enchantment.getSpellAbility().getTargets().get(0).canTarget(tokenPermanent.getId(), game) && controller.chooseUse(Outcome.Neutral, "Attach " + enchantment.getName() + " to the token ?", source, game)) { + if (oldCreature.removeAttachment(enchantment.getId(), game)) { + tokenPermanent.addAttachment(enchantment.getId(), game); + } + } + } } } } diff --git a/Mage.Sets/src/mage/sets/magic2014/DevoutInvocation.java b/Mage.Sets/src/mage/sets/magic2014/DevoutInvocation.java index 3f71b0c0a7..9dc699f772 100644 --- a/Mage.Sets/src/mage/sets/magic2014/DevoutInvocation.java +++ b/Mage.Sets/src/mage/sets/magic2014/DevoutInvocation.java @@ -55,10 +55,9 @@ public class DevoutInvocation extends CardImpl { super(ownerId, 16, "Devout Invocation", Rarity.MYTHIC, new CardType[]{CardType.SORCERY}, "{6}{W}"); this.expansionSetCode = "M14"; - // Tap any number of untapped creatures you control. Put a 4/4 white Angel creature token with flying onto the battlefield for each creature tapped this way. this.getSpellAbility().addEffect(new DevoutInvocationEffect()); - + } public DevoutInvocation(final DevoutInvocation card) { @@ -72,9 +71,9 @@ public class DevoutInvocation extends CardImpl { } class DevoutInvocationEffect extends OneShotEffect { - + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); - + static { filter.add(Predicates.not(new TappedPredicate())); } @@ -93,7 +92,7 @@ class DevoutInvocationEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { int tappedAmount = 0; - TargetPermanent target = new TargetPermanent(0,1,filter, false); + TargetPermanent target = new TargetPermanent(0, 1, filter, false); while (true && controller.canRespond()) { target.clearChosen(); if (target.canChoose(source.getControllerId(), game)) { @@ -109,15 +108,13 @@ class DevoutInvocationEffect extends OneShotEffect { } else { break; } - } - else { + } else { break; } } if (tappedAmount > 0) { AngelToken angelToken = new AngelToken(); angelToken.putOntoBattlefield(tappedAmount, game, source.getSourceId(), source.getControllerId()); - game.informPlayers(new StringBuilder(controller.getLogName()).append(" puts ").append(tappedAmount).append(" token").append(tappedAmount != 1 ?"s":"").append(" onto the battlefield").toString()); } return true; } diff --git a/Mage.Sets/src/mage/sets/mirage/TidalWave.java b/Mage.Sets/src/mage/sets/mirage/TidalWave.java index b5c008cc07..e6c61ac286 100644 --- a/Mage.Sets/src/mage/sets/mirage/TidalWave.java +++ b/Mage.Sets/src/mage/sets/mirage/TidalWave.java @@ -28,13 +28,10 @@ package mage.sets.mirage; import java.util.UUID; - import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.SacrificeTargetEffect; import mage.abilities.keyword.DefenderAbility; import mage.cards.CardImpl; @@ -42,6 +39,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; import mage.target.targetpointer.FixedTarget; @@ -89,13 +87,14 @@ class TidalWaveEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Token token = new WallToken(); if (token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId())) { - SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect(); - sacrificeEffect.setTargetPointer(new FixedTarget(token.getLastAddedToken())); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + for (UUID tokenId : token.getLastAddedTokenIds()) { + Permanent tokenPermanent = game.getPermanent(tokenId); + if (tokenPermanent != null) { + SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect(); + sacrificeEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect), source); + } + } return true; } return false; @@ -103,6 +102,7 @@ class TidalWaveEffect extends OneShotEffect { } class WallToken extends Token { + WallToken() { super("Wall", "5/5 blue Wall creature token with defender"); cardType.add(CardType.CREATURE); @@ -112,4 +112,4 @@ class WallToken extends Token { toughness = new MageInt(5); this.addAbility(DefenderAbility.getInstance()); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/phyrexiavsthecoalition/HornetCannon.java b/Mage.Sets/src/mage/sets/phyrexiavsthecoalition/HornetCannon.java index 921db990ae..df761c9c72 100644 --- a/Mage.Sets/src/mage/sets/phyrexiavsthecoalition/HornetCannon.java +++ b/Mage.Sets/src/mage/sets/phyrexiavsthecoalition/HornetCannon.java @@ -29,7 +29,6 @@ package mage.sets.phyrexiavsthecoalition; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.costs.common.TapSourceCost; @@ -42,6 +41,7 @@ import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.HornetToken; import mage.game.permanent.token.Token; import mage.target.targetpointer.FixedTarget; @@ -73,33 +73,33 @@ public class HornetCannon extends CardImpl { } class HornetCannonEffect extends OneShotEffect { - + public HornetCannonEffect() { super(Outcome.PutCreatureInPlay); staticText = "Put a 1/1 colorless Insect artifact creature token with flying and haste named Hornet onto the battlefield. Destroy it at the beginning of the next end step."; } - + public HornetCannonEffect(final HornetCannonEffect effect) { super(effect); } - + @Override public HornetCannonEffect copy() { return new HornetCannonEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Token hornetToken = new HornetToken(); hornetToken.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId()); - - DestroyTargetEffect destroyEffect = new DestroyTargetEffect("destroy the token."); - destroyEffect.setTargetPointer(new FixedTarget(hornetToken.getLastAddedToken())); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(destroyEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + for (UUID tokenId : hornetToken.getLastAddedTokenIds()) { + Permanent tokenPermanent = game.getPermanent(tokenId); + if (tokenPermanent != null) { + DestroyTargetEffect destroyEffect = new DestroyTargetEffect(false); + destroyEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(destroyEffect), source); + } + } return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/planechase2012/ErraticExplosion.java b/Mage.Sets/src/mage/sets/planechase2012/ErraticExplosion.java index 6e7e00f986..702660e5ae 100644 --- a/Mage.Sets/src/mage/sets/planechase2012/ErraticExplosion.java +++ b/Mage.Sets/src/mage/sets/planechase2012/ErraticExplosion.java @@ -28,26 +28,19 @@ package mage.sets.planechase2012; import java.util.UUID; - +import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Library; import mage.players.Player; import mage.target.common.TargetCreatureOrPlayer; -import mage.target.common.TargetCreaturePermanent; -import mage.target.targetpointer.FixedTarget; /** * @@ -78,7 +71,7 @@ class ErraticExplosionEffect extends OneShotEffect { public ErraticExplosionEffect() { super(Outcome.Damage); - this.staticText = "Choose target creature or player. Reveal cards from the top of your library until you reveal a nonland card. Erratic Explosion deals damage equal to that card's converted mana cost to that creature or player. Put the revealed cards on the bottom of your library in any order."; + this.staticText = "Choose target creature or player. Reveal cards from the top of your library until you reveal a nonland card. {this} deals damage equal to that card's converted mana cost to that creature or player. Put the revealed cards on the bottom of your library in any order"; } public ErraticExplosionEffect(ErraticExplosionEffect effect) { @@ -92,32 +85,36 @@ class ErraticExplosionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null && player.getLibrary().size() > 0) { - CardsImpl cards = new CardsImpl(); - Library library = player.getLibrary(); - Card card = null; - do { - card = library.removeFromTop(game); - if (card != null) { - cards.add(card); - } - } while (library.size() > 0 && card != null && card.getCardType().contains(CardType.LAND)); + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller != null && sourceObject != null) { + CardsImpl toReveal = new CardsImpl(); + boolean nonLandFound = false; + Card nonLandCard = null; + + while (nonLandFound && controller.getLibrary().size() > 0) { + nonLandCard = controller.getLibrary().removeFromTop(game); + toReveal.add(nonLandCard); + nonLandFound = nonLandCard.getCardType().contains(CardType.LAND); + } // reveal cards - if (!cards.isEmpty()) { - player.revealCards("Erratic Explosion", cards, game); + if (!toReveal.isEmpty()) { + controller.revealCards(sourceObject.getIdName(), toReveal, game); } // the nonland card - Permanent targetCreature = game.getPermanent(this.getTargetPointer().getFirst(game, source)); - if (targetCreature != null) { - targetCreature.damage(card.getManaCost().convertedManaCost(), source.getSourceId(), game, false, true); - } - Player targetPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); - if (targetPlayer != null) { - targetPlayer.damage(card.getManaCost().convertedManaCost(), source.getSourceId(), game, false, true); + if (nonLandCard != null) { + Permanent targetCreature = game.getPermanent(this.getTargetPointer().getFirst(game, source)); + if (targetCreature != null) { + targetCreature.damage(nonLandCard.getManaCost().convertedManaCost(), source.getSourceId(), game, false, true); + } else { + Player targetPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); + if (targetPlayer != null) { + targetPlayer.damage(nonLandCard.getManaCost().convertedManaCost(), source.getSourceId(), game, false, true); + } + } } // put the cards on the bottom of the library in any order - return player.putCardsOnBottomOfLibrary(cards, game, source, true); + return controller.putCardsOnBottomOfLibrary(toReveal, game, source, true); } return false; } diff --git a/Mage.Sets/src/mage/sets/prophecy/InfernalGenesis.java b/Mage.Sets/src/mage/sets/prophecy/InfernalGenesis.java index 166bde321c..9bcd7e9778 100644 --- a/Mage.Sets/src/mage/sets/prophecy/InfernalGenesis.java +++ b/Mage.Sets/src/mage/sets/prophecy/InfernalGenesis.java @@ -31,7 +31,6 @@ import java.util.UUID; import mage.constants.*; import mage.MageInt; -import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -51,7 +50,6 @@ public class InfernalGenesis extends CardImpl { super(ownerId, 68, "Infernal Genesis", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{B}{B}"); this.expansionSetCode = "PCY"; - // At the beginning of each player's upkeep, that player puts the top card of his or her library into his or her graveyard. Then he or she puts X 1/1 black Minion creature tokens onto the battlefield, where X is that card's converted mana cost. this.addAbility(new BeginningOfUpkeepTriggeredAbility(new InfernalGenesisEffect(), TargetController.ANY, false)); } @@ -81,9 +79,9 @@ class InfernalGenesisEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); if (player != null) { - Card card = player.getLibrary().removeFromTop(game); + Card card = player.getLibrary().getFromTop(game); if (card != null) { - if (player.moveCards(card, Zone.LIBRARY, Zone.GRAVEYARD, source, game)) { + if (player.moveCards(card, Zone.GRAVEYARD, source, game)) { int cmc = card.getManaCost().convertedManaCost(); MinionToken token = new MinionToken(); token.putOntoBattlefield(cmc, game, source.getSourceId(), player.getId()); diff --git a/Mage.Sets/src/mage/sets/scourge/DayOfTheDragons.java b/Mage.Sets/src/mage/sets/scourge/DayOfTheDragons.java index 8ce0107426..3f3303be3c 100644 --- a/Mage.Sets/src/mage/sets/scourge/DayOfTheDragons.java +++ b/Mage.Sets/src/mage/sets/scourge/DayOfTheDragons.java @@ -27,9 +27,10 @@ */ package mage.sets.scourge; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; -import mage.MageInt; -import mage.ObjectColor; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; @@ -48,7 +49,10 @@ import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.ExileZone; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentToken; import mage.game.permanent.token.DragonToken2; +import mage.players.Player; +import mage.util.CardUtil; /** * @@ -60,7 +64,6 @@ public class DayOfTheDragons extends CardImpl { super(ownerId, 31, "Day of the Dragons", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{U}{U}{U}"); this.expansionSetCode = "SCG"; - // When Day of the Dragons enters the battlefield, exile all creatures you control. Then put that many 5/5 red Dragon creature tokens with flying onto the battlefield. this.addAbility(new EntersBattlefieldTriggeredAbility(new DayOfTheDragonsEntersEffect(), false)); @@ -98,18 +101,17 @@ class DayOfTheDragonsEntersEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - UUID exileId = source.getSourceId(); - int creaturesExiled = 0; - if (exileId != null) { - for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { - if (creature != null) { - if (creature.moveToExile(exileId, "Day of the Dragons", source.getSourceId(), game)) { - creaturesExiled++; - } - } + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller != null && sourceObject != null) { + Set toExile = new HashSet<>(); + toExile.addAll(game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)); + if (!toExile.isEmpty()) { + UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); + controller.moveCardsToExile(toExile, source, game, true, exileId, sourceObject.getIdName()); + DragonToken2 token = new DragonToken2(); + token.putOntoBattlefield(toExile.size(), game, source.getSourceId(), source.getControllerId()); } - DragonToken2 token = new DragonToken2(); - token.putOntoBattlefield(creaturesExiled, game, source.getSourceId(), source.getControllerId()); return true; } return false; @@ -141,20 +143,22 @@ class DayOfTheDragonsLeavesEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - UUID exileId = source.getSourceId(); - for (Permanent dragon : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { - if (dragon != null) { - dragon.sacrifice(source.getSourceId(), game); + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller != null) { + for (Permanent dragon : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { + if (dragon != null) { + dragon.sacrifice(source.getSourceId(), game); + } } - } - ExileZone exile = game.getExile().getExileZone(exileId); - if (exile != null) { - exile = exile.copy(); - for (UUID cardId : exile) { - Card card = game.getCard(cardId); - card.putOntoBattlefield(game, Zone.EXILED, source.getSourceId(), source.getControllerId()); + int zoneChangeCounter = source.getSourceObjectZoneChangeCounter(); + if (zoneChangeCounter > 0 && !(sourceObject instanceof PermanentToken)) { + zoneChangeCounter--; + } + ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter)); + if (exile != null) { + controller.moveCards(exile, Zone.BATTLEFIELD, source, game); } - game.getExile().getExileZone(exileId).clear(); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/shadowmoor/ElementalMastery.java b/Mage.Sets/src/mage/sets/shadowmoor/ElementalMastery.java index 7d06f99630..13c125f5bf 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/ElementalMastery.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/ElementalMastery.java @@ -30,7 +30,6 @@ package mage.sets.shadowmoor; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; @@ -65,7 +64,6 @@ public class ElementalMastery extends CardImpl { this.expansionSetCode = "SHM"; this.subtype.add("Aura"); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); @@ -110,16 +108,17 @@ class ElementalMasteryEffect extends OneShotEffect { Permanent creatureAttached = game.getPermanent(source.getSourceId()); if (creatureAttached != null) { int power = creatureAttached.getPower().getValue(); - for (int i = 0; i < power; i++) { + if (power > 0) { ElementalToken token = new ElementalToken(); - token.putOntoBattlefield(1, game, creatureAttached.getId(), creatureAttached.getControllerId()); - ExileTargetEffect exileEffect = new ExileTargetEffect("exile the token"); - exileEffect.setTargetPointer(new FixedTarget(token.getLastAddedToken())); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + token.putOntoBattlefield(power, game, creatureAttached.getId(), creatureAttached.getControllerId()); + for (UUID tokenId : token.getLastAddedTokenIds()) { + Permanent tokenPermanent = game.getPermanent(tokenId); + if (tokenPermanent != null) { + ExileTargetEffect exileEffect = new ExileTargetEffect(); + exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect), source); + } + } } return true; } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/Giantbaiting.java b/Mage.Sets/src/mage/sets/shadowmoor/Giantbaiting.java index 146c80a3a3..38482fdf37 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/Giantbaiting.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/Giantbaiting.java @@ -30,7 +30,6 @@ package mage.sets.shadowmoor; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTargetEffect; @@ -41,6 +40,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; import mage.target.targetpointer.FixedTarget; @@ -92,13 +92,14 @@ class GiantbaitingEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Token token = new GiantWarriorToken(); if (token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId())) { - ExileTargetEffect exileEffect = new ExileTargetEffect(); - exileEffect.setTargetPointer(new FixedTarget(token.getLastAddedToken())); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); + for (UUID tokenId : token.getLastAddedTokenIds()) { + Permanent tokenPermanent = game.getPermanent(tokenId); + if (tokenPermanent != null) { + ExileTargetEffect exileEffect = new ExileTargetEffect(); + exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect), source); + } + } return true; } return false; diff --git a/Mage.Sets/src/mage/sets/worldwake/StoneIdolTrap.java b/Mage.Sets/src/mage/sets/worldwake/StoneIdolTrap.java index 2bab309e9c..d6f1d3c739 100644 --- a/Mage.Sets/src/mage/sets/worldwake/StoneIdolTrap.java +++ b/Mage.Sets/src/mage/sets/worldwake/StoneIdolTrap.java @@ -30,7 +30,6 @@ package mage.sets.worldwake; import mage.constants.*; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; @@ -47,6 +46,7 @@ import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; import java.util.UUID; +import mage.game.permanent.Permanent; /** * @@ -54,7 +54,6 @@ import java.util.UUID; */ public class StoneIdolTrap extends CardImpl { - public StoneIdolTrap(UUID ownerId) { super(ownerId, 93, "Stone Idol Trap", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{5}{R}"); this.expansionSetCode = "WWK"; @@ -86,6 +85,7 @@ class StoneIdolTrapCostReductionEffect extends CostModificationEffectImpl { static { filter.add(new AttackingPredicate()); } + public StoneIdolTrapCostReductionEffect() { super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST); staticText = "{this} costs {1} less to cast for each attacking creature"; @@ -97,7 +97,7 @@ class StoneIdolTrapCostReductionEffect extends CostModificationEffectImpl { @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { - int reductionAmount = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(),game); + int reductionAmount = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); CardUtil.reduceCost(abilityToModify, reductionAmount); return true; } @@ -136,14 +136,14 @@ class StoneIdolTrapEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { StoneTrapIdolToken token = new StoneTrapIdolToken(); token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId()); - ExileTargetEffect exileEffect = new ExileTargetEffect("exile the token"); - exileEffect.setTargetPointer(new FixedTarget(token.getLastAddedToken())); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect, TargetController.YOU); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); - + for (UUID tokenId : token.getLastAddedTokenIds()) { + Permanent tokenPermanent = game.getPermanent(tokenId); + if (tokenPermanent != null) { + ExileTargetEffect exileEffect = new ExileTargetEffect(); + exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect), source); + } + } return true; } } diff --git a/Mage.Sets/src/mage/sets/zendikar/ElementalAppeal.java b/Mage.Sets/src/mage/sets/zendikar/ElementalAppeal.java index dbe2952eb5..78c175f96c 100644 --- a/Mage.Sets/src/mage/sets/zendikar/ElementalAppeal.java +++ b/Mage.Sets/src/mage/sets/zendikar/ElementalAppeal.java @@ -33,7 +33,6 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.condition.LockedInCondition; import mage.abilities.condition.common.KickedCondition; @@ -44,6 +43,7 @@ import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; /** @@ -56,7 +56,6 @@ public class ElementalAppeal extends CardImpl { super(ownerId, 123, "Elemental Appeal", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{R}{R}{R}{R}"); this.expansionSetCode = "ZEN"; - // Kicker {5} this.addAbility(new KickerAbility("{5}")); @@ -100,17 +99,14 @@ class ElementalAppealEffect extends OneShotEffect { ElementalToken token = new ElementalToken(); token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId()); - FixedTarget fixedTarget = new FixedTarget(token.getLastAddedToken()); - source.getEffects().get(1).setTargetPointer(fixedTarget); - - ExileTargetEffect exileEffect = new ExileTargetEffect(); - exileEffect.setTargetPointer(fixedTarget); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); - + for (UUID tokenId : token.getLastAddedTokenIds()) { + Permanent tokenPermanent = game.getPermanent(tokenId); + if (tokenPermanent != null) { + ExileTargetEffect exileEffect = new ExileTargetEffect(); + exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect), source); + } + } return true; } } diff --git a/Mage.Sets/src/mage/sets/zendikar/ZektarShrineExpedition.java b/Mage.Sets/src/mage/sets/zendikar/ZektarShrineExpedition.java index a6d09201a6..8bc084c9f7 100644 --- a/Mage.Sets/src/mage/sets/zendikar/ZektarShrineExpedition.java +++ b/Mage.Sets/src/mage/sets/zendikar/ZektarShrineExpedition.java @@ -28,14 +28,8 @@ package mage.sets.zendikar; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; -import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.LandfallAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; @@ -47,8 +41,13 @@ import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; import mage.target.targetpointer.FixedTarget; @@ -62,7 +61,6 @@ public class ZektarShrineExpedition extends CardImpl { super(ownerId, 155, "Zektar Shrine Expedition", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); this.expansionSetCode = "ZEN"; - // Landfall - Whenever a land enters the battlefield under your control, you may put a quest counter on Zektar Shrine Expedition. this.addAbility(new LandfallAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.QUEST.createInstance()), true)); // Remove three quest counters from Zektar Shrine Expedition and sacrifice it: Put a 7/1 red Elemental creature token with trample and haste onto the battlefield. Exile it at the beginning of the next end step. @@ -101,15 +99,14 @@ class ZektarShrineExpeditionEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { ElementalToken token = new ElementalToken(); token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId()); - - ExileTargetEffect exileEffect = new ExileTargetEffect(); - exileEffect.setTargetPointer(new FixedTarget(token.getLastAddedToken())); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - game.addDelayedTriggeredAbility(delayedAbility); - + for (UUID tokenId : token.getLastAddedTokenIds()) { + Permanent tokenPermanent = game.getPermanent(tokenId); + if (tokenPermanent != null) { + ExileTargetEffect exileEffect = new ExileTargetEffect(); + exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect), source); + } + } return true; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/DayOfTheDragonsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/DayOfTheDragonsTest.java new file mode 100644 index 0000000000..467f540a78 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/DayOfTheDragonsTest.java @@ -0,0 +1,96 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.triggers; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class DayOfTheDragonsTest extends CardTestPlayerBase { + + @Test + public void TestTokensAreCreated() { + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); + addCard(Zone.BATTLEFIELD, playerA, "Pillarfield Ox", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 7); + // When Day of the Dragons enters the battlefield, exile all creatures you control. Then put that many 5/5 red Dragon creature tokens with flying onto the battlefield. + // When Day of the Dragons leaves the battlefield, sacrifice all Dragons you control. Then return the exiled cards to the battlefield under your control. + addCard(Zone.HAND, playerA, "Day of the Dragons"); // Enchantment - {4}{U}{U}{U} + + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + addCard(Zone.BATTLEFIELD, playerB, "Shivan Dragon"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Day of the Dragons"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertExileCount("Silvercoat Lion", 1); + assertExileCount("Pillarfield Ox", 1); + assertPermanentCount(playerA, "Dragon", 2); + + assertPermanentCount(playerB, "Silvercoat Lion", 1); + assertPermanentCount(playerB, "Shivan Dragon", 1); + } + + @Test + public void TestTokensAreCreatedAndExiled() { + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); + addCard(Zone.BATTLEFIELD, playerA, "Pillarfield Ox", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 7); + // When Day of the Dragons enters the battlefield, exile all creatures you control. Then put that many 5/5 red Dragon creature tokens with flying onto the battlefield. + // When Day of the Dragons leaves the battlefield, sacrifice all Dragons you control. Then return the exiled cards to the battlefield under your control. + addCard(Zone.HAND, playerA, "Day of the Dragons"); // Enchantment - {4}{U}{U}{U} + + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + addCard(Zone.BATTLEFIELD, playerB, "Shivan Dragon"); + addCard(Zone.BATTLEFIELD, playerB, "Plains", 2); + addCard(Zone.HAND, playerB, "Disenchant"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Day of the Dragons"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Disenchant", "Day of the Dragons"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerA, "Day of the Dragons", 1); + assertGraveyardCount(playerB, "Disenchant", 1); + + assertPermanentCount(playerA, "Silvercoat Lion", 1); + assertPermanentCount(playerA, "Pillarfield Ox", 1); + assertPermanentCount(playerA, "Dragon", 0); + + assertPermanentCount(playerB, "Silvercoat Lion", 1); + assertPermanentCount(playerB, "Shivan Dragon", 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GoldnightCommanderTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GoldnightCommanderTest.java index 6da6f33709..acdced5c75 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GoldnightCommanderTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GoldnightCommanderTest.java @@ -37,20 +37,16 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * * @author LevelX2 */ - public class GoldnightCommanderTest extends CardTestPlayerBase { - /** - * Goldnight Commander {3}{W} - * Human Cleric Soldier - * Whenever another creature enters the battlefield under your control, creatures you control get +1/+1 until end of turn. - * - + /* + * Goldnight Commander {3}{W} Human Cleric Soldier + * Whenever another creature enters the battlefield under your control, creatures you control get + * +1/+1 until end of turn. */ @Test public void testThreeCreaturesEnterAtTheSameTime() { // The ability of the Commander triggers three times and each trigger sees all three creatures - addCard(Zone.HAND, playerA, "Thatcher Revolt"); addCard(Zone.BATTLEFIELD, playerA, "Goldnight Commander", 1); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); diff --git a/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java b/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java index 1276b0acdf..beefcf4ca7 100644 --- a/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java @@ -104,7 +104,7 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect { if (returnToZone.equals(Zone.BATTLEFIELD)) { controller.moveCards(exile.getCards(game), returnToZone, source, game, false, false, true, null); } else { - controller.moveCards(exile, null, returnToZone, source, game); + controller.moveCards(exile, returnToZone, source, game); } } return true; diff --git a/Mage/src/mage/game/Game.java b/Mage/src/mage/game/Game.java index fb2244bfaa..3e44fb3657 100644 --- a/Mage/src/mage/game/Game.java +++ b/Mage/src/mage/game/Game.java @@ -385,6 +385,8 @@ public interface Game extends MageItem, Serializable { UUID addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility); + UUID addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility, Ability source); + void applyEffects(); boolean checkStateAndTriggered(); diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index 16c0b614e7..d950276633 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -1490,6 +1490,14 @@ public abstract class GameImpl implements Game, Serializable { } } + @Override + public UUID addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility, Ability source) { + delayedAbility.setSourceId(source.getSourceId()); + delayedAbility.setControllerId(source.getControllerId()); + delayedAbility.setSourceObject(source.getSourceObject(this), this); + return addDelayedTriggeredAbility(delayedAbility); + } + @Override public UUID addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility) { DelayedTriggeredAbility newAbility = delayedAbility.copy();