mirror of
https://github.com/magefree/mage.git
synced 2025-12-22 03:22:00 -08:00
More targets (#13776)
This commit is contained in:
parent
2fedf9c211
commit
a935045e1f
6 changed files with 101 additions and 177 deletions
|
|
@ -42,10 +42,13 @@ public final class AlaniaDivergentStorm extends CardImpl {
|
||||||
// Whenever you cast a spell, if it's the first instant spell, the first sorcery spell, or the first Otter
|
// Whenever you cast a spell, if it's the first instant spell, the first sorcery spell, or the first Otter
|
||||||
// spell other than Alania you've cast this turn, you may have target opponent draw a card. If you do, copy
|
// spell other than Alania you've cast this turn, you may have target opponent draw a card. If you do, copy
|
||||||
// that spell. You may choose new targets for the copy.
|
// that spell. You may choose new targets for the copy.
|
||||||
this.addAbility(new SpellCastControllerTriggeredAbility(
|
Ability ability = new SpellCastControllerTriggeredAbility(
|
||||||
new DoIfCostPaid(new CopyTargetStackObjectEffect(true), new AlaniaDivergentStormCost()),
|
new DoIfCostPaid(new CopyTargetStackObjectEffect(true).setText("copy that spell. You may choose new targets for the copy")
|
||||||
|
, new AlaniaDivergentStormCost()),
|
||||||
null, false, SetTargetPointer.SPELL
|
null, false, SetTargetPointer.SPELL
|
||||||
).withInterveningIf(AlaniaDivergentStormCondition.instance), new AlaniaDivergentStormWatcher());
|
).withInterveningIf(AlaniaDivergentStormCondition.instance);
|
||||||
|
ability.addTarget(new TargetOpponent());
|
||||||
|
this.addAbility(ability, new AlaniaDivergentStormWatcher());
|
||||||
}
|
}
|
||||||
|
|
||||||
private AlaniaDivergentStorm(final AlaniaDivergentStorm card) {
|
private AlaniaDivergentStorm(final AlaniaDivergentStorm card) {
|
||||||
|
|
@ -58,12 +61,10 @@ public final class AlaniaDivergentStorm extends CardImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Based on MarathWillOfTheWildRemoveCountersCost
|
|
||||||
class AlaniaDivergentStormCost extends CostImpl {
|
class AlaniaDivergentStormCost extends CostImpl {
|
||||||
|
|
||||||
AlaniaDivergentStormCost() {
|
AlaniaDivergentStormCost() {
|
||||||
this.text = "have target opponent draw a card";
|
this.text = "have target opponent draw a card";
|
||||||
this.addTarget(new TargetOpponent());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private AlaniaDivergentStormCost(AlaniaDivergentStormCost cost) {
|
private AlaniaDivergentStormCost(AlaniaDivergentStormCost cost) {
|
||||||
|
|
@ -73,32 +74,18 @@ class AlaniaDivergentStormCost extends CostImpl {
|
||||||
@Override
|
@Override
|
||||||
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
|
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
|
||||||
Player player = game.getPlayer(controllerId);
|
Player player = game.getPlayer(controllerId);
|
||||||
if (player == null) {
|
Player opponent = game.getPlayer(source.getFirstTarget());
|
||||||
return false;
|
return player != null && opponent != null;
|
||||||
}
|
|
||||||
for (UUID opponentID : game.getOpponents(controllerId)) {
|
|
||||||
Player opponent = game.getPlayer(opponentID);
|
|
||||||
if (opponent == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (opponent.canBeTargetedBy(source.getSourceObject(game), controllerId, source, game)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
|
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
|
||||||
this.getTargets().clearChosen();
|
|
||||||
paid = false;
|
paid = false;
|
||||||
if (this.getTargets().choose(Outcome.DrawCard, controllerId, source.getSourceId(), source, game)) {
|
Player opponent = game.getPlayer(source.getFirstTarget());
|
||||||
Player opponent = game.getPlayer(this.getTargets().getFirstTarget());
|
if (opponent == null || !opponent.canRespond()) {
|
||||||
if (opponent == null || !opponent.canRespond()) {
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
paid = opponent.drawCards(1, source, game) > 0;
|
|
||||||
}
|
}
|
||||||
|
paid = opponent.drawCards(1, source, game) > 0;
|
||||||
return paid;
|
return paid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,16 +11,16 @@ import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.SubType;
|
import mage.constants.SubType;
|
||||||
import mage.filter.common.FilterCreaturePermanent;
|
import mage.filter.StaticFilters;
|
||||||
import mage.filter.predicate.permanent.ControllerIdPredicate;
|
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.players.Player;
|
|
||||||
import mage.target.TargetPermanent;
|
import mage.target.TargetPermanent;
|
||||||
|
import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
*
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com
|
||||||
*/
|
*/
|
||||||
public final class CyclopsGladiator extends CardImpl {
|
public final class CyclopsGladiator extends CardImpl {
|
||||||
|
|
@ -36,6 +36,8 @@ public final class CyclopsGladiator extends CardImpl {
|
||||||
// Whenever Cyclops Gladiator attacks, you may have it deal damage equal to its power to target creature defending player controls.
|
// Whenever Cyclops Gladiator attacks, you may have it deal damage equal to its power to target creature defending player controls.
|
||||||
// If you do, that creature deals damage equal to its power to Cyclops Gladiator.
|
// If you do, that creature deals damage equal to its power to Cyclops Gladiator.
|
||||||
Ability ability = new AttacksTriggeredAbility(new CyclopsGladiatorEffect(), true);
|
Ability ability = new AttacksTriggeredAbility(new CyclopsGladiatorEffect(), true);
|
||||||
|
ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE));
|
||||||
|
ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,23 +65,12 @@ class CyclopsGladiatorEffect extends OneShotEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
UUID defenderId = game.getCombat().getDefenderId(source.getSourceId());
|
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||||
if (defenderId != null) {
|
Permanent cyclops = game.getPermanent(source.getSourceId());
|
||||||
FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls");
|
if (permanent != null && cyclops != null) {
|
||||||
filter.add(new ControllerIdPredicate(defenderId));
|
permanent.damage(cyclops.getPower().getValue(), cyclops.getId(), source, game, false, true);
|
||||||
TargetPermanent target = new TargetPermanent(filter);
|
cyclops.damage(permanent.getPower().getValue(), permanent.getId(), source, game, false, true);
|
||||||
Player player = game.getPlayer(source.getControllerId());
|
return true;
|
||||||
if (target.canChoose(source.getControllerId(), source, game)) {
|
|
||||||
if (player != null && player.chooseTarget(Outcome.Detriment, target, source, game)) {
|
|
||||||
Permanent permanent = game.getPermanent(target.getFirstTarget());
|
|
||||||
Permanent cyclops = game.getPermanent(source.getSourceId());
|
|
||||||
if (permanent != null && cyclops != null) {
|
|
||||||
permanent.damage(cyclops.getPower().getValue(), cyclops.getId(), source, game, false, true);
|
|
||||||
cyclops.damage(permanent.getPower().getValue(), permanent.getId(), source, game, false, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,25 @@
|
||||||
package mage.cards.j;
|
package mage.cards.j;
|
||||||
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
|
import mage.MageObject;
|
||||||
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.DiesThisOrAnotherTriggeredAbility;
|
import mage.abilities.common.DiesThisOrAnotherTriggeredAbility;
|
||||||
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
|
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
|
||||||
import mage.abilities.keyword.FlyingAbility;
|
import mage.abilities.keyword.FlyingAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.ComparisonType;
|
|
||||||
import mage.constants.SubType;
|
import mage.constants.SubType;
|
||||||
import mage.filter.FilterCard;
|
import mage.filter.FilterCard;
|
||||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||||
import mage.filter.common.FilterCreatureCard;
|
import mage.filter.common.FilterCreatureCard;
|
||||||
import mage.filter.predicate.Predicates;
|
import mage.filter.predicate.ObjectSourcePlayer;
|
||||||
|
import mage.filter.predicate.ObjectSourcePlayerPredicate;
|
||||||
import mage.filter.predicate.mageobject.AbilityPredicate;
|
import mage.filter.predicate.mageobject.AbilityPredicate;
|
||||||
import mage.filter.predicate.mageobject.MageObjectReferencePredicate;
|
|
||||||
import mage.filter.predicate.mageobject.ManaValuePredicate;
|
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.game.events.ZoneChangeEvent;
|
|
||||||
import mage.target.common.TargetCardInYourGraveyard;
|
import mage.target.common.TargetCardInYourGraveyard;
|
||||||
|
import mage.util.CardUtil;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
@ -27,6 +27,14 @@ import java.util.UUID;
|
||||||
* @author notgreat
|
* @author notgreat
|
||||||
*/
|
*/
|
||||||
public final class JackdawSavior extends CardImpl {
|
public final class JackdawSavior extends CardImpl {
|
||||||
|
private static final FilterControlledCreaturePermanent flyingFilter = new FilterControlledCreaturePermanent("creature you control with flying");
|
||||||
|
private static final FilterCard filterCard = new FilterCreatureCard("another target creature card with lesser mana value from your graveyard");
|
||||||
|
|
||||||
|
static {
|
||||||
|
flyingFilter.add(new AbilityPredicate(FlyingAbility.class));
|
||||||
|
filterCard.add(JackdawSaviorPredicate.instance);
|
||||||
|
}
|
||||||
|
|
||||||
public JackdawSavior(UUID ownerId, CardSetInfo setInfo) {
|
public JackdawSavior(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}");
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}");
|
||||||
|
|
||||||
|
|
@ -39,7 +47,9 @@ public final class JackdawSavior extends CardImpl {
|
||||||
this.addAbility(FlyingAbility.getInstance());
|
this.addAbility(FlyingAbility.getInstance());
|
||||||
|
|
||||||
// Whenever Jackdaw Savior or another creature you control with flying dies, return another target creature card with lesser mana value from your graveyard to the battlefield.
|
// Whenever Jackdaw Savior or another creature you control with flying dies, return another target creature card with lesser mana value from your graveyard to the battlefield.
|
||||||
this.addAbility(new JackdawSaviorDiesThisOrAnotherTriggeredAbility());
|
Ability ability = new DiesThisOrAnotherTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), false, flyingFilter);
|
||||||
|
ability.addTarget(new TargetCardInYourGraveyard(filterCard));
|
||||||
|
this.addAbility(ability);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JackdawSavior(final JackdawSavior card) {
|
private JackdawSavior(final JackdawSavior card) {
|
||||||
|
|
@ -52,40 +62,14 @@ public final class JackdawSavior extends CardImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class JackdawSaviorDiesThisOrAnotherTriggeredAbility extends DiesThisOrAnotherTriggeredAbility {
|
enum JackdawSaviorPredicate implements ObjectSourcePlayerPredicate<MageObject> {
|
||||||
private static final FilterControlledCreaturePermanent flyingFilter = new FilterControlledCreaturePermanent("creature you control with flying");
|
instance;
|
||||||
|
|
||||||
static {
|
|
||||||
flyingFilter.add(new AbilityPredicate(FlyingAbility.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
public JackdawSaviorDiesThisOrAnotherTriggeredAbility() {
|
|
||||||
super(new ReturnFromGraveyardToBattlefieldTargetEffect().setText(
|
|
||||||
"return another target creature card with lesser mana value from your graveyard to the battlefield"),
|
|
||||||
false, flyingFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected JackdawSaviorDiesThisOrAnotherTriggeredAbility(final JackdawSaviorDiesThisOrAnotherTriggeredAbility ability) {
|
|
||||||
super(ability);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JackdawSaviorDiesThisOrAnotherTriggeredAbility copy() {
|
public boolean apply(ObjectSourcePlayer<MageObject> input, Game game) {
|
||||||
return new JackdawSaviorDiesThisOrAnotherTriggeredAbility(this);
|
Permanent diedCreature = CardUtil.getEffectValueFromAbility(input.getSource(), "creatureDied", Permanent.class).orElse(null);
|
||||||
}
|
return diedCreature != null
|
||||||
|
&& !input.getObject().getId().equals(diedCreature.getId())
|
||||||
@Override
|
&& input.getObject().getManaValue() < diedCreature.getManaValue();
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
|
||||||
if (super.checkTrigger(event, game)) {
|
|
||||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
|
||||||
FilterCard filter = new FilterCreatureCard();
|
|
||||||
filter.add(Predicates.not(new MageObjectReferencePredicate(zEvent.getTargetId(), game)));
|
|
||||||
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, zEvent.getTarget().getManaValue()));
|
|
||||||
filter.setMessage("target creature card other than "+zEvent.getTarget().getLogName()+" with mana value less than "+zEvent.getTarget().getManaValue());
|
|
||||||
this.getTargets().clear();
|
|
||||||
this.addTarget(new TargetCardInYourGraveyard(filter));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,25 +12,25 @@ import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.filter.FilterPermanent;
|
import mage.filter.FilterPermanent;
|
||||||
|
import mage.filter.common.FilterCreaturePermanent;
|
||||||
import mage.filter.predicate.Predicates;
|
import mage.filter.predicate.Predicates;
|
||||||
import mage.filter.predicate.mageobject.MageObjectReferencePredicate;
|
|
||||||
import mage.filter.predicate.mageobject.ManaValuePredicate;
|
import mage.filter.predicate.mageobject.ManaValuePredicate;
|
||||||
|
import mage.filter.predicate.permanent.CrewedSourceThisTurnPredicate;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.target.TargetPermanent;
|
import mage.target.TargetPermanent;
|
||||||
import mage.util.CardUtil;
|
|
||||||
import mage.util.functions.CopyApplier;
|
import mage.util.functions.CopyApplier;
|
||||||
import mage.watchers.Watcher;
|
import mage.watchers.Watcher;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.HashMap;
|
||||||
import java.util.stream.Collectors;
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author TheElk801
|
* @author TheElk801
|
||||||
*/
|
*/
|
||||||
public final class MindlinkMech extends CardImpl {
|
public final class MindlinkMech extends CardImpl {
|
||||||
|
|
||||||
public MindlinkMech(UUID ownerId, CardSetInfo setInfo) {
|
public MindlinkMech(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{U}");
|
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{U}");
|
||||||
|
|
||||||
|
|
@ -60,9 +60,18 @@ public final class MindlinkMech extends CardImpl {
|
||||||
|
|
||||||
class MindlinkMechTriggeredAbility extends TriggeredAbilityImpl {
|
class MindlinkMechTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
|
private static final FilterPermanent filter = new FilterCreaturePermanent("nonlegendary creature that crewed it this turn");
|
||||||
|
|
||||||
|
static {
|
||||||
|
filter.add(CrewedSourceThisTurnPredicate.instance);
|
||||||
|
filter.add(Predicates.not(SuperType.LEGENDARY.getPredicate()));
|
||||||
|
}
|
||||||
|
|
||||||
MindlinkMechTriggeredAbility() {
|
MindlinkMechTriggeredAbility() {
|
||||||
super(Zone.BATTLEFIELD, new MindlinkMechEffect());
|
super(Zone.BATTLEFIELD, new MindlinkMechEffect());
|
||||||
this.addWatcher(new MindlinkMechWatcher());
|
this.addWatcher(new MindlinkMechWatcher());
|
||||||
|
this.addTarget(new TargetPermanent(filter));
|
||||||
|
this.setTriggerPhrase("Whenever {this} becomes crewed for the first time each turn");
|
||||||
}
|
}
|
||||||
|
|
||||||
private MindlinkMechTriggeredAbility(final MindlinkMechTriggeredAbility ability) {
|
private MindlinkMechTriggeredAbility(final MindlinkMechTriggeredAbility ability) {
|
||||||
|
|
@ -81,26 +90,13 @@ class MindlinkMechTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
if (!event.getSourceId().equals(getSourceId()) || !MindlinkMechWatcher.checkVehicle(this, game)) {
|
return event.getSourceId().equals(getSourceId()) && MindlinkMechWatcher.checkVehicle(this, game);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
this.getTargets().clear();
|
|
||||||
this.addTarget(new TargetPermanent(MindlinkMechWatcher.makeFilter(this, game)));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getRule() {
|
|
||||||
return "Whenever {this} becomes crewed for the first time each turn, until end of turn, " +
|
|
||||||
"{this} becomes a copy of target nonlegendary creature that crewed it this turn, " +
|
|
||||||
"except it's 4/3, it's a Vehicle artifact in addition to its other types, and it has flying.";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MindlinkMechWatcher extends Watcher {
|
class MindlinkMechWatcher extends Watcher {
|
||||||
|
|
||||||
private final Map<MageObjectReference, Integer> crewCount = new HashMap<>();
|
private final Map<MageObjectReference, Integer> crewCount = new HashMap<>();
|
||||||
private final Map<MageObjectReference, Set<MageObjectReference>> crewMap = new HashMap<>();
|
|
||||||
private static final FilterPermanent invalidFilter = new FilterPermanent();
|
private static final FilterPermanent invalidFilter = new FilterPermanent();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|
@ -114,34 +110,16 @@ class MindlinkMechWatcher extends Watcher {
|
||||||
@Override
|
@Override
|
||||||
public void watch(GameEvent event, Game game) {
|
public void watch(GameEvent event, Game game) {
|
||||||
Permanent vehicle;
|
Permanent vehicle;
|
||||||
Permanent crewer;
|
if (event.getType() == GameEvent.EventType.VEHICLE_CREWED) {
|
||||||
switch (event.getType()) {
|
vehicle = game.getPermanent(event.getTargetId());
|
||||||
case VEHICLE_CREWED:
|
|
||||||
vehicle = game.getPermanent(event.getTargetId());
|
|
||||||
crewer = null;
|
|
||||||
break;
|
|
||||||
case CREWED_VEHICLE:
|
|
||||||
vehicle = game.getPermanent(event.getSourceId());
|
|
||||||
crewer = game.getPermanent(event.getTargetId());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (vehicle == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (crewer == null) {
|
|
||||||
crewCount.compute(new MageObjectReference(vehicle, game), (m, i) -> i == null ? 1 : Integer.sum(i, 1));
|
crewCount.compute(new MageObjectReference(vehicle, game), (m, i) -> i == null ? 1 : Integer.sum(i, 1));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
crewMap.computeIfAbsent(new MageObjectReference(vehicle, game), x -> new HashSet<>()).add(new MageObjectReference(crewer, game));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reset() {
|
public void reset() {
|
||||||
super.reset();
|
super.reset();
|
||||||
crewCount.clear();
|
crewCount.clear();
|
||||||
crewMap.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean checkVehicle(Ability source, Game game) {
|
public static boolean checkVehicle(Ability source, Game game) {
|
||||||
|
|
@ -151,34 +129,14 @@ class MindlinkMechWatcher extends Watcher {
|
||||||
.crewCount
|
.crewCount
|
||||||
.getOrDefault(new MageObjectReference(source), 0) < 2;
|
.getOrDefault(new MageObjectReference(source), 0) < 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FilterPermanent makeFilter(Ability source, Game game) {
|
|
||||||
Set<MageObjectReferencePredicate> predicates = game
|
|
||||||
.getState()
|
|
||||||
.getWatcher(MindlinkMechWatcher.class)
|
|
||||||
.crewMap
|
|
||||||
.computeIfAbsent(new MageObjectReference(game.getPermanent(source.getSourceId()), game), x -> new HashSet<>())
|
|
||||||
.stream()
|
|
||||||
.filter(mor -> {
|
|
||||||
Permanent permanent = mor.getPermanent(game);
|
|
||||||
return permanent != null && !permanent.isLegendary(game) && permanent.isCreature(game);
|
|
||||||
}).map(MageObjectReferencePredicate::new)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
if (predicates.isEmpty()) {
|
|
||||||
return invalidFilter;
|
|
||||||
}
|
|
||||||
FilterPermanent filterPermanent = new FilterPermanent(
|
|
||||||
"nonlegendary creature that crewed " + CardUtil.getSourceName(game, source) + " this turn"
|
|
||||||
);
|
|
||||||
filterPermanent.add(Predicates.or(predicates));
|
|
||||||
return filterPermanent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MindlinkMechEffect extends OneShotEffect {
|
class MindlinkMechEffect extends OneShotEffect {
|
||||||
|
|
||||||
MindlinkMechEffect() {
|
MindlinkMechEffect() {
|
||||||
super(Outcome.Benefit);
|
super(Outcome.Benefit);
|
||||||
|
this.setText("until end of turn, {this} becomes a copy of target nonlegendary creature that crewed it this turn, " +
|
||||||
|
"except it's 4/3, it's a Vehicle artifact in addition to its other types, and it has flying.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private MindlinkMechEffect(final MindlinkMechEffect effect) {
|
private MindlinkMechEffect(final MindlinkMechEffect effect) {
|
||||||
|
|
@ -212,4 +170,4 @@ class MindlinkMechApplier extends CopyApplier {
|
||||||
blueprint.getAbilities().add(FlyingAbility.getInstance());
|
blueprint.getAbilities().add(FlyingAbility.getInstance());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,15 @@ import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.cards.Cards;
|
import mage.cards.Cards;
|
||||||
|
import mage.cards.CardsImpl;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.filter.StaticFilters;
|
import mage.filter.FilterCard;
|
||||||
|
import mage.filter.common.FilterPermanentCard;
|
||||||
|
import mage.filter.predicate.card.OwnerIdPredicate;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.target.common.TargetCardInGraveyard;
|
import mage.target.common.TargetCardInGraveyard;
|
||||||
|
import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
@ -20,6 +24,7 @@ import java.util.UUID;
|
||||||
* @author Xanderhall
|
* @author Xanderhall
|
||||||
*/
|
*/
|
||||||
public final class NeyamShaiMurad extends CardImpl {
|
public final class NeyamShaiMurad extends CardImpl {
|
||||||
|
FilterCard filter = new FilterPermanentCard("permanent card from their graveyard");
|
||||||
|
|
||||||
public NeyamShaiMurad(UUID ownerId, CardSetInfo setInfo) {
|
public NeyamShaiMurad(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{B}");
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{B}");
|
||||||
|
|
@ -32,10 +37,11 @@ public final class NeyamShaiMurad extends CardImpl {
|
||||||
|
|
||||||
// Rogue Trader -- Whenever Neyam Shai Murad deals combat damage to a player, you may have that player return target permanent card from their graveyard to their hand.
|
// Rogue Trader -- Whenever Neyam Shai Murad deals combat damage to a player, you may have that player return target permanent card from their graveyard to their hand.
|
||||||
// If you do, that player chooses a permanent card in your graveyard, then you put it onto the battlefield under your control.
|
// If you do, that player chooses a permanent card in your graveyard, then you put it onto the battlefield under your control.
|
||||||
|
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new NeyamShaiMuradEffect(), true, true)
|
||||||
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new NeyamShaiMuradEffect(), true, true)
|
.withFlavorWord("Rogue Trader");
|
||||||
.withFlavorWord("Rogue Trader")
|
ability.addTarget(new TargetCardInGraveyard(filter));
|
||||||
); //TODO: The first should target when triggered, not on resolution
|
ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster(true));
|
||||||
|
this.addAbility(ability);
|
||||||
}
|
}
|
||||||
|
|
||||||
private NeyamShaiMurad(final NeyamShaiMurad card) {
|
private NeyamShaiMurad(final NeyamShaiMurad card) {
|
||||||
|
|
@ -67,28 +73,26 @@ class NeyamShaiMuradEffect extends OneShotEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
|
Object playerId = getValue("damagedPlayer");
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
Cards playerGraveyard = player.getGraveyard();
|
if (controller == null || !(playerId instanceof UUID)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = game.getPlayer((UUID) playerId);
|
||||||
|
Cards cards = new CardsImpl(getTargetPointer().getTargets(game, source));
|
||||||
|
cards.retainZone(Zone.GRAVEYARD, game); //verify the target card is still in the graveyard
|
||||||
|
if (player == null || cards.isEmpty() || !player.moveCards(cards, Zone.HAND, source, game)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Cards controllerGraveyard = controller.getGraveyard();
|
Cards controllerGraveyard = controller.getGraveyard();
|
||||||
if (player == null || controller == null || playerGraveyard.isEmpty()) {
|
FilterCard filter = new FilterPermanentCard("a permanent card in your graveyard");
|
||||||
|
filter.add(new OwnerIdPredicate(source.getControllerId()));
|
||||||
|
TargetCardInGraveyard target = new TargetCardInGraveyard(1, 1, filter, true);
|
||||||
|
if (!target.choose(Outcome.PutCreatureInPlay, player.getId(), source, game)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetCardInGraveyard target = new TargetCardInGraveyard(StaticFilters.FILTER_CARD_PERMANENT);
|
|
||||||
|
|
||||||
if (!controller.chooseTarget(Outcome.ReturnToHand, playerGraveyard, target, source, game)
|
|
||||||
|| !playerGraveyard.contains(target.getFirstTarget())
|
|
||||||
|| !player.moveCards(playerGraveyard.get(target.getFirstTarget(), game), Zone.HAND, source, game)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
target.clearChosen();
|
|
||||||
target.withNotTarget(true);
|
|
||||||
if (!player.choose(Outcome.PutCreatureInPlay, controllerGraveyard, target, source, game)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return controllerGraveyard.contains(target.getFirstTarget()) && controller.moveCards(controllerGraveyard.get(target.getFirstTarget(), game), Zone.BATTLEFIELD, source, game);
|
return controllerGraveyard.contains(target.getFirstTarget()) && controller.moveCards(controllerGraveyard.get(target.getFirstTarget(), game), Zone.BATTLEFIELD, source, game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,8 @@ public class AlaniaDivergentStormTest extends CardTestPlayerBase {
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, alania, true);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, alania, true);
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Coruscation Mage", true);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Coruscation Mage", true);
|
||||||
setChoice(playerA, "No"); // Offspring?
|
setChoice(playerA, "No"); // Offspring?
|
||||||
|
addTarget(playerA, playerB); // Who draws?
|
||||||
setChoice(playerA, "Yes"); // Copy spell?
|
setChoice(playerA, "Yes"); // Copy spell?
|
||||||
setChoice(playerA, "PlayerB"); // Who draws?
|
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
|
@ -61,8 +61,8 @@ public class AlaniaDivergentStormTest extends CardTestPlayerBase {
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, alania, true);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, alania, true);
|
||||||
|
|
||||||
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Stormcatch Mentor", true);
|
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Stormcatch Mentor", true);
|
||||||
|
addTarget(playerA, playerB); // Who draws?
|
||||||
setChoice(playerA, "Yes"); // Copy spell?
|
setChoice(playerA, "Yes"); // Copy spell?
|
||||||
setChoice(playerA, "PlayerB"); // Who draws?
|
|
||||||
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Coruscation Mage", true);
|
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Coruscation Mage", true);
|
||||||
setChoice(playerA, "No"); // Offspring?
|
setChoice(playerA, "No"); // Offspring?
|
||||||
|
|
||||||
|
|
@ -93,16 +93,16 @@ public class AlaniaDivergentStormTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, alania, true);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, alania, true);
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Frolicking Familiar", true);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Frolicking Familiar", true);
|
||||||
|
addTarget(playerA, playerB); // Who draws?
|
||||||
setChoice(playerA, "Yes"); // Copy spell?
|
setChoice(playerA, "Yes"); // Copy spell?
|
||||||
setChoice(playerA, "PlayerB"); // Who draws?
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Coruscation Mage", true);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Coruscation Mage", true);
|
||||||
setChoice(playerA, "No"); // Offspring?
|
setChoice(playerA, "No"); // Offspring?
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Blow Off Steam", true);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Blow Off Steam", true);
|
||||||
setChoice(playerA, "Whenever you cast an instant", 2); // Add Frolicking Familiar triggers first
|
setChoice(playerA, "Whenever you cast an instant", 2); // Add Frolicking Familiar triggers first
|
||||||
setChoice(playerA, "Whenever you cast a noncreature"); // Add Coruscation Mage trigger
|
setChoice(playerA, "Whenever you cast a noncreature"); // Add Coruscation Mage trigger
|
||||||
// Alania's trigger will add last
|
// Alania's trigger will add last
|
||||||
|
addTarget(playerA, playerB); // Who draws?
|
||||||
setChoice(playerA, "Yes"); // Copy spell?
|
setChoice(playerA, "Yes"); // Copy spell?
|
||||||
setChoice(playerA, "PlayerB"); // Who draws?
|
|
||||||
addTarget(playerA, playerB);
|
addTarget(playerA, playerB);
|
||||||
setChoice(playerA, "No"); // Change target?
|
setChoice(playerA, "No"); // Change target?
|
||||||
|
|
||||||
|
|
@ -137,8 +137,8 @@ public class AlaniaDivergentStormTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, alania, true);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, alania, true);
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Acrobatic Leap", true);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Acrobatic Leap", true);
|
||||||
|
addTarget(playerA, playerB); // Who draws?
|
||||||
setChoice(playerA, "Yes"); // Copy spell?
|
setChoice(playerA, "Yes"); // Copy spell?
|
||||||
setChoice(playerA, "PlayerB"); // Who draws?
|
|
||||||
addTarget(playerA, alania); // Target creature
|
addTarget(playerA, alania); // Target creature
|
||||||
setChoice(playerA, "No"); // Change target?
|
setChoice(playerA, "No"); // Change target?
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ancestral Recall", true);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ancestral Recall", true);
|
||||||
|
|
@ -170,8 +170,8 @@ public class AlaniaDivergentStormTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, alania, true);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, alania, true);
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gift of the Fae", true);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gift of the Fae", true);
|
||||||
|
addTarget(playerA, playerB); // Who draws?
|
||||||
setChoice(playerA, "Yes"); // Copy spell?
|
setChoice(playerA, "Yes"); // Copy spell?
|
||||||
setChoice(playerA, "PlayerB"); // Who draws?
|
|
||||||
addTarget(playerA, alania); // Target creature
|
addTarget(playerA, alania); // Target creature
|
||||||
setChoice(playerA, "No"); // Change target?
|
setChoice(playerA, "No"); // Change target?
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Maximize Velocity", true);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Maximize Velocity", true);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue