Rework Infectious Rage (#10625)

* put custom predicate back with Aura Graft

* Rework Infectious Rage and add unit test

* cleanup Aura Graft
This commit is contained in:
xenohedron 2023-07-15 16:49:26 -04:00 committed by GitHub
parent d11269cb56
commit e2cff095b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 109 additions and 85 deletions

View file

@ -1,9 +1,7 @@
package mage.cards.a;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
import mage.cards.CardImpl;
@ -12,35 +10,37 @@ import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.Filter;
import mage.filter.FilterPermanent;
import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.filter.predicate.permanent.PermanentCanBeAttachedToPredicate;
import mage.filter.predicate.permanent.CanBeEnchantedByPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetPermanent;
import mage.util.TargetAddress;
/**
* @author duncant
*/
public final class AuraGraft extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("Aura that's attached to a permanent");
static {
filter.add(SubType.AURA.getPredicate());
filter.add(AuraGraftAttachedToPermanentPredicate.instance);
}
public AuraGraft(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}");
// Gain control of target Aura that's attached to a permanent. Attach it to another permanent it can enchant.
FilterPermanent filter = new FilterPermanent("Aura that's attached to a permanent");
filter.add(SubType.AURA.getPredicate());
filter.add(new AttachedToPermanentPredicate());
this.getSpellAbility().addTarget(new TargetPermanent(filter));
Effect gainControlEffect = new GainControlTargetEffect(Duration.EndOfGame);
this.getSpellAbility().addEffect(gainControlEffect);
this.getSpellAbility().addEffect(new MoveTargetAuraEffect());
this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfGame));
this.getSpellAbility().addEffect(new AuraGraftMoveAuraEffect());
}
private AuraGraft(final AuraGraft card) {
@ -53,11 +53,8 @@ public final class AuraGraft extends CardImpl {
}
}
class AttachedToPermanentPredicate implements ObjectSourcePlayerPredicate<Permanent> {
public AttachedToPermanentPredicate() {
super();
}
enum AuraGraftAttachedToPermanentPredicate implements ObjectSourcePlayerPredicate<Permanent> {
instance;
public boolean apply(ObjectSourcePlayer<Permanent> input, Game game) {
Permanent attached = input.getObject();
@ -65,49 +62,68 @@ class AttachedToPermanentPredicate implements ObjectSourcePlayerPredicate<Perman
}
}
class MoveTargetAuraEffect extends OneShotEffect {
class AuraGraftAuraCanEnchantPredicate implements ObjectSourcePlayerPredicate<Permanent> {
public MoveTargetAuraEffect() {
protected Permanent aura;
AuraGraftAuraCanEnchantPredicate(Permanent aura) {
super();
this.aura = aura;
}
@Override
public boolean apply(ObjectSourcePlayer<Permanent> input, Game game) {
Permanent potentialAttachment = input.getObject();
for (TargetAddress addr : TargetAddress.walk(aura)) {
Target target = addr.getTarget(aura);
Filter filter = target.getFilter();
return filter.match(potentialAttachment, game);
}
return false;
}
}
class AuraGraftMoveAuraEffect extends OneShotEffect {
AuraGraftMoveAuraEffect() {
super(Outcome.Benefit);
staticText = "Attach it to another permanent it can enchant";
}
public MoveTargetAuraEffect(final MoveTargetAuraEffect effect) {
private AuraGraftMoveAuraEffect(final AuraGraftMoveAuraEffect effect) {
super(effect);
}
@Override
public MoveTargetAuraEffect copy() {
return new MoveTargetAuraEffect(this);
public AuraGraftMoveAuraEffect copy() {
return new AuraGraftMoveAuraEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent enchantment = game.getPermanent(targetPointer.getFirst(game, source));
if (enchantment == null) {
return false;
}
Permanent oldAttachment = game.getPermanent(enchantment.getAttachedTo());
if (oldAttachment == null) {
return false;
}
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
if (enchantment == null || controller == null) {
return false;
}
Permanent previouslyEnchanted = game.getPermanent(enchantment.getAttachedTo());
if (previouslyEnchanted == null) {
return false;
}
FilterPermanent filter = new FilterPermanent("another permanent " + enchantment.getLogName() + " can enchant");
filter.add(AnotherPredicate.instance);
filter.add(new PermanentCanBeAttachedToPredicate(enchantment));
filter.add(new AuraGraftAuraCanEnchantPredicate(enchantment)); // extracts Targets from Aura spell ability
filter.add(new CanBeEnchantedByPredicate(enchantment)); // checks for protection
Target target = new TargetPermanent(filter);
target.setNotTarget(true);
if (target.canChoose(controller.getId(), source, game)
&& controller.choose(outcome, target, source, game)) {
Permanent newAttachment = game.getPermanent(target.getFirstTarget());
if (newAttachment != null
&& oldAttachment.removeAttachment(enchantment.getId(), source, game)) {
&& previouslyEnchanted.removeAttachment(enchantment.getId(), source, game)) {
newAttachment.addAttachment(enchantment.getId(), source, game);
game.informPlayers(enchantment.getLogName() + " was unattached from " + oldAttachment.getLogName() + " and attached to " + newAttachment.getLogName());
game.informPlayers(enchantment.getLogName() + " was unattached from " + previouslyEnchanted.getLogName() + " and attached to " + newAttachment.getLogName());
return true;
}
}

View file

@ -11,8 +11,8 @@ import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.predicate.permanent.PermanentCanBeAttachedToPredicate;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.CanBeEnchantedByPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
@ -80,32 +80,28 @@ class InfectiousRageReattachEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Card auraCard = game.getCard(source.getSourceId());
Permanent auraPermanent = source.getSourcePermanentOrLKI(game);
if (controller == null || auraCard == null || auraPermanent == null) {
if (controller == null || auraCard == null) {
return false;
}
if (source.getSourceObjectZoneChangeCounter() != auraCard.getZoneChangeCounter(game)) {
return false;
}
FilterPermanent filter = new FilterPermanent();
filter.add(CardType.CREATURE.getPredicate());
filter.add(new PermanentCanBeAttachedToPredicate(auraPermanent)); // Doesn't yet exclude creatures with protection abilities
FilterCreaturePermanent filter = new FilterCreaturePermanent();
filter.add(new CanBeEnchantedByPredicate(auraCard));
List<Permanent> permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game);
if (!permanents.isEmpty()) {
Permanent creature = RandomUtil.randomFromCollection(permanents);
if (creature != null) {
game.getState().setValue("attachTo:" + auraCard.getId(), creature);
controller.moveCards(auraCard, Zone.BATTLEFIELD, source, game);
return creature.addAttachment(auraCard.getId(), source, game);
}
if (permanents.isEmpty()) {
game.informPlayers("No valid creatures for " + auraCard.getLogName() + "to enchant.");
return false;
}
else {
game.informPlayers("No valid creatures for " + auraPermanent.getLogName() + "to enchant.");
Permanent creature = RandomUtil.randomFromCollection(permanents);
if (creature == null) {
return false;
}
return false;
game.getState().setValue("attachTo:" + auraCard.getId(), creature);
controller.moveCards(auraCard, Zone.BATTLEFIELD, source, game);
return creature.addAttachment(auraCard.getId(), source, game);
}

View file

@ -0,0 +1,47 @@
package org.mage.test.cards.enchantments;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author xenohedron
*/
public class AuraAttachTest extends CardTestPlayerBase {
@Test
public void testInfectiousRage() {
/*
* Infectious Rage {1}{R}
* Enchant creature
* Enchanted creature gets +2/-1.
* When enchanted creature dies, choose a creature at random Infectious Rage can enchant.
* Return Infectious Rage to the battlefield attached to that creature.
*/
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
addCard(Zone.BATTLEFIELD, playerA, "Pensive Minotaur", 1); // 2/3 (vanilla)
addCard(Zone.BATTLEFIELD, playerB, "Slippery Bogle", 1); // 1/1 hexproof
addCard(Zone.BATTLEFIELD, playerB, "Thermal Glider", 1); // 2/1 flying, protection from red
addCard(Zone.HAND, playerA, "Infectious Rage", 1);
addCard(Zone.HAND, playerA, "Shock", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Infectious Rage", "Pensive Minotaur");
// Minotaur is now a 4/2
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shock", "Pensive Minotaur");
// Minotaur dies. Infectious Rage triggers, only legal creature to enchant is Slippery Bogle
// Bogle dies. // Infectious Rage triggers, Thermal Glider can't be enchanted by it, so it remains in graveyard
setStrictChooseMode(true);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerA, "Pensive Minotaur", 1);
assertGraveyardCount(playerA, "Infectious Rage", 1);
assertGraveyardCount(playerA, "Shock", 1);
assertGraveyardCount(playerB, "Slippery Bogle", 1);
assertPermanentCount(playerB, "Thermal Glider", 1);
}
}

View file

@ -1,35 +0,0 @@
package mage.filter.predicate.permanent;
import mage.filter.Filter;
import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.Target;
import mage.util.TargetAddress;
/**
* @author duncant
*/
public class PermanentCanBeAttachedToPredicate implements ObjectSourcePlayerPredicate<Permanent> {
protected Permanent aura;
public PermanentCanBeAttachedToPredicate(Permanent aura) {
super();
this.aura = aura;
}
@Override
public boolean apply(ObjectSourcePlayer<Permanent> input, Game game) {
// TODO: Is it possible to add functionality to exclude objects the aura can't enchant (e.g. protection from)?
Permanent potentialAttachment = input.getObject();
for (TargetAddress addr : TargetAddress.walk(aura)) {
Target target = addr.getTarget(aura);
Filter filter = target.getFilter();
return filter.match(potentialAttachment, game);
}
return false;
}
}