diff --git a/Mage.Sets/src/mage/cards/a/AbandonReason.java b/Mage.Sets/src/mage/cards/a/AbandonReason.java index a34140c11b6..63e6f1bd479 100644 --- a/Mage.Sets/src/mage/cards/a/AbandonReason.java +++ b/Mage.Sets/src/mage/cards/a/AbandonReason.java @@ -12,6 +12,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.Outcome; import mage.target.common.TargetCreaturePermanent; /** @@ -25,6 +26,7 @@ public final class AbandonReason extends CardImpl { // Up to two target creatures each get +1/+0 and gain first strike until end of turn. Effect effect = new BoostTargetEffect(1, 0, Duration.EndOfTurn); + effect.setOutcome(Outcome.Benefit); effect.setText("Up to two target creatures each get +1/+0"); this.getSpellAbility().addEffect(effect); effect = new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn, "and gain first strike until end of turn"); diff --git a/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java b/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java index 0f065a31274..4d8298f83d5 100644 --- a/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java +++ b/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java @@ -17,9 +17,12 @@ import mage.game.Game; import mage.players.Player; import mage.util.CardUtil; import mage.watchers.common.AttackedThisTurnWatcher; - import java.util.Objects; import java.util.UUID; +import mage.abilities.decorator.ConditionalAsThoughEffect; +import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; +import mage.abilities.effects.common.asthought.YouMaySpendManaAsAnyColorToCastTargetEffect; +import mage.target.targetpointer.FixedTarget; /** * @author TheElk801 @@ -49,7 +52,7 @@ public final class RobberOfTheRich extends CardImpl { "if defending player has more cards in hand than you, exile the top card of their library. " + "During any turn you attacked with a Rogue, you may cast that card and " + "you may spend mana as though it were mana of any color to cast that spell." - ).addHint(new ConditionHint(RobberOfTheRichAnyTurnAttackedCondition.instance)), new AttackedThisTurnWatcher()); + ).addHint(new ConditionHint(new RogueAttackedThisTurnCondition(null))), new AttackedThisTurnWatcher()); } private RobberOfTheRich(final RobberOfTheRich card) { @@ -69,24 +72,36 @@ enum RobberOfTheRichAttacksCondition implements Condition { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(game.getCombat().getDefendingPlayerId(source.getSourceId(), game)); - return controller != null && player != null && controller.getHand().size() < player.getHand().size(); + return controller != null + && player != null + && controller.getHand().size() < player.getHand().size(); } } -enum RobberOfTheRichAnyTurnAttackedCondition implements Condition { - instance; +class RogueAttackedThisTurnCondition implements Condition { + + private Ability ability; + + RogueAttackedThisTurnCondition(Ability source) { + this.ability = source; + } @Override public boolean apply(Game game, Ability source) { + // in case the Robber leaves the battlefield, the ability must be referenced for controller information + if (ability == null) { + ability = source; + } // your turn - if (!source.isControlledBy(game.getActivePlayerId())) { + if (!ability.isControlledBy(game.getActivePlayerId())) { return false; } // attacked with Rogue + // note that the MOR object doesn't work well with LKI call when checking for the subtype, thus we check the LKI permanent in the battlefield AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); - return watcher != null && watcher.getAttackedThisTurnCreatures() + return watcher != null && watcher.getAttackedThisTurnCreaturesPermanentLKI() .stream() - .map(mor -> mor.getPermanentOrLKIBattlefield(game)) + .map(permanent -> permanent) .filter(Objects::nonNull) .anyMatch(permanent -> permanent.hasSubtype(SubType.ROGUE, game)); } @@ -100,7 +115,7 @@ enum RobberOfTheRichAnyTurnAttackedCondition implements Condition { class RobberOfTheRichEffect extends OneShotEffect { RobberOfTheRichEffect() { - super(Outcome.PutCreatureInPlay); + super(Outcome.Benefit); } private RobberOfTheRichEffect(final RobberOfTheRichEffect effect) { @@ -116,7 +131,8 @@ class RobberOfTheRichEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Player damagedPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); - if (controller == null || damagedPlayer == null) { + if (controller == null + || damagedPlayer == null) { return false; } Card card = damagedPlayer.getLibrary().getFromTop(game); @@ -125,13 +141,26 @@ class RobberOfTheRichEffect extends OneShotEffect { } // move card to exile controller.moveCardsToExile(card, source, game, true, CardUtil.getExileZoneId(game, source), CardUtil.getSourceName(game, source)); - // Add effects only if the card has a spellAbility (e.g. not for lands). + // add the effects to the exiled card directly + // don't worry about land if (card.getSpellAbility() != null) { - // allow to cast the card - // and you may spend mana as though it were mana of any color to cast it - CardUtil.makeCardPlayable(game, source, card, Duration.Custom, true, null, RobberOfTheRichAnyTurnAttackedCondition.instance); + // the exiled card is independent and requires a new ability in case the Robber leaves the battlefield + // the exiled card can be cast throughout the entire game as long as the controller attacked with a rogue that turn + Ability copiedAbility = source.copy(); + copiedAbility.newId(); + copiedAbility.setSourceId(card.getId()); + copiedAbility.setControllerId(source.getControllerId()); + PlayFromNotOwnHandZoneTargetEffect playFromExile = new PlayFromNotOwnHandZoneTargetEffect(Zone.EXILED, Duration.EndOfGame); + YouMaySpendManaAsAnyColorToCastTargetEffect spendAnyMana = new YouMaySpendManaAsAnyColorToCastTargetEffect(Duration.EndOfGame); + ConditionalAsThoughEffect castOnlyIfARogueAttackedThisTurn = new ConditionalAsThoughEffect(playFromExile, new RogueAttackedThisTurnCondition(copiedAbility)); + playFromExile.setTargetPointer(new FixedTarget(card, game)); + spendAnyMana.setTargetPointer(new FixedTarget(card, game)); + castOnlyIfARogueAttackedThisTurn.setTargetPointer(new FixedTarget(card, game)); + game.addEffect(castOnlyIfARogueAttackedThisTurn, copiedAbility); + game.addEffect(spendAnyMana, copiedAbility); + return true; } - return true; + return false; } } diff --git a/Mage.Sets/src/mage/cards/r/RubblebeltMaaka.java b/Mage.Sets/src/mage/cards/r/RubblebeltMaaka.java index 1508fd3f519..5162436657a 100644 --- a/Mage.Sets/src/mage/cards/r/RubblebeltMaaka.java +++ b/Mage.Sets/src/mage/cards/r/RubblebeltMaaka.java @@ -4,6 +4,7 @@ package mage.cards.r; import java.util.UUID; import mage.MageInt; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.keyword.BloodrushAbility; import mage.cards.CardImpl; @@ -11,6 +12,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.Outcome; /** * @@ -28,7 +30,9 @@ public final class RubblebeltMaaka extends CardImpl { this.toughness = new MageInt(3); // Bloodrush — {R}, Discard Rubblebelt Maaka: Target attacking creature gets +3/+3 until end of turn. - this.addAbility(new BloodrushAbility("{R}", new BoostTargetEffect(3,3, Duration.EndOfTurn))); + Effect boostEffect = new BoostTargetEffect(3,3, Duration.EndOfTurn); + boostEffect.setOutcome(Outcome.Benefit); + this.addAbility(new BloodrushAbility("{R}", boostEffect)); } diff --git a/Mage/src/main/java/mage/watchers/common/AttackedThisTurnWatcher.java b/Mage/src/main/java/mage/watchers/common/AttackedThisTurnWatcher.java index aa74dad37fb..b199c5b431a 100644 --- a/Mage/src/main/java/mage/watchers/common/AttackedThisTurnWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/AttackedThisTurnWatcher.java @@ -19,6 +19,9 @@ public class AttackedThisTurnWatcher extends Watcher { private final Set attackedThisTurnCreatures = new HashSet<>(); private final Map attackedThisTurnCreaturesCounts = new HashMap<>(); + + // issue with Robber of the Rich. it needs to check the subtype of the LKI of the permanent on the battlefield and this fails with MageObjectReference + private final Set attackedThisTurnCreaturesPermanentLKI = new HashSet<>(); public AttackedThisTurnWatcher() { super(WatcherScope.GAME); @@ -28,9 +31,13 @@ public class AttackedThisTurnWatcher extends Watcher { public void watch(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED) { MageObjectReference mor = new MageObjectReference(event.getSourceId(), game); + Permanent permanentOnBattlefield = game.getPermanentOrLKIBattlefield(event.getSourceId()); this.attackedThisTurnCreatures.add(mor); this.attackedThisTurnCreaturesCounts.putIfAbsent(mor, 0); this.attackedThisTurnCreaturesCounts.compute(mor, (k, v) -> (v + 1)); + + // bug with Robber of the Rich as noted above + this.attackedThisTurnCreaturesPermanentLKI.add(permanentOnBattlefield); } } @@ -54,11 +61,16 @@ public class AttackedThisTurnWatcher extends Watcher { } return false; } + + public Set getAttackedThisTurnCreaturesPermanentLKI() { + return this.attackedThisTurnCreaturesPermanentLKI; + } @Override public void reset() { super.reset(); this.attackedThisTurnCreatures.clear(); this.attackedThisTurnCreaturesCounts.clear(); + this.getAttackedThisTurnCreaturesPermanentLKI().clear(); } }