From 06b7e638437b32e2bece6aaa799d3a80fa1c020b Mon Sep 17 00:00:00 2001 From: BetaSteward Date: Sun, 21 Nov 2010 03:35:04 +0000 Subject: [PATCH] added missing Planeswalker damage redirection effect + some fixes --- .../src/mage/sets/magic2010/ProteanHydra.java | 2 +- .../mage/sets/magic2011/NecroticPlague.java | 8 +- .../mage/sets/magic2011/VengefulArchon.java | 2 +- .../mage/sets/zendikar/BraveTheElements.java | 19 ++-- Mage/src/mage/Constants.java | 1 + .../abilities/effects/ContinuousEffects.java | 7 +- .../PlaneswalkerRedirectionEffect.java | 99 +++++++++++++++++++ .../effects/PreventionEffectImpl.java | 2 +- .../abilities/effects/RedirectionEffect.java | 93 +++++++++++++++++ .../DamageAllControlledTargetEffect.java | 2 +- .../effects/common/DamageAllEffect.java | 2 +- .../common/DamageControllerEffect.java | 2 +- .../effects/common/DamageMultiEffect.java | 4 +- .../effects/common/DamageTargetEffect.java | 4 +- .../effects/common/DamageXTargetEffect.java | 4 +- .../DestroyAllControlledTargetEffect.java | 2 +- .../effects/common/DestroyAllEffect.java | 2 +- .../DestroyAllNamedPermanentsEffect.java | 2 +- .../common/DestroyNoRegenTargetEffect.java | 2 +- .../effects/common/DestroySourceEffect.java | 2 +- .../effects/common/DestroyTargetEffect.java | 2 +- .../common/GainAbilityControlledEffect.java | 16 +-- .../common/PreventAllCombatDamageEffect.java | 2 +- .../common/PreventAllDamageSourceEffect.java | 2 +- .../common/PreventAllDamageToEffect.java | 2 +- .../common/PreventDamageTargetEffect.java | 2 +- .../effects/common/SacrificeAllEffect.java | 2 - .../abilities/keyword/CascadeAbility.java | 2 - Mage/src/mage/cards/CardImpl.java | 8 +- Mage/src/mage/game/GameState.java | 16 ++- Mage/src/mage/game/events/GameEvent.java | 12 ++- .../src/mage/game/events/ZoneChangeEvent.java | 17 ++++ .../mage/game/permanent/PermanentCard.java | 52 ++++++++-- .../mage/game/permanent/PermanentImpl.java | 8 +- .../mage/game/permanent/PermanentToken.java | 8 +- Mage/src/mage/game/permanent/token/Token.java | 2 +- Mage/src/mage/players/PlayerImpl.java | 8 +- 37 files changed, 347 insertions(+), 75 deletions(-) create mode 100644 Mage/src/mage/abilities/effects/PlaneswalkerRedirectionEffect.java create mode 100644 Mage/src/mage/abilities/effects/RedirectionEffect.java diff --git a/Mage.Sets/src/mage/sets/magic2010/ProteanHydra.java b/Mage.Sets/src/mage/sets/magic2010/ProteanHydra.java index 04799784045..c0c30de9783 100644 --- a/Mage.Sets/src/mage/sets/magic2010/ProteanHydra.java +++ b/Mage.Sets/src/mage/sets/magic2010/ProteanHydra.java @@ -137,7 +137,7 @@ public class ProteanHydra extends CardImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { boolean retValue = false; - GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, source.getFirstTarget(), source.getId(), source.getControllerId(), event.getAmount()); + GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, source.getFirstTarget(), source.getId(), source.getControllerId(), event.getAmount(), false); int damage = event.getAmount(); if (!game.replaceEvent(preventEvent)) { event.setAmount(0); diff --git a/Mage.Sets/src/mage/sets/magic2011/NecroticPlague.java b/Mage.Sets/src/mage/sets/magic2011/NecroticPlague.java index 0a6d2c7e557..b7aa45c4c55 100644 --- a/Mage.Sets/src/mage/sets/magic2011/NecroticPlague.java +++ b/Mage.Sets/src/mage/sets/magic2011/NecroticPlague.java @@ -40,6 +40,7 @@ import mage.Constants.Zone; import mage.abilities.Ability; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.common.OnEventTriggeredAbility; +import mage.abilities.common.PutIntoGraveFromBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; @@ -117,7 +118,7 @@ class NecroticPlagueEffect extends ContinuousEffectImpl { case AbilityAddingRemovingEffects_6: if (sublayer == SubLayer.NA) { creature.addAbility(new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", new SacrificeSourceEffect())); - creature.addAbility(new LeavesBattlefieldTriggeredAbility(new NecroticPlagueEffect2(source.getSourceId()), false)); + creature.addAbility(new PutIntoGraveFromBattlefieldTriggeredAbility(new NecroticPlagueEffect2(source.getSourceId()), false)); } break; } @@ -187,4 +188,9 @@ class NecroticPlagueEffect2 extends OneShotEffect { return new NecroticPlagueEffect2(this); } + @Override + public String getText(Ability source) { + return "its controller chooses target creature one of his or her opponents controls. Return Necrotic Plague from its owner's graveyard to the battlefield attached to that creature."; + } + } \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/magic2011/VengefulArchon.java b/Mage.Sets/src/mage/sets/magic2011/VengefulArchon.java index 9740a0f1028..222b4640574 100644 --- a/Mage.Sets/src/mage/sets/magic2011/VengefulArchon.java +++ b/Mage.Sets/src/mage/sets/magic2011/VengefulArchon.java @@ -112,7 +112,7 @@ class VengefulArchonEffect extends PreventionEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, source.getControllerId(), source.getId(), source.getControllerId(), event.getAmount()); + GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, source.getControllerId(), source.getId(), source.getControllerId(), event.getAmount(), false); if (!game.replaceEvent(preventEvent)) { Player player = game.getPlayer(source.getFirstTarget()); if (player != null) { diff --git a/Mage.Sets/src/mage/sets/zendikar/BraveTheElements.java b/Mage.Sets/src/mage/sets/zendikar/BraveTheElements.java index 15edcbcba08..8e58acc383f 100644 --- a/Mage.Sets/src/mage/sets/zendikar/BraveTheElements.java +++ b/Mage.Sets/src/mage/sets/zendikar/BraveTheElements.java @@ -74,20 +74,23 @@ public class BraveTheElements extends CardImpl { class BraveTheElementsEffect extends GainAbilityControlledEffect { - FilterCreaturePermanent filter1 = new FilterCreaturePermanent(); + private static FilterCreaturePermanent filter1 = new FilterCreaturePermanent(); + + static { + filter1.setUseColor(true); + filter1.getColor().setWhite(true); + } + FilterCard filter2; public BraveTheElementsEffect() { - super(new ProtectionAbility(new FilterCard()), Duration.EndOfTurn); - filter1.setUseColor(true); - filter1.getColor().setWhite(true); + super(new ProtectionAbility(new FilterCard()), Duration.EndOfTurn, filter1); filter2 = (FilterCard)((ProtectionAbility)ability).getFilter(); filter2.setUseColor(true); } public BraveTheElementsEffect(final BraveTheElementsEffect effect) { super(effect); - this.filter1 = effect.filter1.copy(); this.filter2 = effect.filter2.copy(); } @@ -101,10 +104,8 @@ class BraveTheElementsEffect extends GainAbilityControlledEffect { ChoiceColor choice = (ChoiceColor) source.getChoices().get(0); filter2.setColor(choice.getColor()); filter2.setMessage(choice.getChoice()); - for (Permanent perm: game.getBattlefield().getAllActivePermanents(filter1, source.getControllerId())) { - perm.addAbility(ability); - } - return true; + ability = new ProtectionAbility(new FilterCard(filter2)); + return super.apply(game, source); } @Override diff --git a/Mage/src/mage/Constants.java b/Mage/src/mage/Constants.java index 6a9b3dae018..2bb5436697c 100644 --- a/Mage/src/mage/Constants.java +++ b/Mage/src/mage/Constants.java @@ -281,6 +281,7 @@ public final class Constants { PutManaInPool(true), Regenerate(true), PreventDamage(true), + RedirectDamage(true), Tap(false), Untap(true), Win(true), diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index 098cda75373..ebd007c8b9c 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -59,13 +59,16 @@ public class ContinuousEffects implements Serializable { private final Map preventionEffects = new HashMap(); private final Map asThoughEffects = new HashMap(); private final ApplyCountersEffect applyCounters; + private final PlaneswalkerRedirectionEffect planeswalkerRedirectionEffect; public ContinuousEffects() { applyCounters = new ApplyCountersEffect(); + planeswalkerRedirectionEffect = new PlaneswalkerRedirectionEffect(); } public ContinuousEffects(final ContinuousEffects effect) { this.applyCounters = effect.applyCounters.copy(); + this.planeswalkerRedirectionEffect = effect.planeswalkerRedirectionEffect.copy(); for (Entry entry: effect.layeredEffects.entrySet()) { layeredEffects.put((ContinuousEffect)entry.getKey().copy(), entry.getValue().copy()); } @@ -158,10 +161,12 @@ public class ContinuousEffects implements Serializable { private List getApplicableReplacementEffects(GameEvent event, Game game) { List replaceEffects = new ArrayList(); + if (planeswalkerRedirectionEffect.applies(event, null, game)) + replaceEffects.add(planeswalkerRedirectionEffect); for (ReplacementEffect effect: replacementEffects.keySet()) { if (effect.applies(event, replacementEffects.get(effect), game)) { if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) - replaceEffects.add((ReplacementEffect)effect); + replaceEffects.add(effect); } } return replaceEffects; diff --git a/Mage/src/mage/abilities/effects/PlaneswalkerRedirectionEffect.java b/Mage/src/mage/abilities/effects/PlaneswalkerRedirectionEffect.java new file mode 100644 index 00000000000..ca7e2ab30df --- /dev/null +++ b/Mage/src/mage/abilities/effects/PlaneswalkerRedirectionEffect.java @@ -0,0 +1,99 @@ +/* + * 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 mage.abilities.effects; + +import java.util.UUID; +import mage.Constants.Duration; +import mage.Constants.Outcome; +import mage.abilities.Ability; +import mage.filter.common.FilterPlaneswalkerPermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.TargetPermanent; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class PlaneswalkerRedirectionEffect extends RedirectionEffect { + + private static FilterPlaneswalkerPermanent filter = new FilterPlaneswalkerPermanent(); + + public PlaneswalkerRedirectionEffect() { + super(Duration.EndOfGame); + } + + public PlaneswalkerRedirectionEffect(final PlaneswalkerRedirectionEffect effect) { + super(effect); + } + + @Override + public PlaneswalkerRedirectionEffect copy() { + return new PlaneswalkerRedirectionEffect(this); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getType() == EventType.DAMAGE_PLAYER) { + UUID playerId = getSourceControllerId(event.getSourceId(), game); + if (game.getOpponents(event.getTargetId()).contains(playerId)) { + Player target = game.getPlayer(event.getTargetId()); + Player player = game.getPlayer(playerId); + if (target != null) { + int numPlaneswalkers = game.getBattlefield().countAll(filter, target.getId()); + if (numPlaneswalkers > 0 && player.chooseUse(outcome, "Redirect damage to planeswalker?", game)) { + redirectTarget = new TargetPermanent(filter); + if (numPlaneswalkers == 1) { + redirectTarget.add(game.getBattlefield().getAllActivePermanents(filter, target.getId()).get(0).getId(), game); + } + else { + player.choose(Outcome.Damage, redirectTarget, game); + } + return true; + } + } + } + } + return false; + } + + private UUID getSourceControllerId(UUID sourceId, Game game) { + StackObject source = game.getStack().getStackObject(sourceId); + if (source != null) + return source.getControllerId(); + Permanent permanent = game.getBattlefield().getPermanent(sourceId); + if (permanent != null) + return permanent.getControllerId(); + return null; + } +} diff --git a/Mage/src/mage/abilities/effects/PreventionEffectImpl.java b/Mage/src/mage/abilities/effects/PreventionEffectImpl.java index b051337e65d..d31159d8427 100644 --- a/Mage/src/mage/abilities/effects/PreventionEffectImpl.java +++ b/Mage/src/mage/abilities/effects/PreventionEffectImpl.java @@ -55,7 +55,7 @@ public abstract class PreventionEffectImpl> ex case DAMAGE_CREATURE: case DAMAGE_PLAYER: case DAMAGE_PLANESWALKER: - return true; + return event.getFlag(); default: return false; } diff --git a/Mage/src/mage/abilities/effects/RedirectionEffect.java b/Mage/src/mage/abilities/effects/RedirectionEffect.java new file mode 100644 index 00000000000..3e1e9734dea --- /dev/null +++ b/Mage/src/mage/abilities/effects/RedirectionEffect.java @@ -0,0 +1,93 @@ +/* + * 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 mage.abilities.effects; + +import java.util.UUID; +import mage.Constants.Duration; +import mage.Constants.Outcome; +import mage.abilities.Ability; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.game.stack.StackAbility; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.TargetPermanent; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public abstract class RedirectionEffect> extends ReplacementEffectImpl { + + protected TargetPermanent redirectTarget; + + public RedirectionEffect(Duration duration) { + super(duration, Outcome.RedirectDamage); + } + + public RedirectionEffect(final RedirectionEffect effect) { + super(effect); + this.redirectTarget = effect.redirectTarget; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent permanent = game.getPermanent(redirectTarget.getFirstTarget()); + Ability damageSource = getSource(event.getSourceId(), game); + if (permanent != null) { + permanent.damage(event.getAmount(), damageSource.getId(), game, event.getFlag()); + return true; + } + Player player = game.getPlayer(redirectTarget.getFirstTarget()); + if (player != null) { + player.damage(event.getAmount(), damageSource.getId(), game, false, event.getFlag()); + return true; + } + return false; + } + + protected Ability getSource(UUID sourceId, Game game) { + StackObject source = game.getStack().getStackObject(sourceId); + if (source != null) { + if (source instanceof StackAbility) + return (StackAbility)source; + if (source instanceof Spell) + return ((Spell)source).getSpellAbility(); + } + return null; + } + +} diff --git a/Mage/src/mage/abilities/effects/common/DamageAllControlledTargetEffect.java b/Mage/src/mage/abilities/effects/common/DamageAllControlledTargetEffect.java index 028bdd771d1..0ba16fd5382 100644 --- a/Mage/src/mage/abilities/effects/common/DamageAllControlledTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/DamageAllControlledTargetEffect.java @@ -64,7 +64,7 @@ public class DamageAllControlledTargetEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { - permanent.damage(amount, source.getSourceId(), game, true); + permanent.damage(amount, source.getId(), game, true); } return true; } diff --git a/Mage/src/mage/abilities/effects/common/DamageControllerEffect.java b/Mage/src/mage/abilities/effects/common/DamageControllerEffect.java index b29bd232b69..43060a7cefd 100644 --- a/Mage/src/mage/abilities/effects/common/DamageControllerEffect.java +++ b/Mage/src/mage/abilities/effects/common/DamageControllerEffect.java @@ -72,7 +72,7 @@ public class DamageControllerEffect extends OneShotEffect { for (UUID target: multiTarget.getTargets()) { Permanent permanent = game.getPermanent(target); if (permanent != null) { - permanent.damage(multiTarget.getTargetAmount(target), source.getSourceId(), game, true); + permanent.damage(multiTarget.getTargetAmount(target), source.getId(), game, true); } else { Player player = game.getPlayer(target); if (player != null) { - player.damage(multiTarget.getTargetAmount(target), source.getSourceId(), game, false, true); + player.damage(multiTarget.getTargetAmount(target), source.getId(), game, false, true); } } } diff --git a/Mage/src/mage/abilities/effects/common/DamageTargetEffect.java b/Mage/src/mage/abilities/effects/common/DamageTargetEffect.java index 6b062903d95..872df05f36c 100644 --- a/Mage/src/mage/abilities/effects/common/DamageTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/DamageTargetEffect.java @@ -73,12 +73,12 @@ public class DamageTargetEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getFirstTarget()); if (permanent != null) { - permanent.damage(amount, source.getSourceId(), game, preventable); + permanent.damage(amount, source.getId(), game, preventable); return true; } Player player = game.getPlayer(source.getFirstTarget()); if (player != null) { - player.damage(amount, source.getSourceId(), game, false, preventable); + player.damage(amount, source.getId(), game, false, preventable); return true; } return false; diff --git a/Mage/src/mage/abilities/effects/common/DamageXTargetEffect.java b/Mage/src/mage/abilities/effects/common/DamageXTargetEffect.java index d228416b605..6ed63ef1704 100644 --- a/Mage/src/mage/abilities/effects/common/DamageXTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/DamageXTargetEffect.java @@ -59,12 +59,12 @@ public class DamageXTargetEffect extends OneShotEffect { int amount = source.getCosts().getVariableCosts().get(0).getAmount(); Permanent permanent = game.getPermanent(source.getFirstTarget()); if (permanent != null) { - permanent.damage(amount, source.getSourceId(), game, true); + permanent.damage(amount, source.getId(), game, true); return true; } Player player = game.getPlayer(source.getFirstTarget()); if (player != null) { - player.damage(amount, source.getSourceId(), game, false, true); + player.damage(amount, source.getId(), game, false, true); return true; } return false; diff --git a/Mage/src/mage/abilities/effects/common/DestroyAllControlledTargetEffect.java b/Mage/src/mage/abilities/effects/common/DestroyAllControlledTargetEffect.java index 8b702bd9f84..adfb2001a02 100644 --- a/Mage/src/mage/abilities/effects/common/DestroyAllControlledTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/DestroyAllControlledTargetEffect.java @@ -61,7 +61,7 @@ public class DestroyAllControlledTargetEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { - permanent.destroy(source.getSourceId(), game, noRegen); + permanent.destroy(source.getId(), game, noRegen); return true; } return false; diff --git a/Mage/src/mage/abilities/effects/common/DestroyTargetEffect.java b/Mage/src/mage/abilities/effects/common/DestroyTargetEffect.java index d0f3872e067..68e5cafb7d1 100644 --- a/Mage/src/mage/abilities/effects/common/DestroyTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/DestroyTargetEffect.java @@ -65,7 +65,7 @@ public class DestroyTargetEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getFirstTarget()); if (permanent != null) { - permanent.destroy(source.getSourceId(), game, noRegen); + permanent.destroy(source.getId(), game, noRegen); return true; } return false; diff --git a/Mage/src/mage/abilities/effects/common/GainAbilityControlledEffect.java b/Mage/src/mage/abilities/effects/common/GainAbilityControlledEffect.java index a41b4e1201f..d5dd25684da 100644 --- a/Mage/src/mage/abilities/effects/common/GainAbilityControlledEffect.java +++ b/Mage/src/mage/abilities/effects/common/GainAbilityControlledEffect.java @@ -45,7 +45,7 @@ import mage.game.permanent.Permanent; public class GainAbilityControlledEffect extends ContinuousEffectImpl { protected Ability ability; - protected boolean excludeSource; + protected boolean excludeSource; protected FilterPermanent permanentFilter; public GainAbilityControlledEffect(Ability ability, Duration duration) { @@ -56,18 +56,18 @@ public class GainAbilityControlledEffect extends ContinuousEffectImpl= this.amount) { int damage = event.getAmount(); diff --git a/Mage/src/mage/abilities/effects/common/SacrificeAllEffect.java b/Mage/src/mage/abilities/effects/common/SacrificeAllEffect.java index 430d1c8fb3c..a23fce0a7d0 100644 --- a/Mage/src/mage/abilities/effects/common/SacrificeAllEffect.java +++ b/Mage/src/mage/abilities/effects/common/SacrificeAllEffect.java @@ -35,12 +35,10 @@ import mage.Constants.Outcome; import mage.Constants.TargetController; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; /** diff --git a/Mage/src/mage/abilities/keyword/CascadeAbility.java b/Mage/src/mage/abilities/keyword/CascadeAbility.java index a2bf987690d..720d202ce97 100644 --- a/Mage/src/mage/abilities/keyword/CascadeAbility.java +++ b/Mage/src/mage/abilities/keyword/CascadeAbility.java @@ -97,7 +97,6 @@ class CascadeEffect extends OneShotEffect { if (card == null) break; card.moveToExile(exile.getId(), exile.getName(), game); -// exile.add(card); } while (card.getCardType().contains(CardType.LAND) || card.getManaCost().convertedManaCost() >= sourceCost); if (card != null) { @@ -111,7 +110,6 @@ class CascadeEffect extends OneShotEffect { card = exile.getRandom(game); exile.remove(card.getId()); card.moveToZone(Zone.LIBRARY, game, false); -// player.getLibrary().putOnBottom(card, game); } return true; diff --git a/Mage/src/mage/cards/CardImpl.java b/Mage/src/mage/cards/CardImpl.java index b1c5c23367b..1941d8d88fd 100644 --- a/Mage/src/mage/cards/CardImpl.java +++ b/Mage/src/mage/cards/CardImpl.java @@ -184,7 +184,7 @@ public abstract class CardImpl> extends MageObjectImpl public boolean moveToZone(Zone toZone, UUID controllerId, Game game, boolean flag) { Zone fromZone = zone; - ZoneChangeEvent event = new ZoneChangeEvent(this.getId(), controllerId, fromZone, toZone); + ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, controllerId, fromZone, toZone); if (!game.replaceEvent(event)) { switch (event.getToZone()) { case GRAVEYARD: @@ -226,7 +226,7 @@ public abstract class CardImpl> extends MageObjectImpl @Override public boolean moveToExile(UUID exileId, String name, Game game) { Zone fromZone = zone; - ZoneChangeEvent event = new ZoneChangeEvent(this.getId(), ownerId, fromZone, Zone.EXILED); + ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, ownerId, fromZone, Zone.EXILED); if (!game.replaceEvent(event)) { if (exileId == null) { game.getExile().getPermanentExile().add(this); @@ -235,7 +235,7 @@ public abstract class CardImpl> extends MageObjectImpl game.getExile().createZone(exileId, name).add(this); } zone = event.getToZone(); - game.fireEvent(new ZoneChangeEvent(this.getId(), ownerId, fromZone, Zone.EXILED)); + game.fireEvent(new ZoneChangeEvent(this.objectId, ownerId, fromZone, Zone.EXILED)); return true; } return false; @@ -248,7 +248,7 @@ public abstract class CardImpl> extends MageObjectImpl zone = Zone.BATTLEFIELD; permanent.entersBattlefield(game); game.applyEffects(); - game.fireEvent(new ZoneChangeEvent(permanent.getId(), controllerId, fromZone, Zone.BATTLEFIELD)); + game.fireEvent(new ZoneChangeEvent(permanent, controllerId, fromZone, Zone.BATTLEFIELD)); return true; } diff --git a/Mage/src/mage/game/GameState.java b/Mage/src/mage/game/GameState.java index b26a3a0537d..69310671d47 100644 --- a/Mage/src/mage/game/GameState.java +++ b/Mage/src/mage/game/GameState.java @@ -44,6 +44,8 @@ import mage.abilities.TriggeredAbilities; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffects; import mage.game.combat.Combat; +import mage.game.events.GameEvent.EventType; +import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Battlefield; import mage.game.permanent.Permanent; import mage.game.stack.StackObject; @@ -295,14 +297,20 @@ public class GameState implements Serializable, Copyable { public void handleEvent(GameEvent event, Game game) { watchers.watch(event, game); if (!replaceEvent(event, game)) { + if (event.getType() == EventType.ZONE_CHANGE) { + ZoneChangeEvent zEvent = (ZoneChangeEvent)event; + if (zEvent.getFromZone() == Zone.BATTLEFIELD) { + zEvent.getTarget().checkTriggers(zEvent.getToZone(), event, game); + } + } for (Player player: players.values()) { player.checkTriggers(event, game); } + battlefield.checkTriggers(event, game); + stack.checkTriggers(event, game); + delayed.checkTriggers(event, game); + exile.checkTriggers(event, game); } - battlefield.checkTriggers(event, game); - stack.checkTriggers(event, game); - delayed.checkTriggers(event, game); - exile.checkTriggers(event, game); } public boolean replaceEvent(GameEvent event, Game game) { diff --git a/Mage/src/mage/game/events/GameEvent.java b/Mage/src/mage/game/events/GameEvent.java index c7b57ac567d..36f35575f05 100644 --- a/Mage/src/mage/game/events/GameEvent.java +++ b/Mage/src/mage/game/events/GameEvent.java @@ -41,6 +41,7 @@ public class GameEvent { private UUID sourceId; private UUID playerId; private int amount; + private boolean flag; private String data; public enum EventType { @@ -119,19 +120,20 @@ public class GameEvent { } public GameEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId) { - this(type, targetId, sourceId, playerId, 0); + this(type, targetId, sourceId, playerId, 0, false); } - public GameEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId, int amount) { + public GameEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag) { this.type = type; this.targetId = targetId; this.sourceId = sourceId; this.amount = amount; this.playerId = playerId; + this.flag = flag; } public static GameEvent getEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId, int amount) { - return new GameEvent(type, targetId, sourceId, playerId, amount); + return new GameEvent(type, targetId, sourceId, playerId, amount, false); } public static GameEvent getEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId) { @@ -162,6 +164,10 @@ public class GameEvent { return amount; } + public boolean getFlag() { + return flag; + } + public void setAmount(int amount) { this.amount = amount; } diff --git a/Mage/src/mage/game/events/ZoneChangeEvent.java b/Mage/src/mage/game/events/ZoneChangeEvent.java index 1993ba16f43..51e4426292f 100644 --- a/Mage/src/mage/game/events/ZoneChangeEvent.java +++ b/Mage/src/mage/game/events/ZoneChangeEvent.java @@ -30,6 +30,7 @@ package mage.game.events; import java.util.UUID; import mage.Constants.Zone; +import mage.game.permanent.Permanent; /** * @@ -39,6 +40,14 @@ public class ZoneChangeEvent extends GameEvent { private Zone fromZone; private Zone toZone; + private Permanent target; + + public ZoneChangeEvent(Permanent target, UUID sourceId, UUID playerId, Zone fromZone, Zone toZone) { + super(EventType.ZONE_CHANGE, target.getId(), sourceId, playerId); + this.fromZone = fromZone; + this.toZone = toZone; + this.target = target; + } public ZoneChangeEvent(UUID targetId, UUID sourceId, UUID playerId, Zone fromZone, Zone toZone) { super(EventType.ZONE_CHANGE, targetId, sourceId, playerId); @@ -46,6 +55,10 @@ public class ZoneChangeEvent extends GameEvent { this.toZone = toZone; } + public ZoneChangeEvent(Permanent target, UUID playerId, Zone fromZone, Zone toZone) { + this(target, null, playerId, fromZone, toZone); + } + public ZoneChangeEvent(UUID targetId, UUID playerId, Zone fromZone, Zone toZone) { this(targetId, null, playerId, fromZone, toZone); } @@ -61,4 +74,8 @@ public class ZoneChangeEvent extends GameEvent { public void setToZone(Zone toZone) { this.toZone = toZone; } + + public Permanent getTarget() { + return target; + } } diff --git a/Mage/src/mage/game/permanent/PermanentCard.java b/Mage/src/mage/game/permanent/PermanentCard.java index 8150d306a94..afce2ba4fc6 100644 --- a/Mage/src/mage/game/permanent/PermanentCard.java +++ b/Mage/src/mage/game/permanent/PermanentCard.java @@ -37,10 +37,10 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.keyword.LevelAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.LevelerCard; import mage.game.Game; import mage.game.events.ZoneChangeEvent; +import mage.players.Player; /** * @@ -112,18 +112,58 @@ public class PermanentCard extends PermanentImpl { this.cardNumber = card.getCardNumber(); } +// @Override +// public boolean moveToZone(Zone zone, Game game, boolean flag) { +// ZoneChangeEvent event = new ZoneChangeEvent(this.getId(), this.getControllerId(), Zone.BATTLEFIELD, zone); +// if (!game.replaceEvent(event)) { +// if (game.getPlayer(controllerId).removeFromBattlefield(this, game)) { +// CardImpl card = (CardImpl) game.getCard(objectId); +// return card.moveToZone(event.getToZone(), controllerId, game, flag); +// } +// } +// return false; +// } + @Override - public boolean moveToZone(Zone zone, Game game, boolean flag) { - ZoneChangeEvent event = new ZoneChangeEvent(this.getId(), this.getControllerId(), Zone.BATTLEFIELD, zone); + public boolean moveToZone(Zone toZone, Game game, boolean flag) { + Zone fromZone = zone; + ZoneChangeEvent event = new ZoneChangeEvent(this, controllerId, fromZone, toZone); if (!game.replaceEvent(event)) { - if (game.getPlayer(controllerId).removeFromBattlefield(this, game)) { - CardImpl card = (CardImpl) game.getCard(objectId); - return card.moveToZone(event.getToZone(), controllerId, game, flag); + Player controller = game.getPlayer(controllerId); + if (controller != null && controller.removeFromBattlefield(this, game)) { + Card card = game.getCard(objectId); + Player owner = game.getPlayer(ownerId); + if (owner != null) { + switch (event.getToZone()) { + case GRAVEYARD: + owner.putInGraveyard(card, game, !flag); + break; + case HAND: + owner.getHand().add(card); + break; + case EXILED: + game.getExile().getPermanentExile().add(card); + break; + case LIBRARY: + if (flag) + owner.getLibrary().putOnTop(card, game); + else + owner.getLibrary().putOnBottom(card, game); + break; + case BATTLEFIELD: + //should never happen + break; + } + zone = event.getToZone(); + game.fireEvent(event); + return zone == toZone; + } } } return false; } + @Override public boolean moveToExile(UUID exileId, String name, Game game) { if (game.getPlayer(controllerId).removeFromBattlefield(this, game)) { diff --git a/Mage/src/mage/game/permanent/PermanentImpl.java b/Mage/src/mage/game/permanent/PermanentImpl.java index aa61c26fd31..ebe889b20c4 100644 --- a/Mage/src/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/mage/game/permanent/PermanentImpl.java @@ -438,8 +438,8 @@ public abstract class PermanentImpl> extends CardImpl } protected int damagePlaneswalker(int damage, UUID sourceId, Game game, boolean preventable) { - GameEvent event = new GameEvent(GameEvent.EventType.DAMAGE_PLANESWALKER, objectId, sourceId, controllerId, damage); - if (!preventable || !game.replaceEvent(event)) { + GameEvent event = new GameEvent(GameEvent.EventType.DAMAGE_PLANESWALKER, objectId, sourceId, controllerId, damage, preventable); + if (!game.replaceEvent(event)) { int actualDamage = event.getAmount(); if (actualDamage > 0) { if (event.getAmount() > this.loyalty.getValue()) { @@ -454,8 +454,8 @@ public abstract class PermanentImpl> extends CardImpl } protected int damageCreature(int damage, UUID sourceId, Game game, boolean preventable) { - GameEvent event = new GameEvent(GameEvent.EventType.DAMAGE_CREATURE, objectId, sourceId, controllerId, damage); - if (!preventable || !game.replaceEvent(event)) { + GameEvent event = new GameEvent(GameEvent.EventType.DAMAGE_CREATURE, objectId, sourceId, controllerId, damage, preventable); + if (!game.replaceEvent(event)) { int actualDamage = event.getAmount(); if (actualDamage > 0) { if (this.damage + event.getAmount() > this.toughness.getValue()) { diff --git a/Mage/src/mage/game/permanent/PermanentToken.java b/Mage/src/mage/game/permanent/PermanentToken.java index 222facc7847..323e1af5e42 100644 --- a/Mage/src/mage/game/permanent/PermanentToken.java +++ b/Mage/src/mage/game/permanent/PermanentToken.java @@ -76,9 +76,9 @@ public class PermanentToken extends PermanentImpl { @Override public boolean moveToZone(Zone zone, Game game, boolean flag) { - if (!game.replaceEvent(new ZoneChangeEvent(this.getId(), this.getControllerId(), Zone.BATTLEFIELD, zone))) { + if (!game.replaceEvent(new ZoneChangeEvent(this, this.getControllerId(), Zone.BATTLEFIELD, zone))) { if (game.getPlayer(controllerId).removeFromBattlefield(this, game)) { - game.fireEvent(new ZoneChangeEvent(this.getId(), this.getControllerId(), Zone.BATTLEFIELD, zone)); + game.fireEvent(new ZoneChangeEvent(this, this.getControllerId(), Zone.BATTLEFIELD, zone)); return true; } } @@ -87,9 +87,9 @@ public class PermanentToken extends PermanentImpl { @Override public boolean moveToExile(UUID exileId, String name, Game game) { - if (!game.replaceEvent(new ZoneChangeEvent(this.getId(), this.getControllerId(), Zone.BATTLEFIELD, Zone.EXILED))) { + if (!game.replaceEvent(new ZoneChangeEvent(this, this.getControllerId(), Zone.BATTLEFIELD, Zone.EXILED))) { if (game.getPlayer(controllerId).removeFromBattlefield(this, game)) { - game.fireEvent(new ZoneChangeEvent(this.getId(), this.getControllerId(), Zone.BATTLEFIELD, Zone.EXILED)); + game.fireEvent(new ZoneChangeEvent(this, this.getControllerId(), Zone.BATTLEFIELD, Zone.EXILED)); return true; } } diff --git a/Mage/src/mage/game/permanent/token/Token.java b/Mage/src/mage/game/permanent/token/Token.java index 32d76673158..76d48edba27 100644 --- a/Mage/src/mage/game/permanent/token/Token.java +++ b/Mage/src/mage/game/permanent/token/Token.java @@ -85,7 +85,7 @@ public class Token extends MageObjectImpl { game.getBattlefield().addPermanent(permanent); permanent.entersBattlefield(game); game.applyEffects(); - game.fireEvent(new ZoneChangeEvent(permanent.getId(), controllerId, Zone.OUTSIDE, Zone.BATTLEFIELD)); + game.fireEvent(new ZoneChangeEvent(permanent, controllerId, Zone.OUTSIDE, Zone.BATTLEFIELD)); return true; } diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 3fc016c88f7..5892044058a 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -593,7 +593,7 @@ public abstract class PlayerImpl> implements Player, Ser @Override public int loseLife(int amount, Game game) { - GameEvent event = new GameEvent(GameEvent.EventType.LOSE_LIFE, playerId, playerId, playerId, amount); + GameEvent event = new GameEvent(GameEvent.EventType.LOSE_LIFE, playerId, playerId, playerId, amount, false); if (!game.replaceEvent(event)) { setLife(this.life - amount, game); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LOST_LIFE, playerId, playerId, playerId, amount)); @@ -604,7 +604,7 @@ public abstract class PlayerImpl> implements Player, Ser @Override public void gainLife(int amount, Game game) { - GameEvent event = new GameEvent(GameEvent.EventType.GAIN_LIFE, playerId, playerId, playerId, amount); + GameEvent event = new GameEvent(GameEvent.EventType.GAIN_LIFE, playerId, playerId, playerId, amount, false); if (!game.replaceEvent(event)) { setLife(this.life + amount, game); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.GAINED_LIFE, playerId, playerId, playerId, amount)); @@ -614,8 +614,8 @@ public abstract class PlayerImpl> implements Player, Ser @Override public int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable) { if (damage > 0 && canDamage(game.getObject(sourceId))) { - GameEvent event = new GameEvent(GameEvent.EventType.DAMAGE_PLAYER, playerId, sourceId, playerId, damage); - if (!preventable || !game.replaceEvent(event)) { + GameEvent event = new GameEvent(GameEvent.EventType.DAMAGE_PLAYER, playerId, sourceId, playerId, damage, preventable); + if (!game.replaceEvent(event)) { int actualDamage = event.getAmount(); if (actualDamage > 0) { actualDamage = this.loseLife(actualDamage, game);