diff --git a/Mage.Sets/src/mage/cards/c/CorrosiveOoze.java b/Mage.Sets/src/mage/cards/c/CorrosiveOoze.java index c3eda26765..7fa4894f67 100644 --- a/Mage.Sets/src/mage/cards/c/CorrosiveOoze.java +++ b/Mage.Sets/src/mage/cards/c/CorrosiveOoze.java @@ -27,19 +27,37 @@ */ package mage.cards.c; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; import mage.abilities.common.BlocksOrBecomesBlockedTriggeredAbility; 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.DestroyAllAttachedEquipmentEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.SubType; +import mage.constants.TurnPhase; +import mage.constants.WatcherScope; +import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.EquippedPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.watchers.Watcher; /** * @@ -62,9 +80,8 @@ public class CorrosiveOoze extends CardImpl { this.toughness = new MageInt(2); // Whenever Corrosive Ooze blocks or becomes blocked by an equipped creature, destroy all Equipment attached to that creature at end of combat. - Effect effect = new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(new DestroyAllAttachedEquipmentEffect()), true); - effect.setText("destroy all Equipment attached to that creature at end of combat"); - this.addAbility(new BlocksOrBecomesBlockedTriggeredAbility(effect, filter, false)); + Effect effect = new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(new CorrosiveOozeEffect()), true); + this.addAbility(new BlocksOrBecomesBlockedTriggeredAbility(effect, filter, false), new CorrosiveOozeCombatWatcher()); } public CorrosiveOoze(final CorrosiveOoze card) { @@ -76,3 +93,161 @@ public class CorrosiveOoze extends CardImpl { return new CorrosiveOoze(this); } } + +class CorrosiveOozeEffect extends OneShotEffect { + + public CorrosiveOozeEffect() { + super(Outcome.DestroyPermanent); + this.staticText = "destroy all Equipment attached to that creature at end of combat"; + } + + public CorrosiveOozeEffect(final CorrosiveOozeEffect effect) { + super(effect); + } + + @Override + public CorrosiveOozeEffect copy() { + return new CorrosiveOozeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + CorrosiveOozeCombatWatcher watcher = (CorrosiveOozeCombatWatcher) game.getState().getWatchers().get(CorrosiveOozeCombatWatcher.class.getSimpleName()); + if (controller != null && watcher != null) { + MageObjectReference sourceMor = new MageObjectReference(source.getSourceObject(game), game); + // get equipmentsToDestroy of creatres already left the battlefield + List toDestroy = new ArrayList<>(); + Set toDestroyMor = watcher.getEquipmentsToDestroy(sourceMor); + if (toDestroyMor != null) { + for (MageObjectReference mor : toDestroyMor) { + Permanent attachment = mor.getPermanent(game); + if (attachment != null) { + toDestroy.add(attachment); + } + } + } + // get the related creatures + Set relatedCreatures = watcher.getRelatedBlockedCreatures(sourceMor); + if (relatedCreatures != null) { + for (MageObjectReference relatedCreature : relatedCreatures) { + Permanent permanent = relatedCreature.getPermanent(game); + if (permanent != null) { + for (UUID attachmentId : permanent.getAttachments()) { + Permanent attachment = game.getPermanent(attachmentId); + if (attachment != null && attachment.hasSubtype(SubType.EQUIPMENT, game)) { + toDestroy.add(attachment); + } + } + } + } + } + for (Permanent permanent : toDestroy) { + permanent.destroy(source.getSourceId(), game, false); + } + + return true; + } + return false; + + } +} + +class CorrosiveOozeCombatWatcher extends Watcher { + + public final HashMap> oozeBlocksOrBlocked = new HashMap<>(); + public final HashMap> oozeEquipmentsToDestroy = new HashMap<>(); + + public CorrosiveOozeCombatWatcher() { + super(CorrosiveOozeCombatWatcher.class.getSimpleName(), WatcherScope.GAME); + } + + public CorrosiveOozeCombatWatcher(final CorrosiveOozeCombatWatcher watcher) { + super(watcher); + for (Map.Entry> entry : watcher.oozeBlocksOrBlocked.entrySet()) { + HashSet newSet = new HashSet<>(entry.getValue()); + oozeBlocksOrBlocked.put(entry.getKey(), newSet); + } + for (Map.Entry> entry : watcher.oozeEquipmentsToDestroy.entrySet()) { + HashSet newSet = new HashSet<>(entry.getValue()); + oozeEquipmentsToDestroy.put(entry.getKey(), newSet); + } + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.BEGIN_COMBAT_STEP_PRE) { + this.oozeBlocksOrBlocked.clear(); + } + if (event.getType() == GameEvent.EventType.BLOCKER_DECLARED) { + Permanent attacker = game.getPermanent(event.getTargetId()); + Permanent blocker = game.getPermanent(event.getSourceId()); + if (attacker != null && attacker.getName().equals("Corrosive Ooze")) { + if (blocker != null && hasAttachedEquipment(game, blocker)) { + MageObjectReference oozeMor = new MageObjectReference(attacker, game); + HashSet relatedCreatures = oozeBlocksOrBlocked.getOrDefault(oozeMor, new HashSet<>()); + relatedCreatures.add(new MageObjectReference(event.getSourceId(), game)); + oozeBlocksOrBlocked.put(oozeMor, relatedCreatures); + } + } + if (blocker != null && blocker.getName().equals("Corrosive Ooze")) { + if (attacker != null && hasAttachedEquipment(game, attacker)) { + MageObjectReference oozeMor = new MageObjectReference(blocker, game); + HashSet relatedCreatures = oozeBlocksOrBlocked.getOrDefault(oozeMor, new HashSet<>()); + relatedCreatures.add(new MageObjectReference(event.getTargetId(), game)); + oozeBlocksOrBlocked.put(oozeMor, relatedCreatures); + } + } + } + if (game.getTurn().getPhaseType().equals(TurnPhase.COMBAT)) { + if (event.getType() == GameEvent.EventType.ZONE_CHANGE) { + if (((ZoneChangeEvent) event).getFromZone().equals(Zone.BATTLEFIELD)) { + // Check if a previous blocked or blocked by creatures is leaving the battlefield + for (Map.Entry> entry : oozeBlocksOrBlocked.entrySet()) { + for (MageObjectReference mor : entry.getValue()) { + if (mor.refersTo(((ZoneChangeEvent) event).getTarget(), game)) { + // check for equipments and remember + for (UUID attachmentId : ((ZoneChangeEvent) event).getTarget().getAttachments()) { + Permanent attachment = game.getPermanent(attachmentId); + if (attachment != null && attachment.hasSubtype(SubType.EQUIPMENT, game)) { + HashSet toDestroy = oozeEquipmentsToDestroy.getOrDefault(entry.getKey(), new HashSet<>()); + toDestroy.add(new MageObjectReference(attachment, game)); + oozeEquipmentsToDestroy.put(entry.getKey(), toDestroy); + } + } + } + } + } + } + } + } + } + + private boolean hasAttachedEquipment(Game game, Permanent permanent) { + for (UUID attachmentId : permanent.getAttachments()) { + Permanent attachment = game.getPermanent(attachmentId); + if (attachment != null && attachment.hasSubtype(SubType.EQUIPMENT, game)) { + return true; + } + } + return false; + } + + public Set getRelatedBlockedCreatures(MageObjectReference ooze) { + Set relatedCreatures = this.oozeBlocksOrBlocked.get(ooze); + oozeBlocksOrBlocked.remove(ooze); // remove here to get no overlap with creatures leaving meanwhile + return relatedCreatures; + } + + public Set getEquipmentsToDestroy(MageObjectReference ooze) { + Set equipmentsToDestroy = this.oozeEquipmentsToDestroy.get(ooze); + oozeEquipmentsToDestroy.remove(ooze); // remove here to get no overlap with creatures leaving meanwhile + return equipmentsToDestroy; + } + + @Override + public CorrosiveOozeCombatWatcher copy() { + return new CorrosiveOozeCombatWatcher(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/r/ReflectorMage.java b/Mage.Sets/src/mage/cards/r/ReflectorMage.java index 1eadff8017..9046d789fd 100644 --- a/Mage.Sets/src/mage/cards/r/ReflectorMage.java +++ b/Mage.Sets/src/mage/cards/r/ReflectorMage.java @@ -38,10 +38,9 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.constants.PhaseStep; +import mage.constants.SubType; import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; @@ -50,7 +49,6 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.stack.Spell; -import mage.game.turn.Step; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; @@ -67,7 +65,7 @@ public class ReflectorMage extends CardImpl { } public ReflectorMage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(2); @@ -128,7 +126,7 @@ class ExclusionRitualReplacementEffect extends ContinuousRuleModifyingEffectImpl private final UUID ownerId; ExclusionRitualReplacementEffect(String creatureName, UUID ownerId) { - super(Duration.Custom, Outcome.Detriment); + super(Duration.UntilYourNextTurn, Outcome.Detriment); staticText = "That creature's owner can't cast spells with the same name as that creature until your next turn"; this.creatureName = creatureName; this.ownerId = ownerId; @@ -158,16 +156,6 @@ class ExclusionRitualReplacementEffect extends ContinuousRuleModifyingEffectImpl return false; } - @Override - public boolean isInactive(Ability source, Game game) { - if (game.getPhase().getStep().getType() == PhaseStep.UNTAP && game.getStep().getStepPart() == Step.StepPart.PRE) { - if (game.getActivePlayerId().equals(source.getControllerId()) || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving()) { - return true; - } - } - return false; - } - @Override public boolean apply(Game game, Ability source) { return false;