From 515b55f0882c551b250b83fd18b67e8b26a1c374 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 14 Dec 2019 22:20:59 +0100 Subject: [PATCH] Fixed handling of Guardian Beast, fixed rule text display (fixes #5922). --- Mage.Sets/src/mage/cards/g/GuardianBeast.java | 34 ++++++++++--------- .../continuous/GainControlTargetEffect.java | 29 ++++++++++++---- .../main/java/mage/filter/StaticFilters.java | 8 ++++- .../mage/game/permanent/PermanentImpl.java | 16 ++++++--- 4 files changed, 58 insertions(+), 29 deletions(-) diff --git a/Mage.Sets/src/mage/cards/g/GuardianBeast.java b/Mage.Sets/src/mage/cards/g/GuardianBeast.java index f7a10a6568..32885e4098 100644 --- a/Mage.Sets/src/mage/cards/g/GuardianBeast.java +++ b/Mage.Sets/src/mage/cards/g/GuardianBeast.java @@ -1,4 +1,3 @@ - package mage.cards.g; import java.util.Objects; @@ -18,6 +17,7 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterObject; import mage.filter.FilterStackObject; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledArtifactPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -44,16 +44,20 @@ public final class GuardianBeast extends CardImpl { } public GuardianBeast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add(SubType.BEAST); this.power = new MageInt(2); this.toughness = new MageInt(4); - // As long as Guardian Beast is untapped, noncreature artifacts you control can't be enchanted, they're indestructible, and other players can't gain control of them. This effect doesn't remove Auras already attached to those artifacts. - Effect effect = new ConditionalContinuousEffect(new GainAbilityControlledEffect(IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield, filter), new InvertCondition(SourceTappedCondition.instance), "noncreature artifacts you control can't be enchanted, they're indestructible, and other players can't gain control of them"); - GuardianBeastConditionalEffect effect2 = new GuardianBeastConditionalEffect(this.getId()); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect2)); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + // As long as Guardian Beast is untapped, noncreature artifacts you control can't be enchanted, they're indestructible, and other players can't gain control of them. + // This effect doesn't remove Auras already attached to those artifacts. + Effect effect = new ConditionalContinuousEffect(new GainAbilityControlledEffect(IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield, filter), + new InvertCondition(SourceTappedCondition.instance), + "As long as Guardian Beast is untapped, noncreature artifacts you control can't be enchanted, they're indestructible"); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); + ability.addEffect(new GuardianBeastConditionalEffect(this.getId())); + this.addAbility(ability); + } public GuardianBeast(final GuardianBeast card) { @@ -68,16 +72,11 @@ public final class GuardianBeast extends CardImpl { class GuardianBeastConditionalEffect extends ContinuousRuleModifyingEffectImpl { - private static final FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent("Noncreature artifacts"); - private UUID guardianBeastId; - - static { - filter.add(Predicates.not(new CardTypePredicate(CardType.CREATURE))); - } + private final UUID guardianBeastId; public GuardianBeastConditionalEffect(UUID guardianBeastId) { super(Duration.WhileOnBattlefield, Outcome.Neutral); - staticText = "Noncreature artifacts you control have they can't be enchanted, they're indestructible, and other players can't gain control of them"; + staticText = ", and other players can't gain control of them. This effect doesn't remove Auras already attached to those artifacts"; this.guardianBeastId = guardianBeastId; } @@ -116,8 +115,11 @@ class GuardianBeastConditionalEffect extends ContinuousRuleModifyingEffectImpl { } StackObject spell = game.getStack().getStackObject(event.getSourceId()); - if (event.getType() == EventType.LOSE_CONTROL || event.getType() == EventType.ATTACH || event.getType() == EventType.TARGET && spell != null && spell.isEnchantment() && spell.hasSubtype(SubType.AURA, game)) { - for (Permanent perm : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { + if (event.getType() == EventType.GAIN_CONTROL + || ((event.getType() == EventType.ATTACH + || event.getType() == EventType.TARGET) + && spell != null && spell.isEnchantment() && spell.hasSubtype(SubType.AURA, game))) { + for (Permanent perm : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_ARTIFACTS_NON_CREATURE, source.getControllerId(), game)) { if (perm != null && Objects.equals(perm.getId(), targetPermanent.getId()) && !perm.isCreature()) { return true; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlTargetEffect.java index 129c58657a..c418dadd40 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlTargetEffect.java @@ -2,6 +2,7 @@ package mage.abilities.effects.common.continuous; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.ActivatedAbility; import mage.abilities.Mode; import mage.abilities.effects.ContinuousEffectImpl; import mage.constants.Duration; @@ -23,6 +24,7 @@ public class GainControlTargetEffect extends ContinuousEffectImpl { protected UUID controllingPlayerId; private boolean fixedControl; + private boolean firstControlChange = true; public GainControlTargetEffect(Duration duration) { this(duration, false, null); @@ -77,31 +79,44 @@ public class GainControlTargetEffect extends ContinuousEffectImpl { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - boolean targetStillExists = false; + boolean oneTargetStillExists = false; for (UUID permanentId : getTargetPointer().getTargets(game, source)) { Permanent permanent = game.getPermanent(permanentId); if (permanent != null) { - targetStillExists = true; + oneTargetStillExists = true; if (!permanent.isControlledBy(controllingPlayerId)) { GameEvent loseControlEvent = GameEvent.getEvent(GameEvent.EventType.LOSE_CONTROL, permanentId, source.getId(), permanent.getControllerId()); if (game.replaceEvent(loseControlEvent)) { return false; } + boolean controlChanged = false; if (controllingPlayerId != null) { - permanent.changeControllerId(controllingPlayerId, game); - permanent.getAbilities().setControllerId(controllingPlayerId); + if (permanent.changeControllerId(controllingPlayerId, game)) { + permanent.getAbilities().setControllerId(controllingPlayerId); + controlChanged = true; + } } else { - permanent.changeControllerId(source.getControllerId(), game); - permanent.getAbilities().setControllerId(source.getControllerId()); + if (permanent.changeControllerId(source.getControllerId(), game)) { + permanent.getAbilities().setControllerId(source.getControllerId()); + controlChanged = true; + } + } + if (source instanceof ActivatedAbility + && firstControlChange && !controlChanged) { + // If it was not possible to get control of target permanent by the activated ability the first time it took place + // the effect failed (e.g. because of Guardian Beast) and must be discarded + // This does not handle correctly multiple targets at once + discard(); } } } } // no valid target exists and the controller is no longer in the game, effect can be discarded - if (!targetStillExists + if (!oneTargetStillExists || !controller.isInGame()) { discard(); } + firstControlChange = false; return true; } discard(); // controller no longer exists diff --git a/Mage/src/main/java/mage/filter/StaticFilters.java b/Mage/src/main/java/mage/filter/StaticFilters.java index 2888e8840a..0462ba6f48 100644 --- a/Mage/src/main/java/mage/filter/StaticFilters.java +++ b/Mage/src/main/java/mage/filter/StaticFilters.java @@ -133,7 +133,6 @@ public final class StaticFilters { FILTER_CARD_A_NON_LAND.setLockedFilter(true); } - public static final FilterNonlandCard FILTER_CARDS_NON_LAND = new FilterNonlandCard("nonland cards"); static { @@ -188,6 +187,13 @@ public final class StaticFilters { FILTER_ARTIFACT_CREATURE_PERMANENT.setLockedFilter(true); } + public static final FilterControlledArtifactPermanent FILTER_ARTIFACTS_NON_CREATURE = new FilterControlledArtifactPermanent("Noncreature artifacts"); + + static { + FILTER_ARTIFACTS_NON_CREATURE.add(Predicates.not(new CardTypePredicate(CardType.CREATURE))); + FILTER_ARTIFACTS_NON_CREATURE.setLockedFilter(true); + } + public static final FilterPermanent FILTER_PERMANENT_ARTIFACT_OR_CREATURE = new FilterPermanent("artifact or creature"); static { diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index 4537ecf18b..e1f020ebf4 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -1,5 +1,6 @@ package mage.game.permanent; +import java.util.*; import mage.MageObject; import mage.MageObjectReference; import mage.ObjectColor; @@ -37,8 +38,6 @@ import mage.util.GameLog; import mage.util.ThreadLocalStringBuilder; import org.apache.log4j.Logger; -import java.util.*; - /** * @author BetaSteward_at_googlemail.com */ @@ -665,6 +664,13 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { @Override public boolean changeControllerId(UUID controllerId, Game game) { Player newController = game.getPlayer(controllerId); + // For each control change compared to last controler send a GAIN_CONTROL replace event to be able to prevent the gain control (e.g. Guardian Beast) + if (beforeResetControllerId != controllerId) { + GameEvent gainControlEvent = GameEvent.getEvent(GameEvent.EventType.GAIN_CONTROL, this.getId(), null, controllerId); + if (game.replaceEvent(gainControlEvent)) { + return false; + } + } GameEvent loseControlEvent = GameEvent.getEvent(GameEvent.EventType.LOSE_CONTROL, this.getId(), null, controllerId); @@ -755,7 +761,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { this.attachedTo = attachToObjectId; this.attachedToZoneChangeCounter = game.getState().getZoneChangeCounter(attachToObjectId); for (Ability ability : this.getAbilities()) { - for (Iterator ite = ability.getEffects(game, EffectType.CONTINUOUS).iterator(); ite.hasNext(); ) { + for (Iterator ite = ability.getEffects(game, EffectType.CONTINUOUS).iterator(); ite.hasNext();) { ContinuousEffect effect = (ContinuousEffect) ite.next(); game.getContinuousEffects().setOrder(effect); // It's important to update the timestamp of the copied effect in ContinuousEffects because it does the action @@ -810,8 +816,8 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { * @param game * @param preventable * @param combat - * @param markDamage If true, damage will be dealt later in applyDamage - * method + * @param markDamage If true, damage will be dealt later in applyDamage + * method * @return */ private int damage(int damageAmount, UUID sourceId, Game game, boolean preventable, boolean combat, boolean markDamage, List appliedEffects) {