implement [MH3] Volatile Stormdrake ; provide source Ability to canBeTargetedBy and HexproofBaseAbility::checkObject

This commit is contained in:
Susucre 2024-06-06 16:52:53 +02:00
parent 8ec4ffd9de
commit 2d625f0364
49 changed files with 399 additions and 171 deletions

View file

@ -1,7 +1,6 @@
package mage.cards.b;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.common.ExileTargetEffect;
@ -14,8 +13,9 @@ import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class BlazingHope extends CardImpl {
@ -53,8 +53,8 @@ class BlazingHopeTarget extends TargetCreaturePermanent {
Permanent permanent = game.getPermanent(id);
if (permanent != null) {
if (!isNotTarget()) {
if (!permanent.canBeTargetedBy(game.getObject(source.getId()), controllerId, game)
|| !permanent.canBeTargetedBy(game.getObject(source), controllerId, game)) {
if (!permanent.canBeTargetedBy(game.getObject(source.getId()), controllerId, source, game)
|| !permanent.canBeTargetedBy(game.getObject(source), controllerId, source, game)) {
return false;
}
}
@ -75,10 +75,10 @@ class BlazingHopeTarget extends TargetCreaturePermanent {
int count = 0;
Player controller = game.getPlayer(sourceControllerId);
MageObject targetSource = game.getObject(source);
if(targetSource != null) {
if (targetSource != null) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
if (!targets.containsKey(permanent.getId())) {
if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
if (controller != null && permanent.getPower().getValue() >= controller.getLife()) {
count++;
if (count >= remainingTargets) {

View file

@ -1,7 +1,5 @@
package mage.cards.b;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
@ -20,8 +18,9 @@ import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author Susucr
*/
public final class BreakingOfTheFellowship extends CardImpl {
@ -113,7 +112,7 @@ class BreakingOfTheFellowshipFirstTarget extends TargetCreaturePermanent {
int possibleTargets = 0;
MageObject sourceObject = game.getObject(source.getId());
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controllingPlayerId, game)) {
if (permanent.canBeTargetedBy(sourceObject, controllerId, game)) {
if (permanent.canBeTargetedBy(sourceObject, controllerId, source, game)) {
possibleTargets++;
}
}
@ -130,7 +129,7 @@ class BreakingOfTheFellowshipFirstTarget extends TargetCreaturePermanent {
int possibleTargets = 0;
MageObject sourceObject = game.getObject(source);
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, playerId, game)) {
if (permanent.canBeTargetedBy(sourceObject, controllingPlayerId, game)) {
if (permanent.canBeTargetedBy(sourceObject, controllingPlayerId, source, game)) {
possibleTargets++;
}
}

View file

@ -1,11 +1,6 @@
package mage.cards.d;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
@ -13,11 +8,7 @@ import mage.abilities.effects.common.continuous.ExchangeControlTargetEffect;
import mage.abilities.keyword.InspiredAbility;
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.TargetController;
import mage.constants.*;
import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.game.permanent.Permanent;
@ -25,6 +16,11 @@ import mage.players.Player;
import mage.target.TargetPermanent;
import mage.target.common.TargetControlledPermanent;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
* @author LevelX2
*/
@ -91,7 +87,7 @@ class TargetControlledPermanentSharingOpponentPermanentCardType extends TargetCo
MageObject targetSource = game.getObject(source);
if (targetSource != null) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
for (CardType type : permanent.getCardType(game)) {
if (cardTypes.contains(type)) {
possibleTargets.add(permanent.getId());
@ -160,7 +156,7 @@ class DaringThiefSecondTarget extends TargetPermanent {
MageObject targetSource = game.getObject(source);
if (targetSource != null) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
if (permanent.shareTypes(firstTarget, game)) {
possibleTargets.add(permanent.getId());
}

View file

@ -90,7 +90,7 @@ class GauntletsOfChaosFirstTarget extends TargetControlledPermanent {
MageObject targetSource = game.getObject(source);
if (targetSource != null) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
for (CardType type : permanent.getCardType(game)) {
if (cardTypes.contains(type)) {
possibleTargets.add(permanent.getId());
@ -159,7 +159,7 @@ class GauntletsOfChaosSecondTarget extends TargetPermanent {
MageObject targetSource = game.getObject(source);
if (targetSource != null) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
if (permanent.shareTypes(firstTarget, game)) {
possibleTargets.add(permanent.getId());
}

View file

@ -1,9 +1,6 @@
package mage.cards.g;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
@ -22,6 +19,10 @@ import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.watchers.common.PlayerDamagedBySourceWatcher;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -99,7 +100,7 @@ class GiltspireAvengerTarget extends TargetPermanent {
MageObject targetSource = game.getObject(source);
PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, sourceControllerId);
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)
&& watcher != null && watcher.hasSourceDoneDamage(permanent.getId(), game)) {
count++;
if (count >= remainingTargets) {

View file

@ -81,7 +81,7 @@ class GlyphOfDelusionSecondTarget extends TargetPermanent {
MageObject targetSource = game.getObject(source);
if (targetSource != null) {
for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, source, game)) {
if (!targets.containsKey(creature.getId()) && creature.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (!targets.containsKey(creature.getId()) && creature.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), new MageObjectReference(firstTarget, game), game)) {
possibleTargets.add(creature.getId());
}

View file

@ -1,8 +1,5 @@
package mage.cards.k;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
@ -10,10 +7,10 @@ import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.constants.SubType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.FilterOpponent;
import mage.filter.StaticFilters;
import mage.game.Game;
@ -21,15 +18,18 @@ import mage.game.permanent.token.BeastToken4;
import mage.players.Player;
import mage.target.TargetPlayer;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
*
* @author noahg
*/
public final class KeeperOfTheBeasts extends CardImpl {
public KeeperOfTheBeasts(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{G}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.WIZARD);
this.power = new MageInt(1);
@ -90,7 +90,7 @@ class KeeperOfTheBeastsTarget extends TargetPlayer {
< game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game)
&& !player.hasLeft()
&& filter.match(player, sourceControllerId, source, game)
&& player.canBeTargetedBy(targetSource, sourceControllerId, game)) {
&& player.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
count++;
if (count >= this.minNumberOfTargets) {
return true;

View file

@ -1,9 +1,6 @@
package mage.cards.k;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
@ -21,8 +18,11 @@ import mage.game.Game;
import mage.players.Player;
import mage.target.TargetPlayer;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
*
* @author stevemarkham81
*/
public final class KeeperOfTheLight extends CardImpl {
@ -95,7 +95,7 @@ class KeeperOfTheLightTarget extends TargetPlayer {
&& controller.getLife() < player.getLife()
&& !player.hasLeft()
&& filter.match(player, sourceControllerId, source, game)
&& player.canBeTargetedBy(targetSource, sourceControllerId, game)) {
&& player.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
count++;
if (count >= this.minNumberOfTargets) {
return true;

View file

@ -109,7 +109,7 @@ class MutinyFirstTarget extends TargetCreaturePermanent {
int possibleTargets = 0;
MageObject sourceObject = game.getObject(source.getId());
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controllingPlayerId, game)) {
if (permanent.canBeTargetedBy(sourceObject, controllerId, game)) {
if (permanent.canBeTargetedBy(sourceObject, controllerId, source, game)) {
possibleTargets++;
}
}
@ -126,7 +126,7 @@ class MutinyFirstTarget extends TargetCreaturePermanent {
int possibleTargets = 0;
MageObject sourceObject = game.getObject(source);
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, playerId, game)) {
if (permanent.canBeTargetedBy(sourceObject, controllingPlayerId, game)) {
if (permanent.canBeTargetedBy(sourceObject, controllingPlayerId, source, game)) {
possibleTargets++;
}
}

View file

@ -62,7 +62,7 @@ class TargetCreatureWithLessPowerPermanent extends TargetPermanent {
return false;
}
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURES, sourceControllerId, game)) {
if (permanent.getPower().getValue() > maxPower && permanent.canBeTargetedBy(sourceCard, sourceControllerId, game)) {
if (permanent.getPower().getValue() > maxPower && permanent.canBeTargetedBy(sourceCard, sourceControllerId, source, game)) {
maxPower = permanent.getPower().getValue();
}
}
@ -70,7 +70,7 @@ class TargetCreatureWithLessPowerPermanent extends TargetPermanent {
FilterCreaturePermanent checkFilter = new FilterCreaturePermanent();
checkFilter.add(new PowerPredicate(ComparisonType.FEWER_THAN, maxPower));
for (Permanent permanent : game.getBattlefield().getActivePermanents(checkFilter, sourceControllerId, source, game)) {
if (permanent.canBeTargetedBy(sourceCard, sourceControllerId, game)) {
if (permanent.canBeTargetedBy(sourceCard, sourceControllerId, source, game)) {
return true;
}
}

View file

@ -1,9 +1,6 @@
package mage.cards.p;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
@ -20,8 +17,11 @@ import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.target.common.TargetControlledPermanent;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public final class PucasMischief extends CardImpl {
@ -29,7 +29,7 @@ public final class PucasMischief extends CardImpl {
private static final String rule = "you may exchange control of target nonland permanent you control and target nonland permanent an opponent controls with an equal or lesser mana value";
public PucasMischief(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{U}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}");
// At the beginning of your upkeep, you may exchange control of target nonland permanent you control and target nonland permanent an opponent controls with an equal or lesser converted mana cost.
Ability ability = new BeginningOfUpkeepTriggeredAbility(new ExchangeControlTargetEffect(Duration.EndOfGame, rule, false, true), TargetController.YOU, true);
@ -66,9 +66,9 @@ class TargetControlledPermanentWithCMCGreaterOrLessThanOpponentPermanent extends
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
Set<UUID> possibleTargets = new HashSet<>();
MageObject targetSource = game.getObject(source);
if(targetSource != null) {
if (targetSource != null) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
possibleTargets.add(permanent.getId());
}
}
@ -118,7 +118,7 @@ class PucasMischiefSecondTarget extends TargetPermanent {
MageObject targetSource = game.getObject(source);
if (targetSource != null) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
if (firstTarget.getManaValue() >= permanent.getManaValue()) {
possibleTargets.add(permanent.getId());
}

View file

@ -1,9 +1,6 @@
package mage.cards.r;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.common.ExileTargetEffect;
@ -16,6 +13,10 @@ import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.watchers.common.PlayerDamagedBySourceWatcher;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
* @author LevelX2
*/
@ -82,10 +83,10 @@ class ReciprocateTarget extends TargetPermanent {
}
int count = 0;
MageObject targetSource = game.getObject(source);
if(targetSource != null) {
if (targetSource != null) {
PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, sourceControllerId);
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)
&& watcher != null && watcher.hasSourceDoneDamage(permanent.getId(), game)) {
count++;
if (count >= remainingTargets) {

View file

@ -43,7 +43,7 @@ public final class RoleReversal extends CardImpl {
class TargetPermanentsThatShareCardType extends TargetPermanent {
TargetPermanentsThatShareCardType() {
TargetPermanentsThatShareCardType() {
super(2, 2, StaticFilters.FILTER_PERMANENT, false);
targetName = "permanents that share a permanent type";
}
@ -74,7 +74,7 @@ class TargetPermanentsThatShareCardType extends TargetPermanent {
MageObject targetSource = game.getObject(source);
if (targetSource != null) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
for (CardType cardType : permanent.getCardType(game)) {
if (cardTypes.contains(cardType)) {
return true;

View file

@ -74,7 +74,7 @@ class TargetPermanentsThatShareCardType extends TargetPermanent {
MageObject targetSource = game.getObject(source);
if (targetSource != null) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
for (CardType cardType : permanent.getCardType(game)) {
if (cardTypes.contains(cardType)) {
return true;

View file

@ -1,9 +1,6 @@
package mage.cards.s;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
@ -11,19 +8,17 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.continuous.ExchangeControlTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.target.common.TargetControlledPermanent;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
*
* @author jeffwadsworth & L_J
*/
public final class Spawnbroker extends CardImpl {
@ -31,12 +26,12 @@ public final class Spawnbroker extends CardImpl {
private static final String rule = "you may exchange control of target creature you control and target creature with power less than or equal to that creature's power an opponent controls";
public Spawnbroker(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.WIZARD);
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// When Spawnbroker enters the battlefield, you may exchange control of target creature you control and target creature with power less than or equal to that creature's power an opponent controls.
Ability ability = new EntersBattlefieldTriggeredAbility(new ExchangeControlTargetEffect(Duration.Custom, rule, false, true), true);
ability.addTarget(new TargetControlledCreatureWithPowerGreaterOrLessThanOpponentPermanent());
@ -72,9 +67,9 @@ class TargetControlledCreatureWithPowerGreaterOrLessThanOpponentPermanent extend
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
Set<UUID> possibleTargets = new HashSet<>();
MageObject targetSource = game.getObject(source);
if(targetSource != null) {
if (targetSource != null) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
possibleTargets.add(permanent.getId());
}
}
@ -122,9 +117,9 @@ class SpawnbrokerSecondTarget extends TargetPermanent {
Set<UUID> possibleTargets = new HashSet<>();
if (firstTarget != null) {
MageObject targetSource = game.getObject(source);
if(targetSource != null) {
if (targetSource != null) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
if (firstTarget.getPower().getValue() >= permanent.getPower().getValue()) {
possibleTargets.add(permanent.getId());
}

View file

@ -19,13 +19,12 @@ import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author FenrisulfrX
*/
public final class TemporaryInsanity extends CardImpl {
public TemporaryInsanity(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{R}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}");
// Untap target creature with power less than the number of cards in your graveyard
this.getSpellAbility().addTarget(new TargetCreatureWithPowerLessThanNumberOfCardsInYourGraveyard());
@ -78,9 +77,9 @@ class TargetCreatureWithPowerLessThanNumberOfCardsInYourGraveyard extends Target
@Override
public boolean canChoose(UUID sourceControllerId, Ability source, Game game) {
MageObject targetSource = game.getObject(source);
if(targetSource != null) {
if (targetSource != null) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
if (permanent.getPower().getValue() < game.getPlayer(sourceControllerId).getGraveyard().size()) {
return true;
}

View file

@ -115,7 +115,7 @@ class TheTricksterGodsHeistTarget extends TargetPermanent {
return false;
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
if (!permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (!permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
continue;
}
for (CardType cardType : permanent.getCardType(game)) {

View file

@ -73,7 +73,7 @@ class ThranTomeEffect extends OneShotEffect {
// target an opponent, if able
Player opponent;
Set<UUID> opponents = game.getOpponents(controller.getId());
opponents.removeIf(opp -> !game.getPlayer(opp).canBeTargetedBy(sourceObject, source.getControllerId(), game));
opponents.removeIf(opp -> !game.getPlayer(opp).canBeTargetedBy(sourceObject, source.getControllerId(), source, game));
if (opponents.isEmpty()) {
return false;

View file

@ -1,9 +1,5 @@
package mage.cards.t;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.common.ExileTargetEffect;
@ -14,8 +10,12 @@ import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
/**
*
* @author L_J
*/
public final class Topple extends CardImpl {
@ -72,7 +72,7 @@ class ToppleTargetCreature extends TargetCreaturePermanent {
List<Permanent> activePermanents = game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game);
Set<UUID> possibleTargets = new HashSet<>();
MageObject targetSource = game.getObject(source);
if(targetSource == null){
if (targetSource == null) {
return possibleTargets;
}
for (Permanent permanent : activePermanents) {
@ -81,7 +81,7 @@ class ToppleTargetCreature extends TargetCreaturePermanent {
}
}
for (Permanent permanent : activePermanents) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
if (permanent.getPower().getValue() == maxPower) {
possibleTargets.add(permanent.getId());
}

View file

@ -0,0 +1,147 @@
package mage.cards.v;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.costs.common.PayEnergyCost;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DoIfCostPaid;
import mage.abilities.effects.common.SacrificeTargetEffect;
import mage.abilities.effects.common.continuous.ExchangeControlTargetEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.HexproofBaseAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetOpponentsCreaturePermanent;
import java.io.ObjectStreamException;
import java.util.UUID;
/**
* @author Susucr
*/
public final class VolatileStormdrake extends CardImpl {
public VolatileStormdrake(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}");
this.subtype.add(SubType.DRAKE);
this.power = new MageInt(3);
this.toughness = new MageInt(2);
// Flying
this.addAbility(FlyingAbility.getInstance());
// Hexproof from activated and triggered abilities
this.addAbility(VolatileStormdrakeHexproofAbility.getInstance());
// When Volatile Stormdrake enters the battlefield, exchange control of Volatile Stormdrake and target creature an opponent controls. If you do, you get {E}{E}{E}{E}, then sacrifice that creature unless you pay an amount of {E} equal to its mana value.
Ability ability = new EntersBattlefieldTriggeredAbility(new VolatileStormdrakeEffect());
ability.addTarget(new TargetOpponentsCreaturePermanent());
this.addAbility(ability);
}
private VolatileStormdrake(final VolatileStormdrake card) {
super(card);
}
@Override
public VolatileStormdrake copy() {
return new VolatileStormdrake(this);
}
}
class VolatileStormdrakeHexproofAbility extends HexproofBaseAbility {
private static final VolatileStormdrakeHexproofAbility instance;
static {
instance = new VolatileStormdrakeHexproofAbility();
}
private Object readResolve() throws ObjectStreamException {
return instance;
}
public static VolatileStormdrakeHexproofAbility getInstance() {
return instance;
}
private VolatileStormdrakeHexproofAbility() {
super();
}
@Override
public boolean checkObject(MageObject sourceObject, Ability source, Game game) {
return source.isTriggeredAbility() || source.isActivatedAbility();
}
@Override
public VolatileStormdrakeHexproofAbility copy() {
return instance;
}
@Override
public String getRule() {
return "hexproof from activated and triggered abilities";
}
@Override
public String getCardIconHint(Game game) {
return "hexproof from activated and triggered abilities";
}
}
class VolatileStormdrakeEffect extends OneShotEffect {
VolatileStormdrakeEffect() {
super(Outcome.GainControl);
this.staticText = "exchange control of {this} and up to one target creature an opponent controls. "
+ "If you do, you get {E}{E}{E}{E}, then sacrifice that creature unless you pay an amount of {E} equal to its mana value";
}
private VolatileStormdrakeEffect(final VolatileStormdrakeEffect effect) {
super(effect);
}
@Override
public VolatileStormdrakeEffect copy() {
return new VolatileStormdrakeEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
Permanent sourceObject = game.getPermanent(source.getSourceId());
if (sourceObject == null) {
return false;
}
Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (targetPermanent == null) {
return false;
}
ContinuousEffect effect = new ExchangeControlTargetEffect(Duration.EndOfGame, "", true);
effect.setTargetPointer(this.getTargetPointer().copy());
game.addEffect(effect, source);
game.getState().processAction(game);
controller.addCounters(CounterType.ENERGY.createInstance(4), controller.getId(), source, game);
new DoIfCostPaid(
null, new SacrificeTargetEffect("", controller.getId()),
new PayEnergyCost(targetPermanent.getManaValue()), true
).apply(game, source);
return true;
}
}

View file

@ -307,6 +307,7 @@ public final class ModernHorizons3 extends ExpansionSet {
cards.add(new SetCardInfo("Vexing Bauble", 212, Rarity.UNCOMMON, mage.cards.v.VexingBauble.class));
cards.add(new SetCardInfo("Victimize", 278, Rarity.UNCOMMON, mage.cards.v.Victimize.class));
cards.add(new SetCardInfo("Voidpouncer", 143, Rarity.COMMON, mage.cards.v.Voidpouncer.class));
cards.add(new SetCardInfo("Volatile Stormdrake", 79, Rarity.RARE, mage.cards.v.VolatileStormdrake.class));
cards.add(new SetCardInfo("Voltstorm Angel", 46, Rarity.UNCOMMON, mage.cards.v.VoltstormAngel.class));
cards.add(new SetCardInfo("Warped Tusker", 16, Rarity.COMMON, mage.cards.w.WarpedTusker.class));
cards.add(new SetCardInfo("Warren Soultrader", 110, Rarity.RARE, mage.cards.w.WarrenSoultrader.class));

View file

@ -0,0 +1,75 @@
package org.mage.test.cards.single.mh3;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author Susucr
*/
public class VolatileStormdrakeTest extends CardTestPlayerBase {
/**
* {@link mage.cards.v.VolatileStormdrake Volatile Stormdrake} {1}{U}
* Creature Drake
* Flying, hexproof from activated and triggered abilities
* When Volatile Stormdrake enters the battlefield, exchange control of Volatile Stormdrake and target creature an opponent controls. If you do, you get {E}{E}{E}{E}, then sacrifice that creature unless you pay an amount of {E} equal to its mana value.
* 3/2
*/
private static final String drake = "Volatile Stormdrake";
@Test
public void test_Hexproof_From_Triggered() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerB, drake);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4);
addCard(Zone.HAND, playerA, "Ravenous Chupacabra");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ravenous Chupacabra");
// no trigger, as the drake has hexproof from triggered ability so there is no valid target
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerB, drake, 1);
assertPermanentCount(playerA, "Ravenous Chupacabra", 1);
}
@Test
public void test_Hexproof_From_Activated() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerB, drake);
addCard(Zone.BATTLEFIELD, playerA, "Alluring Siren");
addCard(Zone.HAND, playerB, "Memnite");
checkPlayableAbility("can not activate Siren", 1, PhaseStep.PRECOMBAT_MAIN, playerA,
"{T}: Target creature an opponent controls attacks you this turn if able.", false);
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Memnite");
checkPlayableAbility("can not activate Siren", 3, PhaseStep.PRECOMBAT_MAIN, playerA,
"{T}: Target creature an opponent controls attacks you this turn if able.", true);
setStopAt(3, PhaseStep.BEGIN_COMBAT);
execute();
}
@Test
public void test_CanBeTargetted_BySpell() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerB, drake);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
addCard(Zone.HAND, playerA, "Murder");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Murder", drake);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerB, drake, 1);
}
}

View file

@ -3027,8 +3027,8 @@ public class TestPlayer implements Player {
}
@Override
public boolean canBeTargetedBy(MageObject source, UUID sourceControllerId, Game game) {
return computerPlayer.canBeTargetedBy(source, sourceControllerId, game);
public boolean canBeTargetedBy(MageObject sourceObject, UUID sourceControllerId, Ability source, Game game) {
return computerPlayer.canBeTargetedBy(sourceObject, sourceControllerId, source, game);
}
@Override

View file

@ -1,6 +1,7 @@
package mage.abilities.keyword;
import mage.MageObject;
import mage.abilities.Ability;
import mage.game.Game;
import java.io.ObjectStreamException;
@ -32,7 +33,7 @@ public class HexproofAbility extends HexproofBaseAbility {
}
@Override
public boolean checkObject(MageObject source, Game game) {
public boolean checkObject(MageObject sourceObject, Ability source, Game game) {
return true;
}

View file

@ -2,6 +2,7 @@ package mage.abilities.keyword;
import mage.MageObject;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.MageSingleton;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.icon.CardIcon;
@ -9,10 +10,12 @@ import mage.abilities.icon.CardIconImpl;
import mage.abilities.icon.CardIconType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.util.CardUtil;
import java.util.*;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* an abstract base class for hexproof abilities
@ -21,11 +24,11 @@ import java.util.*;
*/
public abstract class HexproofBaseAbility extends SimpleStaticAbility implements MageSingleton {
HexproofBaseAbility() {
protected HexproofBaseAbility() {
super(Zone.BATTLEFIELD, null);
}
public abstract boolean checkObject(MageObject source, Game game);
public abstract boolean checkObject(MageObject sourceObject, Ability source, Game game);
public static Set<HexproofBaseAbility> getFromColor(ObjectColor color) {
Set<HexproofBaseAbility> abilities = new HashSet<>();

View file

@ -1,6 +1,7 @@
package mage.abilities.keyword;
import mage.MageObject;
import mage.abilities.Ability;
import mage.game.Game;
import java.io.ObjectStreamException;
@ -31,8 +32,8 @@ public class HexproofFromArtifactsCreaturesAndEnchantments extends HexproofBaseA
}
@Override
public boolean checkObject(MageObject source, Game game) {
return source.isArtifact(game) || source.isCreature(game) || source.isEnchantment(game);
public boolean checkObject(MageObject sourceObject, Ability source, Game game) {
return sourceObject.isArtifact(game) || sourceObject.isCreature(game) || sourceObject.isEnchantment(game);
}
@Override

View file

@ -1,6 +1,7 @@
package mage.abilities.keyword;
import mage.MageObject;
import mage.abilities.Ability;
import mage.game.Game;
import java.io.ObjectStreamException;
@ -32,8 +33,8 @@ public class HexproofFromBlackAbility extends HexproofBaseAbility {
}
@Override
public boolean checkObject(MageObject source, Game game) {
return source.getColor(game).isBlack();
public boolean checkObject(MageObject sourceObject, Ability source, Game game) {
return sourceObject.getColor(game).isBlack();
}
@Override

View file

@ -1,6 +1,7 @@
package mage.abilities.keyword;
import mage.MageObject;
import mage.abilities.Ability;
import mage.game.Game;
import java.io.ObjectStreamException;
@ -32,8 +33,8 @@ public class HexproofFromBlueAbility extends HexproofBaseAbility {
}
@Override
public boolean checkObject(MageObject source, Game game) {
return source.getColor(game).isBlue();
public boolean checkObject(MageObject sourceObject, Ability source, Game game) {
return sourceObject.getColor(game).isBlue();
}
@Override

View file

@ -1,6 +1,7 @@
package mage.abilities.keyword;
import mage.MageObject;
import mage.abilities.Ability;
import mage.game.Game;
import java.io.ObjectStreamException;
@ -31,8 +32,8 @@ public class HexproofFromEachColorAbility extends HexproofBaseAbility {
}
@Override
public boolean checkObject(MageObject source, Game game) {
return !source.getColor(game).isColorless();
public boolean checkObject(MageObject sourceObject, Ability source, Game game) {
return !sourceObject.getColor(game).isColorless();
}
@Override

View file

@ -1,6 +1,7 @@
package mage.abilities.keyword;
import mage.MageObject;
import mage.abilities.Ability;
import mage.game.Game;
import java.io.ObjectStreamException;
@ -32,8 +33,8 @@ public class HexproofFromGreenAbility extends HexproofBaseAbility {
}
@Override
public boolean checkObject(MageObject source, Game game) {
return source.getColor(game).isGreen();
public boolean checkObject(MageObject sourceObject, Ability source, Game game) {
return sourceObject.getColor(game).isGreen();
}
@Override

View file

@ -1,6 +1,7 @@
package mage.abilities.keyword;
import mage.MageObject;
import mage.abilities.Ability;
import mage.game.Game;
import java.io.ObjectStreamException;
@ -32,8 +33,8 @@ public class HexproofFromMonocoloredAbility extends HexproofBaseAbility {
}
@Override
public boolean checkObject(MageObject source, Game game) {
return !source.getColor(game).isMulticolored() && !source.getColor(game).isColorless();
public boolean checkObject(MageObject sourceObject, Ability source, Game game) {
return !sourceObject.getColor(game).isMulticolored() && !sourceObject.getColor(game).isColorless();
}
@Override

View file

@ -1,10 +1,11 @@
package mage.abilities.keyword;
import java.io.ObjectStreamException;
import mage.MageObject;
import mage.abilities.Ability;
import mage.game.Game;
import java.io.ObjectStreamException;
public class HexproofFromMulticoloredAbility extends HexproofBaseAbility {
private static final HexproofFromMulticoloredAbility instance;
@ -31,8 +32,8 @@ public class HexproofFromMulticoloredAbility extends HexproofBaseAbility {
}
@Override
public boolean checkObject(MageObject source, Game game) {
return source.getColor().isMulticolored();
public boolean checkObject(MageObject sourceObject, Ability source, Game game) {
return sourceObject.getColor().isMulticolored();
}
@Override

View file

@ -1,6 +1,7 @@
package mage.abilities.keyword;
import mage.MageObject;
import mage.abilities.Ability;
import mage.game.Game;
import java.io.ObjectStreamException;
@ -31,8 +32,8 @@ public class HexproofFromPlaneswalkersAbility extends HexproofBaseAbility {
}
@Override
public boolean checkObject(MageObject source, Game game) {
return source.isPlaneswalker(game);
public boolean checkObject(MageObject sourceObject, Ability source, Game game) {
return sourceObject.isPlaneswalker(game);
}
@Override

View file

@ -1,6 +1,7 @@
package mage.abilities.keyword;
import mage.MageObject;
import mage.abilities.Ability;
import mage.game.Game;
import java.io.ObjectStreamException;
@ -32,8 +33,8 @@ public class HexproofFromRedAbility extends HexproofBaseAbility {
}
@Override
public boolean checkObject(MageObject source, Game game) {
return source.getColor(game).isRed();
public boolean checkObject(MageObject sourceObject, Ability source, Game game) {
return sourceObject.getColor(game).isRed();
}
@Override

View file

@ -1,6 +1,7 @@
package mage.abilities.keyword;
import mage.MageObject;
import mage.abilities.Ability;
import mage.game.Game;
import java.io.ObjectStreamException;
@ -32,8 +33,8 @@ public class HexproofFromWhiteAbility extends HexproofBaseAbility {
}
@Override
public boolean checkObject(MageObject source, Game game) {
return source.getColor(game).isWhite();
public boolean checkObject(MageObject sourceObject, Ability source, Game game) {
return sourceObject.getColor(game).isWhite();
}
@Override

View file

@ -128,7 +128,7 @@ public interface Permanent extends Card, Controllable {
void unattach(Game game);
boolean canBeTargetedBy(MageObject source, UUID controllerId, Game game);
boolean canBeTargetedBy(MageObject sourceObject, UUID controllerId, Ability source, Game game);
boolean hasProtectionFrom(MageObject source, Game game);

View file

@ -1302,8 +1302,8 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
}
@Override
public boolean canBeTargetedBy(MageObject source, UUID sourceControllerId, Game game) {
if (source != null) {
public boolean canBeTargetedBy(MageObject sourceObject, UUID sourceControllerId, Ability source, Game game) {
if (sourceObject != null) {
if (abilities.containsKey(ShroudAbility.getInstance().getId())) {
if (game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.SHROUD, null, sourceControllerId, game).isEmpty()) {
return false;
@ -1315,17 +1315,17 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
&& abilities.stream()
.filter(HexproofBaseAbility.class::isInstance)
.map(HexproofBaseAbility.class::cast)
.anyMatch(ability -> ability.checkObject(source, game))) {
.anyMatch(ability -> ability.checkObject(sourceObject, source, game))) {
return false;
}
if (hasProtectionFrom(source, game)) {
if (hasProtectionFrom(sourceObject, game)) {
return false;
}
// example: Fiendslayer Paladin tried to target with Ultimate Price
return !game.getContinuousEffects().preventedByRuleModification(
new TargetEvent(this, source.getId(), sourceControllerId),
new TargetEvent(this, sourceObject.getId(), sourceControllerId),
null,
game,
true

View file

@ -513,7 +513,7 @@ public interface Player extends MageItem, Copyable<Player> {
boolean triggerAbility(TriggeredAbility ability, Game game);
boolean canBeTargetedBy(MageObject source, UUID sourceControllerId, Game game);
boolean canBeTargetedBy(MageObject sourceObject, UUID sourceControllerId, Ability source, Game game);
boolean hasProtectionFrom(MageObject source, Game game);

View file

@ -687,11 +687,11 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public boolean canBeTargetedBy(MageObject source, UUID sourceControllerId, Game game) {
public boolean canBeTargetedBy(MageObject sourceObject, UUID sourceControllerId, Ability source, Game game) {
if (this.hasLost() || this.hasLeft()) {
return false;
}
if (source != null) {
if (sourceObject != null) {
if (abilities.containsKey(ShroudAbility.getInstance().getId())
&& game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.SHROUD, null, sourceControllerId, game).isEmpty()) {
return false;
@ -703,17 +703,17 @@ public abstract class PlayerImpl implements Player, Serializable {
&& abilities.stream()
.filter(HexproofBaseAbility.class::isInstance)
.map(HexproofBaseAbility.class::cast)
.anyMatch(ability -> ability.checkObject(source, game))) {
.anyMatch(ability -> ability.checkObject(sourceObject, source, game))) {
return false;
}
if (hasProtectionFrom(source, game)) {
if (hasProtectionFrom(sourceObject, game)) {
return false;
}
// example: Peace Talks
return !game.getContinuousEffects().preventedByRuleModification(
new TargetEvent(this, source.getId(), sourceControllerId),
new TargetEvent(this, sourceObject.getId(), sourceControllerId),
null,
game,
true

View file

@ -67,8 +67,8 @@ public class TargetPermanent extends TargetObject {
// first for protection from spells or abilities (e.g. protection from colored spells, r1753)
// second for protection from sources (e.g. protection from artifacts + equip ability)
if (!isNotTarget()) {
if (!permanent.canBeTargetedBy(game.getObject(source.getId()), controllerId, game)
|| !permanent.canBeTargetedBy(game.getObject(source), controllerId, game)) {
if (!permanent.canBeTargetedBy(game.getObject(source.getId()), controllerId, source, game)
|| !permanent.canBeTargetedBy(game.getObject(source), controllerId, source, game)) {
return false;
}
}
@ -108,7 +108,7 @@ public class TargetPermanent extends TargetObject {
MageObject targetSource = game.getObject(source);
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
if (!targets.containsKey(permanent.getId())) {
if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
count++;
if (count >= remainingTargets) {
return true;
@ -155,7 +155,7 @@ public class TargetPermanent extends TargetObject {
MageObject targetSource = game.getObject(source);
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
if (!targets.containsKey(permanent.getId())) {
if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
possibleTargets.add(permanent.getId());
}
}

View file

@ -67,7 +67,7 @@ public class TargetPlayer extends TargetImpl {
for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
Player player = game.getPlayer(playerId);
if (player != null && !player.hasLeft() && filter.match(player, sourceControllerId, source, game)) {
if (player.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (player.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
count++;
if (count >= this.minNumberOfTargets) {
return true;
@ -109,7 +109,7 @@ public class TargetPlayer extends TargetImpl {
for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
Player player = game.getPlayer(playerId);
if (player != null && !player.hasLeft() && filter.match(player, sourceControllerId, source, game)) {
if (isNotTarget() || player.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (isNotTarget() || player.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
possibleTargets.add(playerId);
}
}
@ -149,7 +149,7 @@ public class TargetPlayer extends TargetImpl {
Player player = game.getPlayer(id);
if (player != null) {
if (source != null) {
return (isNotTarget() || player.canBeTargetedBy(game.getObject(source), source.getControllerId(), game))
return (isNotTarget() || player.canBeTargetedBy(game.getObject(source), source.getControllerId(), source, game))
&& filter.match(player, source.getControllerId(), source, game);
} else {
return filter.match(player, game);

View file

@ -63,7 +63,7 @@ public class TargetCardInGraveyardBattlefieldOrStack extends TargetCard {
}
MageObject targetSource = game.getObject(source);
for (Permanent permanent : game.getBattlefield().getActivePermanents(filterPermanent, sourceControllerId, source, game)) {
if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
return true;
}
}
@ -110,7 +110,7 @@ public class TargetCardInGraveyardBattlefieldOrStack extends TargetCard {
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game); // in graveyard first
MageObject targetSource = game.getObject(source);
for (Permanent permanent : game.getBattlefield().getActivePermanents(filterPermanent, sourceControllerId, source, game)) {
if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
possibleTargets.add(permanent.getId());
}
}

View file

@ -71,10 +71,10 @@ public class TargetCreatureOrPlayer extends TargetImpl {
if (source != null) {
MageObject targetSource = game.getObject(source);
if (permanent != null) {
return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(permanent, source.getControllerId(), source, game);
return permanent.canBeTargetedBy(targetSource, source.getControllerId(), source, game) && filter.match(permanent, source.getControllerId(), source, game);
}
if (player != null) {
return player.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(player, game);
return player.canBeTargetedBy(targetSource, source.getControllerId(), source, game) && filter.match(player, game);
}
}
@ -100,7 +100,7 @@ public class TargetCreatureOrPlayer extends TargetImpl {
MageObject targetSource = game.getObject(source);
for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
Player player = game.getPlayer(playerId);
if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, game)) {
if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, source, game) && filter.match(player, game)) {
count++;
if (count >= this.minNumberOfTargets) {
return true;
@ -108,7 +108,7 @@ public class TargetCreatureOrPlayer extends TargetImpl {
}
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getCreatureFilter(), sourceControllerId, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceControllerId, source, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game) && filter.match(permanent, sourceControllerId, source, game)) {
count++;
if (count >= this.minNumberOfTargets) {
return true;
@ -157,13 +157,13 @@ public class TargetCreatureOrPlayer extends TargetImpl {
for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
Player player = game.getPlayer(playerId);
if (player != null
&& player.canBeTargetedBy(targetSource, sourceControllerId, game)
&& player.canBeTargetedBy(targetSource, sourceControllerId, source, game)
&& filter.getPlayerFilter().match(player, sourceControllerId, source, game)) {
possibleTargets.add(playerId);
}
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getCreatureFilter(), sourceControllerId, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game)
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)
&& filter.getCreatureFilter().match(permanent, sourceControllerId, source, game)) {
possibleTargets.add(permanent.getId());
}

View file

@ -40,8 +40,8 @@ public class TargetOpponentsChoicePermanent extends TargetPermanent {
if (source != null) {
boolean canSourceControllerTarget = true;
if (!isNotTarget()) {
if (!permanent.canBeTargetedBy(game.getObject(source.getId()), controllerId, game)
|| !permanent.canBeTargetedBy(game.getObject(source), controllerId, game)) {
if (!permanent.canBeTargetedBy(game.getObject(source.getId()), controllerId, source, game)
|| !permanent.canBeTargetedBy(game.getObject(source), controllerId, source, game)) {
canSourceControllerTarget = false;
}
}
@ -89,7 +89,7 @@ public class TargetOpponentsChoicePermanent extends TargetPermanent {
for (Permanent perm : game.getBattlefield().getActivePermanents(opp.getId(), game)) {
if (!targets.containsKey(perm.getId())
&& filter.match(perm, opp.getId(), source, game)
&& perm.canBeTargetedBy(sourceObject, sourceControllerId, game)) {
&& perm.canBeTargetedBy(sourceObject, sourceControllerId, source, game)) {
counter++;
if (counter >= minNumberOfTargets) {
return true;

View file

@ -72,7 +72,7 @@ public class TargetPermanentAmount extends TargetAmount {
return filter.match(permanent, game);
}
MageObject targetSource = source.getSourceObject(game);
return (notTarget || permanent.canBeTargetedBy(targetSource, source.getControllerId(), game))
return (notTarget || permanent.canBeTargetedBy(targetSource, source.getControllerId(), source, game))
&& filter.match(permanent, source.getControllerId(), source, game);
}
@ -106,7 +106,7 @@ public class TargetPermanentAmount extends TargetAmount {
.getActivePermanents(filter, sourceControllerId, source, game)
.stream()
.filter(Objects::nonNull)
.filter(permanent -> notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game))
.filter(permanent -> notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game))
.map(Permanent::getId)
.collect(Collectors.toSet());
}

View file

@ -85,8 +85,8 @@ public class TargetPermanentOrPlayer extends TargetImpl {
MageObject targetSource = game.getObject(source);
if (permanent != null) {
if (!isNotTarget()) {
if (!permanent.canBeTargetedBy(game.getObject(source.getId()), source.getControllerId(), game)
|| !permanent.canBeTargetedBy(game.getObject(source), source.getControllerId(), game)) {
if (!permanent.canBeTargetedBy(game.getObject(source.getId()), source.getControllerId(), source, game)
|| !permanent.canBeTargetedBy(game.getObject(source), source.getControllerId(), source, game)) {
return false;
}
}
@ -94,7 +94,7 @@ public class TargetPermanentOrPlayer extends TargetImpl {
}
if (player != null) {
if (!isNotTarget()) {
if (!player.canBeTargetedBy(targetSource, source.getControllerId(), game)
if (!player.canBeTargetedBy(targetSource, source.getControllerId(), source, game)
|| !filter.match(player, source.getControllerId(), source, game)) {
return false;
}
@ -126,7 +126,7 @@ public class TargetPermanentOrPlayer extends TargetImpl {
MageObject targetSource = game.getObject(source);
for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
Player player = game.getPlayer(playerId);
if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, sourceControllerId, source, game)) {
if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, source, game) && filter.match(player, sourceControllerId, source, game)) {
count++;
if (count >= this.minNumberOfTargets) {
return true;
@ -134,7 +134,7 @@ public class TargetPermanentOrPlayer extends TargetImpl {
}
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceControllerId, source, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game) && filter.match(permanent, sourceControllerId, source, game)) {
count++;
if (count >= this.minNumberOfTargets) {
return true;
@ -183,12 +183,12 @@ public class TargetPermanentOrPlayer extends TargetImpl {
MageObject targetSource = game.getObject(source);
for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
Player player = game.getPlayer(playerId);
if (player != null && (notTarget || player.canBeTargetedBy(targetSource, sourceControllerId, game)) && filter.match(player, sourceControllerId, source, game)) {
if (player != null && (notTarget || player.canBeTargetedBy(targetSource, sourceControllerId, source, game)) && filter.match(player, sourceControllerId, source, game)) {
possibleTargets.add(playerId);
}
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) {
if ((notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) && filter.match(permanent, sourceControllerId, source, game)) {
if ((notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) && filter.match(permanent, sourceControllerId, source, game)) {
possibleTargets.add(permanent.getId());
}
}

View file

@ -71,11 +71,11 @@ public abstract class TargetPermanentOrPlayerAmount extends TargetAmount {
if (source != null) {
MageObject targetSource = source.getSourceObject(game);
if (permanent != null) {
return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game)
return permanent.canBeTargetedBy(targetSource, source.getControllerId(), source, game)
&& filter.match(permanent, source.getControllerId(), source, game);
}
if (player != null) {
return player.canBeTargetedBy(targetSource, source.getControllerId(), game)
return player.canBeTargetedBy(targetSource, source.getControllerId(), source, game)
&& filter.match(player, game);
}
}
@ -99,7 +99,7 @@ public abstract class TargetPermanentOrPlayerAmount extends TargetAmount {
for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
Player player = game.getPlayer(playerId);
if (player == null
|| !player.canBeTargetedBy(targetSource, sourceControllerId, game)
|| !player.canBeTargetedBy(targetSource, sourceControllerId, source, game)
|| !filter.match(player, game)) {
continue;
}
@ -109,7 +109,7 @@ public abstract class TargetPermanentOrPlayerAmount extends TargetAmount {
}
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) {
if (!permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) {
if (!permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
continue;
}
count++;
@ -160,7 +160,7 @@ public abstract class TargetPermanentOrPlayerAmount extends TargetAmount {
.stream()
.map(game::getPlayer)
.filter(Objects::nonNull)
.filter(player -> player.canBeTargetedBy(targetSource, sourceControllerId, game)
.filter(player -> player.canBeTargetedBy(targetSource, sourceControllerId, source, game)
&& filter.match(player, game)
)
.map(Player::getId)
@ -170,7 +170,7 @@ public abstract class TargetPermanentOrPlayerAmount extends TargetAmount {
.getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)
.stream()
.filter(Objects::nonNull)
.filter(permanent -> permanent.canBeTargetedBy(targetSource, sourceControllerId, game))
.filter(permanent -> permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game))
.map(Permanent::getId)
.forEach(possibleTargets::add);

View file

@ -57,7 +57,7 @@ public class TargetPermanentOrSuspendedCard extends TargetImpl {
public boolean canChoose(UUID sourceControllerId, Ability source, Game game) {
MageObject sourceObject = game.getObject(source);
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) {
if (permanent.canBeTargetedBy(sourceObject, sourceControllerId, game) && filter.match(permanent, sourceControllerId, source, game)) {
if (permanent.canBeTargetedBy(sourceObject, sourceControllerId, source, game) && filter.match(permanent, sourceControllerId, source, game)) {
return true;
}
}
@ -74,7 +74,7 @@ public class TargetPermanentOrSuspendedCard extends TargetImpl {
Set<UUID> possibleTargets = new HashSet<>(20);
MageObject sourceObject = game.getObject(source);
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) {
if (permanent.canBeTargetedBy(sourceObject, sourceControllerId, game) && filter.match(permanent, sourceControllerId, source, game)) {
if (permanent.canBeTargetedBy(sourceObject, sourceControllerId, source, game) && filter.match(permanent, sourceControllerId, source, game)) {
possibleTargets.add(permanent.getId());
}
}
@ -102,7 +102,7 @@ public class TargetPermanentOrSuspendedCard extends TargetImpl {
if (permanent != null) {
if (source != null) {
MageObject targetSource = game.getObject(source);
return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game)
return permanent.canBeTargetedBy(targetSource, source.getControllerId(), source, game)
&& filter.match(permanent, source.getControllerId(), source, game);
} else {
return filter.match(permanent, game);

View file

@ -89,7 +89,7 @@ public class TargetSpellOrPermanent extends TargetImpl {
if (permanent != null) {
if (source != null) {
MageObject targetSource = game.getObject(source);
return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game)
return permanent.canBeTargetedBy(targetSource, source.getControllerId(), source, game)
&& filter.match(permanent, source.getControllerId(), source, game);
} else {
return filter.match(permanent, game);
@ -132,7 +132,7 @@ public class TargetSpellOrPermanent extends TargetImpl {
}
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceControllerId, source, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game) && filter.match(permanent, sourceControllerId, source, game)) {
count++;
if (count >= this.minNumberOfTargets) {
return true;
@ -189,7 +189,7 @@ public class TargetSpellOrPermanent extends TargetImpl {
}
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceControllerId, source, game)) {
if (permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game) && filter.match(permanent, sourceControllerId, source, game)) {
possibleTargets.add(permanent.getId());
}
}