* Deals damage divided as you choose - fixed that some cards can't choose planeswalkers (example: Arc Lightning, see #7276);

Refactor: simplified FilterCreaturePlayerOrPlaneswalker to use single permanent filter;
This commit is contained in:
Oleg Agafonov 2020-12-23 02:31:41 +04:00
parent 347a3b1e1a
commit 255c292104
18 changed files with 162 additions and 222 deletions

View file

@ -1,16 +1,10 @@
package mage.player.ai;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
import mage.ApprovingObject;
import mage.ConditionalMana;
import mage.MageObject;
import mage.Mana;
import mage.abilities.*;
import mage.abilities.costs.AlternativeSourceCosts;
import mage.abilities.costs.OptionalAdditionalSourceCosts;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.mana.*;
import mage.abilities.effects.Effect;
@ -42,7 +36,6 @@ import mage.game.combat.CombatGroup;
import mage.game.draft.Draft;
import mage.game.draft.RateCard;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.match.Match;
import mage.game.permanent.Permanent;
import mage.game.stack.Spell;
@ -63,6 +56,11 @@ import mage.util.TournamentUtil;
import mage.util.TreeNode;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
/**
* suitable for two player games and some multiplayer games
*
@ -270,9 +268,9 @@ public class ComputerPlayer extends PlayerImpl implements Player {
List<Permanent> targets;
TargetAnyTarget origTarget = (TargetAnyTarget) target.getOriginalTarget();
if (outcome.isGood()) {
targets = threats(abilityControllerId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
targets = threats(abilityControllerId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
} else {
targets = threats(randomOpponentId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
targets = threats(randomOpponentId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
}
for (Permanent permanent : targets) {
List<UUID> alreadyTargetted = target.getTargets();
@ -651,9 +649,9 @@ public class ComputerPlayer extends PlayerImpl implements Player {
List<Permanent> targets;
TargetAnyTarget origTarget = ((TargetAnyTarget) target.getOriginalTarget());
if (outcome.isGood()) {
targets = threats(abilityControllerId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
targets = threats(abilityControllerId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
} else {
targets = threats(randomOpponentId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
targets = threats(randomOpponentId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
}
if (targets.isEmpty()) {
@ -667,7 +665,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
if (targets.isEmpty() && required) {
targets = game.getBattlefield().getActivePermanents(((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getCreatureFilter(), playerId, game);
targets = game.getBattlefield().getActivePermanents(((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), playerId, game);
}
for (Permanent permanent : targets) {
List<UUID> alreadyTargeted = target.getTargets();

View file

@ -33,9 +33,8 @@ public final class ArcTrail extends CardImpl {
this.getSpellAbility().addTarget(target1);
FilterCreaturePlayerOrPlaneswalker filter2 = new FilterCreaturePlayerOrPlaneswalker("another creature, player or planeswalker to deal 1 damage");
AnotherTargetPredicate predicate = new AnotherTargetPredicate(2);
filter2.getCreatureFilter().add(predicate);
filter2.getPlayerFilter().add(predicate);
filter2.getPermanentFilter().add(new AnotherTargetPredicate(2));
filter2.getPlayerFilter().add(new AnotherTargetPredicate(2));
TargetAnyTarget target2 = new TargetAnyTarget(1, 1, filter2);
target2.setTargetTag(2);
this.getSpellAbility().addTarget(target2);

View file

@ -32,14 +32,12 @@ public final class BondOfPassion extends CardImpl {
private static final FilterPermanent filter
= new FilterCreaturePermanent();
private static final FilterCreaturePlayerOrPlaneswalker filter2
private static final FilterCreaturePlayerOrPlaneswalker otherFilter
= new FilterCreaturePlayerOrPlaneswalker("any other target");
static {
filter.add(new AnotherTargetPredicate(1));
filter2.getCreatureFilter().add(new AnotherTargetPredicate(2));
filter2.getPlaneswalkerFilter().add(new AnotherTargetPredicate(2));
filter2.getPlayerFilter().add(new AnotherTargetPredicate(2));
otherFilter.getPlayerFilter().add(new AnotherTargetPredicate(2));
otherFilter.getPlayerFilter().add(new AnotherTargetPredicate(2));
}
public BondOfPassion(UUID ownerId, CardSetInfo setInfo) {
@ -50,7 +48,7 @@ public final class BondOfPassion extends CardImpl {
Target target = new TargetPermanent(filter);
target.setTargetTag(1);
this.getSpellAbility().addTarget(target);
target = new TargetAnyTarget(filter2);
target = new TargetAnyTarget(otherFilter);
target.setTargetTag(2);
this.getSpellAbility().addTarget(target);
}

View file

@ -1,7 +1,5 @@
package mage.cards.c;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
@ -18,12 +16,12 @@ import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.common.FilterCreaturePlayerOrPlaneswalker;
import mage.target.common.TargetAnyTarget;
import java.util.UUID;
/**
*
* @author anonymous
*/
public final class CauterySliver extends CardImpl {
@ -43,10 +41,12 @@ public final class CauterySliver extends CardImpl {
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD,
new GainAbilityAllEffect(ability1, Duration.WhileOnBattlefield, filter,
"All Slivers have \"{1}, Sacrifice this permanent: This permanent deals 1 damage to any target.\"")));
// All Slivers have "{1}, Sacrifice this permanent: Prevent the next 1 damage that would be dealt to target Sliver creature or player this turn."
// All Slivers have "{1}, Sacrifice this permanent: Prevent the next 1 damage that would be dealt to target player, planeswalker, or Sliver creature this turn."
Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventDamageToTargetEffect(Duration.EndOfTurn, 1), new ManaCostsImpl("1"));
ability2.addCost(new SacrificeSourceCost());
ability2.addTarget(new TargetSliverCreatureOrPlayer());
ability2.addTarget(new TargetAnyTarget(new FilterCreatureOrPlayerByType(SubType.SLIVER, "Sliver creature or player")));
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD,
new GainAbilityAllEffect(ability2, Duration.WhileOnBattlefield, filter,
"All Slivers have \"{1}, Sacrifice this permanent: Prevent the next 1 damage that would be dealt to target Sliver creature or player this turn.\"")));
@ -62,18 +62,10 @@ public final class CauterySliver extends CardImpl {
}
}
class TargetSliverCreatureOrPlayer extends TargetAnyTarget {
public TargetSliverCreatureOrPlayer() {
super();
filter = new FilterCreatureOrPlayerByType("Sliver", "Sliver creature or player");
}
}
class FilterCreatureOrPlayerByType extends FilterCreaturePlayerOrPlaneswalker {
public FilterCreatureOrPlayerByType(String type, String name) {
public FilterCreatureOrPlayerByType(SubType subType, String name) {
super(name);
creatureFilter = new FilterCreaturePermanent(type);
this.getPermanentFilter().add(subType.getPredicate());
}
}

View file

@ -24,24 +24,23 @@ public final class ConeOfFlame extends CardImpl {
public ConeOfFlame(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}{R}");
// Cone of Flame deals 1 damage to any target, 2 damage to another any target, and 3 damage to a third any target.
FilterCreaturePlayerOrPlaneswalker filter1 = new FilterCreaturePlayerOrPlaneswalker("creature, player or planeswalker to deal 1 damage");
// Cone of Flame deals 1 damage to any target, 2 damage to another target, and 3 damage to a third target.
// 1
FilterCreaturePlayerOrPlaneswalker filter1 = new FilterCreaturePlayerOrPlaneswalker("any target to deal 1 damage");
TargetAnyTarget target1 = new TargetAnyTarget(1, 1, filter1);
target1.setTargetTag(1);
this.getSpellAbility().addTarget(target1);
FilterCreaturePlayerOrPlaneswalker filter2 = new FilterCreaturePlayerOrPlaneswalker("another creature, player or planeswalker to deal 2 damage");
AnotherTargetPredicate predicate2 = new AnotherTargetPredicate(2);
filter2.getCreatureFilter().add(predicate2);
filter2.getPlayerFilter().add(predicate2);
// 2
FilterCreaturePlayerOrPlaneswalker filter2 = new FilterCreaturePlayerOrPlaneswalker("another target to deal 2 damage");
filter2.getPermanentFilter().add(new AnotherTargetPredicate(2));
filter2.getPlayerFilter().add(new AnotherTargetPredicate(2));
TargetAnyTarget target2 = new TargetAnyTarget(1, 1, filter2);
target2.setTargetTag(2);
this.getSpellAbility().addTarget(target2);
FilterCreaturePlayerOrPlaneswalker filter3 = new FilterCreaturePlayerOrPlaneswalker("another creature, player or planeswalker to deal 3 damage");
AnotherTargetPredicate predicate3 = new AnotherTargetPredicate(3);
filter3.getCreatureFilter().add(predicate3);
filter3.getPlayerFilter().add(predicate3);
// 3
FilterCreaturePlayerOrPlaneswalker filter3 = new FilterCreaturePlayerOrPlaneswalker("third target to deal 3 damage");
filter3.getPermanentFilter().add(new AnotherTargetPredicate(3));
filter3.getPlayerFilter().add(new AnotherTargetPredicate(3));
TargetAnyTarget target3 = new TargetAnyTarget(1, 1, filter3);
target3.setTargetTag(3);
this.getSpellAbility().addTarget(target3);

View file

@ -43,9 +43,8 @@ public final class DrakusethMawOfFlames extends CardImpl {
target.setTargetTag(1);
ability.addTarget(target);
FilterCreaturePlayerOrPlaneswalker filter = new FilterCreaturePlayerOrPlaneswalker("any target");
filter.getCreatureFilter().add(new AnotherTargetPredicate(2, true));
filter.getPlayerFilter().add(new AnotherTargetPredicate(2, true));
filter.getPlaneswalkerFilter().add(new AnotherTargetPredicate(2, true));
filter.getPermanentFilter().add(new AnotherTargetPredicate(2, true));
target = new TargetAnyTarget(0, 2, filter).withChooseHint("to deal 3 damage");
target.setTargetTag(2);
ability.addTarget(target);

View file

@ -1,7 +1,5 @@
package mage.cards.e;
import java.util.UUID;
import mage.abilities.effects.common.PreventAllDamageToAllEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -10,26 +8,26 @@ import mage.constants.Duration;
import mage.constants.TargetController;
import mage.filter.common.FilterCreaturePlayerOrPlaneswalker;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public final class Endure extends CardImpl {
private static final FilterCreaturePlayerOrPlaneswalker filter = new FilterCreaturePlayerOrPlaneswalker("you and permanents you control");
static {
filter.getCreatureFilter().add(TargetController.YOU.getControllerPredicate());
filter.getPermanentFilter().add(TargetController.YOU.getControllerPredicate());
filter.getPlayerFilter().add(TargetController.YOU.getPlayerPredicate());
}
public Endure(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{W}{W}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{W}{W}");
// Prevent all damage that would be dealt to you and permanents you control this turn.
this.getSpellAbility().addEffect(new PreventAllDamageToAllEffect(Duration.EndOfTurn, filter));
}
public Endure(final Endure card) {

View file

@ -1,7 +1,5 @@
package mage.cards.i;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
@ -16,17 +14,15 @@ import mage.constants.Zone;
import mage.filter.common.FilterCreaturePlayerOrPlaneswalker;
import mage.target.common.TargetAnyTarget;
import java.util.UUID;
/**
*
* @author Styxo
*/
public final class ImperialGunner extends CardImpl {
private static final FilterCreaturePlayerOrPlaneswalker filter = new FilterCreaturePlayerOrPlaneswalker("target player, planeswalker or Starship creature");
static {
filter.getCreatureFilter().add(SubType.STARSHIP.getPredicate());
}
private static final FilterCreaturePlayerOrPlaneswalker filter = new FilterCreaturePlayerOrPlaneswalker(
"target player, planeswalker or Starship creature", SubType.STARSHIP);
public ImperialGunner(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}");
@ -35,7 +31,7 @@ public final class ImperialGunner extends CardImpl {
this.power = new MageInt(1);
this.toughness = new MageInt(2);
// {1},{T}:Imperial Gunner deals 1 damage to target player or Starship creature.
// {1},{T}: Imperial Gunner deals 1 damage to target player or Starship creature.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new ManaCostsImpl("{1}"));
ability.addTarget(new TargetAnyTarget(filter));
ability.addCost(new TapSourceCost());

View file

@ -1,7 +1,5 @@
package mage.cards.n;
import java.util.UUID;
import mage.MageItem;
import mage.MageObject;
import mage.abilities.effects.Effect;
@ -17,18 +15,18 @@ import mage.players.Player;
import mage.target.common.TargetAnyTarget;
import mage.watchers.common.DamageDoneWatcher;
import java.util.UUID;
/**
*
* @author Quercitron
*/
public final class NeedleDrop extends CardImpl {
private static final FilterCreaturePlayerOrPlaneswalker FILTER = new FilterCreaturePlayerOrPlaneswalker();
private static final FilterCreaturePlayerOrPlaneswalker filer = new FilterCreaturePlayerOrPlaneswalker();
static {
FILTER.getCreatureFilter().add(new DamagedThisTurnPredicate());
FILTER.getPlaneswalkerFilter().add(new DamagedThisTurnPredicate());
FILTER.getPlayerFilter().add(new DamagedThisTurnPredicate());
filer.getPlayerFilter().add(new DamagedThisTurnPredicate());
filer.getPermanentFilter().add(new DamagedThisTurnPredicate());
}
public NeedleDrop(UUID ownerId, CardSetInfo setInfo) {
@ -38,7 +36,7 @@ public final class NeedleDrop extends CardImpl {
Effect effect = new DamageTargetEffect(1);
effect.setText("{this} deals 1 damage to any target that was dealt damage this turn");
this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetAnyTarget(1, 1, FILTER));
this.getSpellAbility().addTarget(new TargetAnyTarget(1, 1, filer));
// Draw a card.
this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1));

View file

@ -7,6 +7,7 @@ import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.ExileAllEffect;
import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect;
import mage.cards.*;
import mage.constants.*;
import mage.filter.FilterCard;
@ -20,27 +21,25 @@ import mage.target.Target;
import mage.target.common.TargetAnyTarget;
import mage.target.common.TargetCardInHand;
import mage.target.common.TargetOpponent;
import mage.target.targetpointer.FixedTarget;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect;
import mage.target.targetpointer.FixedTarget;
/**
* @author Will
*/
public final class NicolBolasGodPharaoh extends CardImpl {
private static final FilterPermanent filter = new FilterNonlandPermanent();
private static final FilterCreaturePlayerOrPlaneswalker filter2
private static final FilterCreaturePlayerOrPlaneswalker damageFilter
= new FilterCreaturePlayerOrPlaneswalker("opponent, creature an opponent controls, or planeswalker an opponent controls.");
private static final FilterPermanent exileFilter = new FilterNonlandPermanent();
static {
filter.add(TargetController.OPPONENT.getControllerPredicate());
filter2.getPlayerFilter().add(TargetController.OPPONENT.getPlayerPredicate());
filter2.getCreatureFilter().add(TargetController.OPPONENT.getControllerPredicate());
filter2.getPlaneswalkerFilter().add(TargetController.OPPONENT.getControllerPredicate());
damageFilter.getPlayerFilter().add(TargetController.OPPONENT.getPlayerPredicate());
damageFilter.getPermanentFilter().add(TargetController.OPPONENT.getControllerPredicate());
exileFilter.add(TargetController.OPPONENT.getControllerPredicate());
}
public NicolBolasGodPharaoh(UUID ownerId, CardSetInfo setInfo) {
@ -58,13 +57,13 @@ public final class NicolBolasGodPharaoh extends CardImpl {
// +1: Each opponent exiles two cards from their hand.
this.addAbility(new LoyaltyAbility(new NicolBolasGodPharaohPlusOneEffect(), 1));
// -4: Nicol Bolas, God-Pharaoh deals 7 damage to any target.
// -4: Nicol Bolas, God-Pharaoh deals 7 damage to target opponent, creature an opponent controls, or planeswalker an opponent controls.
ability = new LoyaltyAbility(new DamageTargetEffect(7), -4);
ability.addTarget(new TargetAnyTarget(filter2));
ability.addTarget(new TargetAnyTarget(damageFilter));
this.addAbility(ability);
// -12: Exile each nonland permanent your opponents control.
this.addAbility(new LoyaltyAbility(new ExileAllEffect(filter)
this.addAbility(new LoyaltyAbility(new ExileAllEffect(exileFilter)
.setText("exile each nonland permanent your opponents control"), -12));
}
@ -168,7 +167,7 @@ class NicolBolasGodPharaohPlusTwoEffect extends OneShotEffect {
if (card.isLand()) {
continue;
}
ContinuousEffect effect = new PlayFromNotOwnHandZoneTargetEffect(Zone.EXILED, TargetController.YOU, Duration.EndOfTurn, true);
ContinuousEffect effect = new PlayFromNotOwnHandZoneTargetEffect(Zone.EXILED, TargetController.YOU, Duration.EndOfTurn, true);
effect.setTargetPointer(new FixedTarget(card, game));
game.addEffect(effect, source);
break;

View file

@ -1,7 +1,5 @@
package mage.cards.t;
import java.util.UUID;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DamageMultiEffect;
import mage.cards.CardImpl;
@ -9,21 +7,21 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.target.common.TargetAnyTargetAmount;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class TwinBolt extends CardImpl {
public TwinBolt(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{R}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}");
// Twin Bolt deals 2 damage divided as you choose among one or two target creatures and/or players.
Effect effect = new DamageMultiEffect(2);
effect.setText("{this} deals 2 damage divided as you choose among one or two target creatures and/or players");
this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetAnyTargetAmount(2));
}
public TwinBolt(final TwinBolt card) {

View file

@ -0,0 +1,39 @@
package org.mage.test.cards.single.m11;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author JayDi85
*/
public class InfernoTitanTest extends CardTestPlayerBase {
@Test
public void test_MustAbleToTargetPlaneswalkers() {
// bug: https://github.com/magefree/mage/issues/7276
// Whenever Inferno Titan enters the battlefield or attacks, it deals 3 damage divided as you choose among one, two, or three targets.
addCard(Zone.HAND, playerA, "Inferno Titan"); // {4}{R}{R}
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6);
//
addCard(Zone.BATTLEFIELD, playerA, "Chandra, Acolyte of Flame", 1); // 4
addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); // 2/2
// cast and devide damage (2x to creature and 1x to planeswalker)
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Inferno Titan");
addTargetAmount(playerA, "Grizzly Bears", 2);
addTargetAmount(playerA, "Chandra, Acolyte of Flame", 1);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Inferno Titan", 1);
assertGraveyardCount(playerA, "Grizzly Bears", 1);
assertCounterCount(playerA, "Chandra, Acolyte of Flame", CounterType.LOYALTY, 4 - 1);
}
}

View file

@ -8,61 +8,61 @@ import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* 4RR
* Creature - Angel
* Flying
*
* Whenever a source an opponent controls deals damage to you or a permanent you control,
* you may have Flameblade Angel deal 1 damage to that source's controller.
*
* 4RR
* Creature - Angel
* Flying
* <p>
* Whenever a source an opponent controls deals damage to you or a permanent you control,
* you may have Flameblade Angel deal 1 damage to that source's controller.
*
* @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
*/
public class FlamebladeAngelTest extends CardTestPlayerBase {
/**
* Reported bug: Not triggering when damage is dealt to the creatures I control.
*/
@Test
public void testDamageToCreature() {
addCard(Zone.BATTLEFIELD, playerA, "Flameblade Angel");
addCard(Zone.BATTLEFIELD, playerA, "Wall of Roots"); // 0/5
addCard(Zone.HAND, playerB, "Shock"); // instant deals 2 dmg to creature/player
addCard(Zone.BATTLEFIELD, playerB, "Mountain");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Shock");
addTarget(playerB, "Wall of Roots");
setStopAt(2, PhaseStep.BEGIN_COMBAT);
execute();
Permanent roots = getPermanent("Wall of Roots", playerA);
Assert.assertEquals("Wall of Roots should have 2 damage dealt to it", 2, roots.getDamage());
assertGraveyardCount(playerB, "Shock", 1);
assertLife(playerA, 20);
assertLife(playerB, 19); // Angel should deal 1 damage to Shock's controller
}
/**
* Reported bug: Not triggering when damage is dealt to the creatures I control.
*/
@Test
public void testDamageToMultipleCreatures() {
addCard(Zone.BATTLEFIELD, playerA, "Flameblade Angel");
addCard(Zone.BATTLEFIELD, playerA, "Wall of Roots"); // 0/5
addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); // 2/2
addCard(Zone.HAND, playerB, "Shock", 2); // instant deals 2 dmg to creature/player
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 2);
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Shock");
addTarget(playerB, "Wall of Roots");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Shock");
addTarget(playerB, "Grizzly Bears");
setStopAt(2, PhaseStep.BEGIN_COMBAT);
execute();
Permanent roots = getPermanent("Wall of Roots", playerA);
Assert.assertEquals("Wall of Roots should have 2 damage dealt to it", 2, roots.getDamage());
assertGraveyardCount(playerB, "Shock", 2);
@ -70,27 +70,27 @@ public class FlamebladeAngelTest extends CardTestPlayerBase {
assertLife(playerA, 20);
assertLife(playerB, 18); // Angel should deal 1 damage twice to Shock's controller
}
/**
* Reported bug: Not triggering when damage is dealt to the creatures I control.
*/
@Test
public void testCombatDamageToCreatures() {
addCard(Zone.BATTLEFIELD, playerA, "Flameblade Angel");
addCard(Zone.BATTLEFIELD, playerA, "Wall of Roots"); // 0/5
addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); // 2/2
addCard(Zone.BATTLEFIELD, playerB, "Elite Vanguard"); // 2/1
addCard(Zone.BATTLEFIELD, playerB, "Hill Giant"); // 3/3
attack(2, playerB, "Elite Vanguard");
attack(2, playerB, "Hill Giant");
block(2, playerA, "Wall of Roots", "Hill Giant");
block(2, playerA, "Grizzly Bears", "Elite Vanguard");
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
Permanent roots = getPermanent("Wall of Roots", playerA);
Assert.assertEquals("Wall of Roots should have 3 damage dealt to it", 3, roots.getDamage());
assertGraveyardCount(playerA, "Grizzly Bears", 1);

View file

@ -2281,9 +2281,6 @@ public class TestPlayer implements Player {
if (filter instanceof FilterCreatureOrPlayer) {
filter = ((FilterCreatureOrPlayer) filter).getCreatureFilter();
}
if (filter instanceof FilterCreaturePlayerOrPlaneswalker) {
filter = ((FilterCreaturePlayerOrPlaneswalker) filter).getCreatureFilter();
}
if (filter instanceof FilterPermanentOrPlayer) {
filter = ((FilterPermanentOrPlayer) filter).getPermanentFilter();
}

View file

@ -1,72 +1,48 @@
package mage.filter.common;
import mage.MageItem;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.MageObject;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.predicate.Predicate;
import mage.filter.predicate.Predicates;
import java.util.UUID;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* If you add predicate to permanentFilter then it will be applied to planeswalker too
*
* @author JRHerlehy Created on 4/8/18.
*/
public class FilterCreaturePlayerOrPlaneswalker extends FilterPermanentOrPlayer {
protected FilterCreaturePermanent creatureFilter;
protected FilterPlaneswalkerPermanent planeswalkerFilter;
public FilterCreaturePlayerOrPlaneswalker() {
this("any target");
}
public FilterCreaturePlayerOrPlaneswalker(String name) {
this(name, (SubType) null);
}
public FilterCreaturePlayerOrPlaneswalker(String name, SubType... andCreatureTypes) {
super(name);
creatureFilter = new FilterCreaturePermanent();
planeswalkerFilter = new FilterPlaneswalkerPermanent();
List<Predicate<MageObject>> allCreaturePredicates = Arrays.stream(andCreatureTypes)
.filter(Objects::nonNull)
.map(SubType::getPredicate)
.collect(Collectors.toList());
allCreaturePredicates.add(0, CardType.CREATURE.getPredicate());
Predicate<MageObject> planeswalkerPredicate = CardType.PLANESWALKER.getPredicate();
this.permanentFilter.add(Predicates.or(
Predicates.and(allCreaturePredicates),
planeswalkerPredicate
));
}
public FilterCreaturePlayerOrPlaneswalker(final FilterCreaturePlayerOrPlaneswalker filter) {
super(filter);
this.creatureFilter = filter.creatureFilter.copy();
this.planeswalkerFilter = filter.planeswalkerFilter.copy();
}
@Override
public boolean match(MageItem o, Game game) {
if (super.match(o, game)) {
if (o instanceof Player) {
return playerFilter.match((Player) o, game);
} else if (o instanceof Permanent) {
return creatureFilter.match((Permanent) o, game)
|| planeswalkerFilter.match((Permanent) o, game);
}
}
return false;
}
@Override
public boolean match(MageItem o, UUID sourceId, UUID playerId, Game game) {
if (super.match(o, game)) { // process predicates
if (o instanceof Player) {
return playerFilter.match((Player) o, sourceId, playerId, game);
} else if (o instanceof Permanent) {
return creatureFilter.match((Permanent) o, sourceId, playerId, game)
|| planeswalkerFilter.match((Permanent) o, sourceId, playerId, game);
}
}
return false;
}
public FilterCreaturePermanent getCreatureFilter() {
return this.creatureFilter;
}
public FilterPlaneswalkerPermanent getPlaneswalkerFilter() {
return this.planeswalkerFilter;
}
public void setCreatureFilter(FilterCreaturePermanent creatureFilter) {
this.creatureFilter = creatureFilter;
}
@Override

View file

@ -116,7 +116,7 @@ public class TargetAnyTarget extends TargetImpl {
}
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getCreatureFilter(), sourceControllerId, game)) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) {
count++;
if (count >= this.minNumberOfTargets) {
@ -125,15 +125,6 @@ public class TargetAnyTarget extends TargetImpl {
}
}
for (Permanent planeswalker : game.getBattlefield().getActivePermanents(filter.getPlaneswalkerFilter(), sourceControllerId, game)) {
if (planeswalker.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(planeswalker, sourceId, sourceControllerId, game)) {
count++;
if (count >= this.minNumberOfTargets) {
return true;
}
}
}
return false;
}
@ -160,7 +151,7 @@ public class TargetAnyTarget extends TargetImpl {
}
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getCreatureFilter(), sourceControllerId, game)) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) {
if (filter.match(permanent, null, sourceControllerId, game)) {
count++;
if (count >= this.minNumberOfTargets) {
@ -169,15 +160,6 @@ public class TargetAnyTarget extends TargetImpl {
}
}
for (Permanent planeswalker : game.getBattlefield().getActivePermanents(filter.getPlaneswalkerFilter(), sourceControllerId, game)) {
if (filter.match(planeswalker, null, sourceControllerId, game)) {
count++;
if (count >= this.minNumberOfTargets) {
return true;
}
}
}
return false;
}
@ -190,25 +172,18 @@ public class TargetAnyTarget extends TargetImpl {
Player player = game.getPlayer(playerId);
if (player != null
&& player.canBeTargetedBy(targetSource, sourceControllerId, game)
&& filter.getPlayerFilter().match(player, sourceId, sourceControllerId, game)) {
&& filter.match(player, sourceId, sourceControllerId, game)) {
possibleTargets.add(playerId);
}
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getCreatureFilter(), sourceControllerId, game)) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game)
&& filter.getCreatureFilter().match(permanent, sourceId, sourceControllerId, game)) {
&& filter.match(permanent, sourceId, sourceControllerId, game)) {
possibleTargets.add(permanent.getId());
}
}
for (Permanent planeswalker : game.getBattlefield().getActivePermanents(filter.getPlaneswalkerFilter(), sourceControllerId, game)) {
if (planeswalker.canBeTargetedBy(targetSource, sourceControllerId, game)
&& filter.getPlaneswalkerFilter().match(planeswalker, sourceId, sourceControllerId, game)) {
possibleTargets.add(planeswalker.getId());
}
}
return possibleTargets;
}
@ -218,23 +193,17 @@ public class TargetAnyTarget extends TargetImpl {
for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
Player player = game.getPlayer(playerId);
if (player != null && filter.getPlayerFilter().match(player, game)) {
if (player != null && filter.match(player, game)) {
possibleTargets.add(playerId);
}
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getCreatureFilter(), sourceControllerId, game)) {
if (filter.getCreatureFilter().match(permanent, null, sourceControllerId, game)) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) {
if (filter.getPermanentFilter().match(permanent, null, sourceControllerId, game)) {
possibleTargets.add(permanent.getId());
}
}
for (Permanent planeswalker : game.getBattlefield().getActivePermanents(filter.getPlaneswalkerFilter(), sourceControllerId, game)) {
if (filter.getPlaneswalkerFilter().match(planeswalker, null, sourceControllerId, game)) {
possibleTargets.add(planeswalker.getId());
}
}
return possibleTargets;
}

View file

@ -2,23 +2,17 @@ package mage.target.common;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePlayerOrPlaneswalker;
import mage.filter.common.FilterPermanentOrPlayer;
/**
* @author BetaSteward_at_googlemail.com
*/
public class TargetAnyTargetAmount extends TargetPermanentOrPlayerAmount {
private static final FilterPermanentOrPlayer defaultFilter
private static final FilterCreaturePlayerOrPlaneswalker defaultFilter
= new FilterCreaturePlayerOrPlaneswalker("targets");
static {
defaultFilter.getPermanentFilter().add(CardType.CREATURE.getPredicate());
}
public TargetAnyTargetAmount(int amount) {
this(amount, 0);
}

View file

@ -1,6 +1,5 @@
package mage.target.common;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent;
@ -16,18 +15,10 @@ public class TargetCreatureOrPlaneswalkerAmount extends TargetPermanentAmount {
super(amount, defaultFilter);
}
public TargetCreatureOrPlaneswalkerAmount(DynamicValue amount) {
super(amount, defaultFilter);
}
public TargetCreatureOrPlaneswalkerAmount(int amount, FilterPermanent filter) {
super(amount, filter);
}
public TargetCreatureOrPlaneswalkerAmount(DynamicValue amount, FilterPermanent filter) {
super(amount, filter);
}
private TargetCreatureOrPlaneswalkerAmount(final TargetCreatureOrPlaneswalkerAmount target) {
super(target);
}