From 329116669afa17f0776862e437fe9d8534656a58 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 26 Apr 2018 23:35:26 +0200 Subject: [PATCH] * Fixed a problem with stack abilities created by Designations eg. Monarch triggered ability (fixes #4457). --- .../src/main/java/mage/view/CardView.java | 14 +- .../src/main/java/mage/view/GameView.java | 2 +- .../src/mage/cards/s/StrionicResonator.java | 4 +- .../abilities/effects/ReplacementEffect.java | 12 +- .../java/mage/constants/MageObjectType.java | 74 ++++-- .../target/common/TargetTriggeredAbility.java | 234 +++++++++--------- 6 files changed, 184 insertions(+), 156 deletions(-) diff --git a/Mage.Common/src/main/java/mage/view/CardView.java b/Mage.Common/src/main/java/mage/view/CardView.java index edef6d7453a..54dda8d7395 100644 --- a/Mage.Common/src/main/java/mage/view/CardView.java +++ b/Mage.Common/src/main/java/mage/view/CardView.java @@ -27,6 +27,7 @@ */ package mage.view; +import com.google.gson.annotations.Expose; import java.util.*; import java.util.stream.Collectors; import mage.MageObject; @@ -44,6 +45,7 @@ import mage.counters.CounterType; import mage.designations.Designation; import mage.game.Game; import mage.game.command.Emblem; +import mage.game.command.Plane; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentToken; import mage.game.permanent.token.Token; @@ -53,9 +55,6 @@ import mage.target.Target; import mage.target.Targets; import mage.util.SubTypeList; -import com.google.gson.annotations.Expose; -import mage.game.command.Plane; - /** * @author BetaSteward_at_googlemail.com */ @@ -529,6 +528,13 @@ public class CardView extends SimpleCardView { // Display in landscape/rotated/on its side this.rotate = true; this.rules = plane.getAbilities().getRules(plane.getName()); + } else if (object instanceof Designation) { + this.mageObjectType = MageObjectType.DESIGNATION; + Designation designation = (Designation) object; + this.rarity = Rarity.SPECIAL; + this.frameStyle = FrameStyle.M15_NORMAL; + // Display in landscape/rotated/on its side + this.rules = designation.getAbilities().getRules(designation.getName()); } if (this.rarity == null && object instanceof StackAbility) { StackAbility stackAbility = (StackAbility) object; @@ -769,7 +775,7 @@ public class CardView extends SimpleCardView { @Override public String getExpansionSetCode() { - if (expansionSetCode == null) { + if (expansionSetCode == null) { expansionSetCode = ""; } return expansionSetCode; diff --git a/Mage.Common/src/main/java/mage/view/GameView.java b/Mage.Common/src/main/java/mage/view/GameView.java index 6ac1ff99aca..5a93bc70170 100644 --- a/Mage.Common/src/main/java/mage/view/GameView.java +++ b/Mage.Common/src/main/java/mage/view/GameView.java @@ -149,7 +149,7 @@ public class GameView implements Serializable { } else if (object instanceof Designation) { Designation designation = (Designation) game.getObject(object.getId()); if (designation != null) { - stack.put(stackObject.getId(), new CardView(designation, (StackAbility) stackObject)); + stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, designation.getName(), new CardView(designation))); } else { LOGGER.fatal("Designation object not found: " + object.getName() + ' ' + object.toString() + ' ' + object.getClass().toString()); } diff --git a/Mage.Sets/src/mage/cards/s/StrionicResonator.java b/Mage.Sets/src/mage/cards/s/StrionicResonator.java index 808740b8e04..f3986009fe1 100644 --- a/Mage.Sets/src/mage/cards/s/StrionicResonator.java +++ b/Mage.Sets/src/mage/cards/s/StrionicResonator.java @@ -52,7 +52,7 @@ import mage.target.common.TargetTriggeredAbility; public class StrionicResonator extends CardImpl { public StrionicResonator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // {2}, {T}: Copy target triggered ability you control. You may choose new targets for the copy. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new StrionicResonatorEffect(), new ManaCostsImpl("{2}")); @@ -89,7 +89,7 @@ class StrionicResonatorEffect extends OneShotEffect { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (controller != null && sourcePermanent != null) { stackAbility.createCopyOnStack(game, source, source.getControllerId(), true); - game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(": ").append(controller.getLogName()).append(" copied triggered ability").toString()); + game.informPlayers(sourcePermanent.getIdName() + ": " + controller.getLogName() + " copied triggered ability"); return true; } } diff --git a/Mage/src/main/java/mage/abilities/effects/ReplacementEffect.java b/Mage/src/main/java/mage/abilities/effects/ReplacementEffect.java index c325fbd9dbf..90e71a2d4a5 100644 --- a/Mage/src/main/java/mage/abilities/effects/ReplacementEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/ReplacementEffect.java @@ -24,8 +24,7 @@ * 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 mage.abilities.Ability; @@ -37,21 +36,22 @@ import mage.game.events.GameEvent; * @author BetaSteward_at_googlemail.com */ public interface ReplacementEffect extends ContinuousEffect { - + boolean replaceEvent(GameEvent event, Ability source, Game game); /** - * This check for the relevant events is called at first to prevent further actions if - * the current event is ignored from this effect + * This check for the relevant events is called at first to prevent further + * actions if the current event is ignored from this effect + * * @param event * @param game * @return */ boolean checksEventType(GameEvent event, Game game); + boolean applies(GameEvent event, Ability source, Game game); boolean hasSelfScope(); - @Override public ContinuousEffect copy(); diff --git a/Mage/src/main/java/mage/constants/MageObjectType.java b/Mage/src/main/java/mage/constants/MageObjectType.java index 97782827d4f..8d08765e643 100644 --- a/Mage/src/main/java/mage/constants/MageObjectType.java +++ b/Mage/src/main/java/mage/constants/MageObjectType.java @@ -5,42 +5,64 @@ package mage.constants; /** - * 109.1. An object is an ability on the stack, a card, a copy of a card, a token, a spell, a permanent, or an emblem. - * 109.2. If a spell or ability uses a description of an object that includes a card type - * or subtype, but doesn't include the word "card," "spell," "source," or "scheme," it - * means a permanent of that card type or subtype on the battlefield. - * 109.2a If a spell or ability uses a description of an object that includes the word "card" and the name of a zone, it means a card matching that description in the stated zone. # - * 109.2b If a spell or ability uses a description of an object that includes the word "spell," it means a spell matching that description on the stack. # - * 109.2c If a spell or ability uses a description of an object that includes the word "source," it means a source matching that description -- either a source of an ability or a source of damage -- in any zone. See rule 609.7. # - * 109.2d If an ability of a scheme card includes the text "this scheme," it means the scheme card in the command zone on which that ability is printed. # - * 109.3. An object's characteristics are name, mana cost, color, color indicator, card type, subtype, supertype, expansion symbol, rules text, abilities, power, toughness, loyalty, hand modifier, and life modifier. Objects can have some or all of these characteristics. Any other information about an object isn't a characteristic. For example, characteristics don't include whether a permanent is tapped, a spell's target, an object's owner or controller, what an Aura enchants, and so on. # - * 109.4. Only objects on the stack or on the battlefield have a controller. Objects that are neither on the stack nor on the battlefield aren't controlled by any player. See rule 108.4. There are four exceptions to this rule: # - * 109.4a An emblem is controlled by the player that puts it into the command zone. See rule 113, "Emblems." # - * 109.4b In a Planechase game, a face-up plane or phenomenon card is controlled by the player designated as the planar controller. This is usually the active player. See rule 901.6. # - * 109.4c In a Vanguard game, each vanguard card is controlled by its owner. See rule 902.6. # - * 109.4d In an Archenemy game, each scheme card is controlled by its owner. See rule 904.7. # - * 109.5. The words "you" and "your" on an object refer to the object's controller, its would-be controller (if a player is attempting to play, cast, or activate it), or its owner (if it has no controller). For a static ability, this is the current controller of the object it's on. For an activated ability, this is the player who activated the ability. For a triggered ability, this is the controller of the object when the ability triggered, unless it's a delayed triggered ability. To determine the controller of a delayed triggered ability, see rules 603.7d-f + * 109.1. An object is an ability on the stack, a card, a copy of a card, a + * token, a spell, a permanent, or an emblem. 109.2. If a spell or ability uses + * a description of an object that includes a card type or subtype, but doesn't + * include the word "card," "spell," "source," or "scheme," it means a permanent + * of that card type or subtype on the battlefield. 109.2a If a spell or ability + * uses a description of an object that includes the word "card" and the name of + * a zone, it means a card matching that description in the stated zone. # + * 109.2b If a spell or ability uses a description of an object that includes + * the word "spell," it means a spell matching that description on the stack. # + * 109.2c If a spell or ability uses a description of an object that includes + * the word "source," it means a source matching that description -- either a + * source of an ability or a source of damage -- in any zone. See rule 609.7. # + * 109.2d If an ability of a scheme card includes the text "this scheme," it + * means the scheme card in the command zone on which that ability is printed. # + * 109.3. An object's characteristics are name, mana cost, color, color + * indicator, card type, subtype, supertype, expansion symbol, rules text, + * abilities, power, toughness, loyalty, hand modifier, and life modifier. + * Objects can have some or all of these characteristics. Any other information + * about an object isn't a characteristic. For example, characteristics don't + * include whether a permanent is tapped, a spell's target, an object's owner or + * controller, what an Aura enchants, and so on. # 109.4. Only objects on the + * stack or on the battlefield have a controller. Objects that are neither on + * the stack nor on the battlefield aren't controlled by any player. See rule + * 108.4. There are four exceptions to this rule: # 109.4a An emblem is + * controlled by the player that puts it into the command zone. See rule 113, + * "Emblems." # 109.4b In a Planechase game, a face-up plane or phenomenon card + * is controlled by the player designated as the planar controller. This is + * usually the active player. See rule 901.6. # 109.4c In a Vanguard game, each + * vanguard card is controlled by its owner. See rule 902.6. # 109.4d In an + * Archenemy game, each scheme card is controlled by its owner. See rule 904.7. + * # 109.5. The words "you" and "your" on an object refer to the object's + * controller, its would-be controller (if a player is attempting to play, cast, + * or activate it), or its owner (if it has no controller). For a static + * ability, this is the current controller of the object it's on. For an + * activated ability, this is the player who activated the ability. For a + * triggered ability, this is the controller of the object when the ability + * triggered, unless it's a delayed triggered ability. To determine the + * controller of a delayed triggered ability, see rules 603.7d-f * * @author LevelX2 */ - public enum MageObjectType { - ABILITY_STACK ("Ability on the Stack", false, false), - CARD ("Card", false, true), - COPY_CARD ("Copy of a Card", false, true), - TOKEN ("Token", true, true), - SPELL ("Spell", false, true), - PERMANENT ("Permanent", true, true), - EMBLEM ("Emblem", false, false), - COMMANDER ("Commander", false, false), - PLANE ("Plane", false, false), + ABILITY_STACK("Ability on the Stack", false, false), + CARD("Card", false, true), + COPY_CARD("Copy of a Card", false, true), + TOKEN("Token", true, true), + SPELL("Spell", false, true), + PERMANENT("Permanent", true, true), + EMBLEM("Emblem", false, false), + COMMANDER("Commander", false, false), + DESIGNATION("Designation", false, false), + PLANE("Plane", false, false), NULL("NullObject", false, false); private final String text; private final boolean permanent; private final boolean canHaveCounters; - MageObjectType(String text, boolean permanent, boolean canHaveCounters) { this.text = text; this.permanent = permanent; diff --git a/Mage/src/main/java/mage/target/common/TargetTriggeredAbility.java b/Mage/src/main/java/mage/target/common/TargetTriggeredAbility.java index 22896eab0d9..7af6b081b29 100644 --- a/Mage/src/main/java/mage/target/common/TargetTriggeredAbility.java +++ b/Mage/src/main/java/mage/target/common/TargetTriggeredAbility.java @@ -1,117 +1,117 @@ -/* - * 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.target.common; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; -import mage.constants.Zone; -import mage.filter.Filter; -import mage.filter.FilterAbility; -import mage.game.Game; -import mage.game.stack.StackObject; -import mage.target.TargetObject; - -/** - * - * @author Styxo - */ -public class TargetTriggeredAbility extends TargetObject { - - public TargetTriggeredAbility() { - this.minNumberOfTargets = 1; - this.maxNumberOfTargets = 1; - this.zone = Zone.STACK; - this.targetName = "target triggered ability you control"; - } - - public TargetTriggeredAbility(final TargetTriggeredAbility target) { - super(target); - } - - @Override - public boolean canTarget(UUID id, Ability source, Game game) { - if (source != null && source.getSourceId().equals(id)) { - return false; - } - - StackObject stackObject = game.getStack().getStackObject(id); - return stackObject.getStackAbility() != null - && (stackObject.getStackAbility() instanceof TriggeredAbility) - && source != null - && stackObject.getStackAbility().getControllerId().equals(source.getControllerId()); - } - - @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - return canChoose(sourceControllerId, game); - } - - @Override - public boolean canChoose(UUID sourceControllerId, Game game) { - for (StackObject stackObject : game.getStack()) { - if (stackObject.getStackAbility() != null - && stackObject.getStackAbility() instanceof TriggeredAbility - && stackObject.getStackAbility().getControllerId().equals(sourceControllerId)) { - return true; - } - } - return false; - } - - @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - return possibleTargets(sourceControllerId, game); - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet<>(); - for (StackObject stackObject : game.getStack()) { - if (stackObject.getStackAbility() != null - && stackObject.getStackAbility() instanceof TriggeredAbility - && stackObject.getStackAbility().getControllerId().equals(sourceControllerId)) { - possibleTargets.add(stackObject.getStackAbility().getId()); - } - } - return possibleTargets; - } - - @Override - public TargetTriggeredAbility copy() { - return new TargetTriggeredAbility(this); - } - - @Override - public Filter getFilter() { - return new FilterAbility(); - } - -} +/* + * 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.target.common; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbility; +import mage.constants.Zone; +import mage.filter.Filter; +import mage.filter.FilterAbility; +import mage.game.Game; +import mage.game.stack.StackObject; +import mage.target.TargetObject; + +/** + * + * @author Styxo + */ +public class TargetTriggeredAbility extends TargetObject { + + public TargetTriggeredAbility() { + this.minNumberOfTargets = 1; + this.maxNumberOfTargets = 1; + this.zone = Zone.STACK; + this.targetName = "target triggered ability you control"; + } + + public TargetTriggeredAbility(final TargetTriggeredAbility target) { + super(target); + } + + @Override + public boolean canTarget(UUID id, Ability source, Game game) { + if (source != null && source.getSourceId().equals(id)) { + return false; + } + + StackObject stackObject = game.getStack().getStackObject(id); + return stackObject.getStackAbility() != null + && (stackObject.getStackAbility() instanceof TriggeredAbility) + && source != null + && stackObject.getStackAbility().getControllerId().equals(source.getControllerId()); + } + + @Override + public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + return canChoose(sourceControllerId, game); + } + + @Override + public boolean canChoose(UUID sourceControllerId, Game game) { + for (StackObject stackObject : game.getStack()) { + if (stackObject.getStackAbility() != null + && stackObject.getStackAbility() instanceof TriggeredAbility + && stackObject.getStackAbility().getControllerId().equals(sourceControllerId)) { + return true; + } + } + return false; + } + + @Override + public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + return possibleTargets(sourceControllerId, game); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Game game) { + Set possibleTargets = new HashSet<>(); + for (StackObject stackObject : game.getStack()) { + if (stackObject.getStackAbility() != null + && stackObject.getStackAbility() instanceof TriggeredAbility + && stackObject.getStackAbility().getControllerId().equals(sourceControllerId)) { + possibleTargets.add(stackObject.getStackAbility().getId()); + } + } + return possibleTargets; + } + + @Override + public TargetTriggeredAbility copy() { + return new TargetTriggeredAbility(this); + } + + @Override + public Filter getFilter() { + return new FilterAbility(); + } + +}