Refactoring + Fix of several cards (#8699)

* Simplified Azorius Aethermage

* - Flattened the if statements
- Renamed the custom effects and abilities to be more readable
- Changed certain functiosn to be private

* Flatten Thieves Auction

* Flatten Possibility Storm

* Flatten Aminatous Augury

* Minor refactoring

* Flattening and adjusting access modifiers

* Aetherspouts should have been using getPlayersInRange. Current implementation was affecting all players

* Simplified Akoum Hellkite

* Simplified Ali From Cairo

* Flattened An-Havva Constable

* Flattened Aura Finesse and Autum Willow

* Fixed All Hallow's Eve since it didn't work.

* Several small simplifications

* Flattening/Simplification of several classes

* Added test for Azorius Aethermage

* Added test for Abandoned Sarcophagus

* Updated test with docstring instead of comment

* Update AzoriusAethermageTest.java

* Update BattlegateMimic.java

* Update AetherworksMarvel.java

* Update AetherworksMarvel.java

* Update AzoriusAethermageTest.java

* Update AzoriusAethermageTest.java

Co-authored-by: Jeff Wadsworth <jeffwadsworth@users.noreply.github.com>
This commit is contained in:
Alex Vasile 2022-03-15 17:57:16 -04:00 committed by GitHub
parent 8dc99256d5
commit 6a7b2e80ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
65 changed files with 1471 additions and 1258 deletions

View file

@ -34,7 +34,7 @@ public final class AbandonReason extends CardImpl {
this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2));
// Madness {1}{R}
this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{R}")));
this.addAbility(new MadnessAbility(this, new ManaCostsImpl<>("{1}{R}")));
}
private AbandonReason(final AbandonReason card) {

View file

@ -3,6 +3,7 @@ package mage.cards.a;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ReplacementEffectImpl;
@ -25,13 +26,17 @@ import mage.watchers.Watcher;
*/
public final class AbandonedSarcophagus extends CardImpl {
private static final FilterCard filter = new FilterCard("nonland cards with cycling");
static {
filter.add(Predicates.not(CardType.LAND.getPredicate()));
filter.add(new AbilityPredicate(CyclingAbility.class));
}
public AbandonedSarcophagus(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
// You may cast nonland cards with cycling from your graveyard.
FilterCard filter = new FilterCard("nonland cards with cycling");
filter.add(Predicates.not(CardType.LAND.getPredicate()));
filter.add(new AbilityPredicate(CyclingAbility.class));
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD,
new PlayFromNotOwnHandZoneAllEffect(filter,
Zone.GRAVEYARD, true, TargetController.YOU, Duration.WhileOnBattlefield)
@ -77,16 +82,20 @@ class AbandonedSarcophagusReplacementEffect extends ReplacementEffectImpl {
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null) {
return controller.moveCards(permanent, Zone.EXILED, source, game);
}
Card card = game.getCard(event.getTargetId());
if (card != null) {
return controller.moveCards(card, Zone.EXILED, source, game);
}
if (controller == null) {
return false;
}
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null) {
return controller.moveCards(permanent, Zone.EXILED, source, game);
}
Card card = game.getCard(event.getTargetId());
if (card != null) {
return controller.moveCards(card, Zone.EXILED, source, game);
}
return false;
}
@ -97,32 +106,46 @@ class AbandonedSarcophagusReplacementEffect extends ReplacementEffectImpl {
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
boolean cardWasCycledThisTurn = false;
boolean cardHasCycling = false;
if (!(((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD)) {
return false;
}
Player controller = game.getPlayer(source.getControllerId());
AbandonedSarcophagusWatcher watcher = game.getState().getWatcher(AbandonedSarcophagusWatcher.class);
Card card = game.getCard(event.getTargetId());
if (card == null
|| controller == null
|| watcher == null
|| !card.isOwnedBy(controller.getId())) {
if (controller == null) {
return false;
}
Card card = game.getCard(event.getTargetId());
if (card == null) {
return false;
}
if (!card.isOwnedBy(controller.getId())) {
return false;
}
AbandonedSarcophagusWatcher watcher = game.getState().getWatcher(AbandonedSarcophagusWatcher.class);
if (watcher == null) {
return false;
}
boolean cardHasCycling = false;
for (Ability ability : card.getAbilities(game)) {
if (ability instanceof CyclingAbility) {
cardHasCycling = true;
break;
}
}
Cards cards = watcher.getCardsCycledThisTurn(controller.getId());
for (Card c : cards.getCards(game)) {
if (c == card) {
boolean cardWasCycledThisTurn = false;
for (Card cardCycledThisTurn : cards.getCards(game)) {
if (cardCycledThisTurn == card) {
cardWasCycledThisTurn = true;
watcher.getCardsCycledThisTurn(controller.getId()).remove(card); //remove reference to the card as it is no longer needed
}
}
return !cardWasCycledThisTurn && cardHasCycling;
}
}
@ -137,17 +160,26 @@ class AbandonedSarcophagusWatcher extends Watcher {
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.CYCLE_CARD) {
Card card = game.getCard(event.getSourceId());
Player controller = game.getPlayer(event.getPlayerId());
if (card != null
&& controller != null
&& card.isOwnedBy(controller.getId())) {
Cards c = getCardsCycledThisTurn(event.getPlayerId());
c.add(card);
cycledCardsThisTurn.put(event.getPlayerId(), c);
}
if (event.getType() != GameEvent.EventType.CYCLE_CARD) {
return;
}
Card card = game.getCard(event.getSourceId());
if (card == null) {
return;
}
Player controller = game.getPlayer(event.getPlayerId());
if (controller == null) {
return;
}
if (!card.isOwnedBy(controller.getId())) {
return;
}
Cards c = getCardsCycledThisTurn(event.getPlayerId());
c.add(card);
cycledCardsThisTurn.put(event.getPlayerId(), c);
}
public Cards getCardsCycledThisTurn(UUID playerId) {

View file

@ -54,7 +54,7 @@ class ActOfAuthorityEffect extends OneShotEffect {
this.staticText = "you may exile target artifact or enchantment. If you do, its controller gains control of {this}";
}
public ActOfAuthorityEffect(final ActOfAuthorityEffect effect) {
private ActOfAuthorityEffect(final ActOfAuthorityEffect effect) {
super(effect);
}
@ -66,29 +66,32 @@ class ActOfAuthorityEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (targetPermanent != null && new ExileTargetEffect().apply(game, source)) {
Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game);
if (sourcePermanent != null) {
ContinuousEffect effect = new ActOfAuthorityGainControlEffect(Duration.Custom, targetPermanent.getControllerId());
effect.setTargetPointer(new FixedTarget(sourcePermanent, game));
game.addEffect(effect, source);
}
return true;
}
return false;
if (targetPermanent == null) { return false; }
ExileTargetEffect exileTargetEffect = new ExileTargetEffect();
if (!exileTargetEffect.apply(game, source)) { return false; }
Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game);
if (sourcePermanent == null) { return true; }
ContinuousEffect effect = new ActOfAuthorityGainControlEffect(Duration.Custom, targetPermanent.getControllerId());
effect.setTargetPointer(new FixedTarget(sourcePermanent, game));
game.addEffect(effect, source);
return true;
}
}
// TODO: These and it's duplicates can probably be replaced by a gain control of effect
class ActOfAuthorityGainControlEffect extends ContinuousEffectImpl {
UUID controller;
private final UUID controller;
public ActOfAuthorityGainControlEffect(Duration duration, UUID controller) {
super(duration, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl);
this.controller = controller;
}
public ActOfAuthorityGainControlEffect(final ActOfAuthorityGainControlEffect effect) {
private ActOfAuthorityGainControlEffect(final ActOfAuthorityGainControlEffect effect) {
super(effect);
this.controller = effect.controller;
}
@ -100,14 +103,16 @@ class ActOfAuthorityGainControlEffect extends ContinuousEffectImpl {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (targetPointer != null) {
Permanent permanent;
if (targetPointer == null) {
permanent = game.getPermanent(source.getFirstTarget());
} else {
permanent = game.getPermanent(targetPointer.getFirst(game, source));
}
if (permanent != null) {
return permanent.changeControllerId(controller, game, source);
}
return false;
if (permanent == null) { return false; }
return permanent.changeControllerId(controller, game, source);
}
@Override

View file

@ -84,18 +84,17 @@ class AdarkarValkyrieEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
DelayedTriggeredAbility delayedAbility = new AdarkarValkyrieDelayedTriggeredAbility(new MageObjectReference(permanent, game));
game.addDelayedTriggeredAbility(delayedAbility, source);
return true;
}
return false;
if (permanent == null) { return false; }
DelayedTriggeredAbility delayedAbility = new AdarkarValkyrieDelayedTriggeredAbility(new MageObjectReference(permanent, game));
game.addDelayedTriggeredAbility(delayedAbility, source);
return true;
}
}
class AdarkarValkyrieDelayedTriggeredAbility extends DelayedTriggeredAbility {
protected MageObjectReference mor;
private final MageObjectReference mor;
public AdarkarValkyrieDelayedTriggeredAbility(MageObjectReference mor) {
super(new ReturnToBattlefieldUnderYourControlTargetEffect(), Duration.EndOfTurn);
@ -119,14 +118,17 @@ class AdarkarValkyrieDelayedTriggeredAbility extends DelayedTriggeredAbility {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (((ZoneChangeEvent) event).isDiesEvent()
&& mor.refersTo(((ZoneChangeEvent) event).getTarget(), game)
&& game.getState().getZone(event.getTargetId()) == Zone.GRAVEYARD) { // must be in the graveyard
getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
return true;
if (!((ZoneChangeEvent) event).isDiesEvent()) { return false; }
}
return false;
if (!mor.refersTo(((ZoneChangeEvent) event).getTarget(), game)) { return false; }
// TODO: Must it? Why?
// Must be in the graveyard
if (game.getState().getZone(event.getTargetId()) != Zone.GRAVEYARD) { return false; }
getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
return true;
}
@Override

View file

@ -91,7 +91,7 @@ class DamagedByPiratesWatcher extends Watcher {
}
public boolean damagedByEnoughPirates(UUID sourceId) {
return damageSourceIds.keySet().contains(sourceId) && damageSourceIds.get(sourceId).size() > 2;
return damageSourceIds.containsKey(sourceId) && damageSourceIds.get(sourceId).size() > 2;
}
@Override

View file

@ -110,6 +110,6 @@ enum AerialSurveyorHint implements Hint {
@Override
public AerialSurveyorHint copy() {
return this;
return instance;
}
}

View file

@ -44,11 +44,13 @@ public final class Aetherspouts extends CardImpl {
/*
7/18/2014 The owner of each attacking creature chooses whether to put it on the top or bottom
of their library. The active player (the player whose turn it is) makes all of
their choices first, followed by each other player in turn order.
of their library.
The active player (the player whose turn it is) makes all of their choices first,
followed by each other player in turn order.
7/18/2014 If an effect puts two or more cards on the top or bottom of a library at the same time,
the owner of those cards may arrange them in any order. That library's owner doesn't reveal
the order in which the cards go into their library.
the owner of those cards may arrange them in any order.
That library's owner doesn't reveal the order in which the cards go into their library.
*/
class AetherspoutsEffect extends OneShotEffect {
@ -57,7 +59,7 @@ class AetherspoutsEffect extends OneShotEffect {
this.staticText = "For each attacking creature, its owner puts it on the top or bottom of their library";
}
public AetherspoutsEffect(final AetherspoutsEffect effect) {
private AetherspoutsEffect(final AetherspoutsEffect effect) {
super(effect);
}
@ -70,107 +72,107 @@ class AetherspoutsEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
game.getPlayerList();
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
PlayerList playerList = game.getPlayerList().copy();
playerList.setCurrent(game.getActivePlayerId());
Player player = game.getPlayer(game.getActivePlayerId());
Player activePlayer = player;
do {
List<Permanent> permanentsToTop = new ArrayList<>();
List<Permanent> permanentsToBottom = new ArrayList<>();
for (Permanent permanent : game.getState().getBattlefield().getActivePermanents(new FilterAttackingCreature(), player.getId(), source.getSourceId(), game)) {
if (permanent.isOwnedBy(player.getId())) {
if (player.chooseUse(outcome, "Put " + permanent.getLogName() + " to the top? (else it goes to bottom)", source, game)) {
permanentsToTop.add(permanent);
game.informPlayers(permanent.getLogName() + " goes to the top of " + player.getLogName() + "'s library");
} else {
permanentsToBottom.add(permanent);
game.informPlayers(permanent.getLogName() + " goes to the bottom of " + player.getLogName() + "'s library");
}
}
}
// cards to top
Cards cards = new CardsImpl();
List<Permanent> toLibrary = new ArrayList<>();
for (Permanent permanent : permanentsToTop) {
if (permanent instanceof PermanentToken) {
toLibrary.add(permanent);
} else {
Card card = game.getCard(permanent.getId());
if (card != null) {
cards.add(card);
}
}
}
TargetCard target = new TargetCard(Zone.BATTLEFIELD, new FilterCard("order to put on the top of library (last choosen will be the top most)"));
while (cards.size() > 1) {
if (!player.canRespond()) {
return false;
}
player.choose(Outcome.Neutral, cards, target, game);
Card card = cards.get(target.getFirstTarget(), game);
if (card != null) {
cards.remove(card);
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null) {
toLibrary.add(permanent);
}
}
target.clearChosen();
}
if (cards.size() == 1) {
Card card = cards.get(cards.iterator().next(), game);
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null) {
toLibrary.add(permanent);
}
}
// move all permanents to lib at the same time
for (Permanent permanent : toLibrary) {
player.moveCardToLibraryWithInfo(permanent, source, game, Zone.BATTLEFIELD, true, false);
}
// cards to bottom
cards.clear();
toLibrary.clear();
for (Permanent permanent : permanentsToBottom) {
if (permanent instanceof PermanentToken) {
toLibrary.add(permanent);
} else {
Card card = game.getCard(permanent.getId());
if (card != null) {
cards.add(card);
}
}
}
target = new TargetCard(Zone.BATTLEFIELD, new FilterCard("order to put on bottom of library (last choosen will be bottommost card)"));
while (player.canRespond() && cards.size() > 1) {
player.choose(Outcome.Neutral, cards, target, game);
if (controller == null) { return false; }
Card card = cards.get(target.getFirstTarget(), game);
if (card != null) {
cards.remove(card);
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null) {
toLibrary.add(permanent);
}
PlayerList playerList = game.getState().getPlayersInRange(controller.getId(), game);
playerList.setCurrent(game.getActivePlayerId());
Player player = game.getPlayer(game.getActivePlayerId());
Player activePlayer = player;
do {
List<Permanent> permanentsToTop = new ArrayList<>();
List<Permanent> permanentsToBottom = new ArrayList<>();
for (Permanent permanent : game.getState().getBattlefield().getActivePermanents(new FilterAttackingCreature(), player.getId(), source.getSourceId(), game)) {
if (permanent.isOwnedBy(player.getId())) {
if (player.chooseUse(outcome, "Put " + permanent.getLogName() + " to the top? (else it goes to bottom)", source, game)) {
permanentsToTop.add(permanent);
game.informPlayers(permanent.getLogName() + " goes to the top of " + player.getLogName() + "'s library");
} else {
permanentsToBottom.add(permanent);
game.informPlayers(permanent.getLogName() + " goes to the bottom of " + player.getLogName() + "'s library");
}
target.clearChosen();
}
if (cards.size() == 1) {
Card card = cards.get(cards.iterator().next(), game);
}
// cards to top
Cards cards = new CardsImpl();
List<Permanent> toLibrary = new ArrayList<>();
for (Permanent permanent : permanentsToTop) {
if (permanent instanceof PermanentToken) {
toLibrary.add(permanent);
} else {
Card card = game.getCard(permanent.getId());
if (card != null) {
cards.add(card);
}
}
}
TargetCard target = new TargetCard(Zone.BATTLEFIELD, new FilterCard("order to put on the top of library (last choosen will be the top most)"));
while (cards.size() > 1) {
if (!player.canRespond()) {
return false;
}
player.choose(Outcome.Neutral, cards, target, game);
Card card = cards.get(target.getFirstTarget(), game);
if (card != null) {
cards.remove(card);
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null) {
toLibrary.add(permanent);
}
}
// move all permanents to lib at the same time
for (Permanent permanent : toLibrary) {
player.moveCardToLibraryWithInfo(permanent, source, game, Zone.BATTLEFIELD, false, false);
target.clearChosen();
}
if (cards.size() == 1) {
Card card = cards.get(cards.iterator().next(), game);
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null) {
toLibrary.add(permanent);
}
player = playerList.getNext(game, false);
} while (player != null && !player.getId().equals(game.getActivePlayerId()) && activePlayer.canRespond());
return true;
}
return false;
}
// move all permanents to lib at the same time
for (Permanent permanent : toLibrary) {
player.moveCardToLibraryWithInfo(permanent, source, game, Zone.BATTLEFIELD, true, false);
}
// cards to bottom
cards.clear();
toLibrary.clear();
for (Permanent permanent : permanentsToBottom) {
if (permanent instanceof PermanentToken) {
toLibrary.add(permanent);
} else {
Card card = game.getCard(permanent.getId());
if (card != null) {
cards.add(card);
}
}
}
target = new TargetCard(Zone.BATTLEFIELD, new FilterCard("order to put on bottom of library (last choosen will be bottommost card)"));
while (player.canRespond() && cards.size() > 1) {
player.choose(Outcome.Neutral, cards, target, game);
Card card = cards.get(target.getFirstTarget(), game);
if (card != null) {
cards.remove(card);
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null) {
toLibrary.add(permanent);
}
}
target.clearChosen();
}
if (cards.size() == 1) {
Card card = cards.get(cards.iterator().next(), game);
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null) {
toLibrary.add(permanent);
}
}
// move all permanents to lib at the same time
for (Permanent permanent : toLibrary) {
player.moveCardToLibraryWithInfo(permanent, source, game, Zone.BATTLEFIELD, false, false);
}
player = playerList.getNext(game, false);
} while (player != null && !player.getId().equals(game.getActivePlayerId()) && activePlayer.canRespond());
return true;
}
}

View file

@ -50,37 +50,37 @@ public final class AgelessSentinels extends CardImpl {
public AgelessSentinels copy() {
return new AgelessSentinels(this);
}
}
private class AgelessSentinelsEffect extends ContinuousEffectImpl {
class AgelessSentinelsEffect extends ContinuousEffectImpl {
public AgelessSentinelsEffect() {
super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.BecomeCreature);
staticText = "it becomes a Bird Giant";
public AgelessSentinelsEffect() {
super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.BecomeCreature);
staticText = "it becomes a Bird Giant";
}
private AgelessSentinelsEffect(final AgelessSentinelsEffect effect) {
super(effect);
}
@Override
public AgelessSentinelsEffect copy() {
return new AgelessSentinelsEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent == null) {
return false;
}
permanent.removeAllCreatureTypes(game);
permanent.addSubType(game, SubType.BIRD, SubType.GIANT);
return true;
}
public AgelessSentinelsEffect(final AgelessSentinelsEffect effect) {
super(effect);
}
@Override
public AgelessSentinelsEffect copy() {
return new AgelessSentinelsEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent == null) {
return false;
}
permanent.removeAllCreatureTypes(game);
permanent.addSubType(game, SubType.BIRD, SubType.GIANT);
return true;
}
@Override
public boolean hasLayer(Layer layer) {
return layer == Layer.TypeChangingEffects_4;
}
@Override
public boolean hasLayer(Layer layer) {
return layer == Layer.TypeChangingEffects_4;
}
}

View file

@ -58,7 +58,7 @@ class AkoumHellkiteTriggeredAbility extends TriggeredAbilityImpl {
super(Zone.BATTLEFIELD, new AkoumHellkiteDamageEffect());
}
public AkoumHellkiteTriggeredAbility(final AkoumHellkiteTriggeredAbility ability) {
private AkoumHellkiteTriggeredAbility(final AkoumHellkiteTriggeredAbility ability) {
super(ability);
}
@ -75,19 +75,21 @@ class AkoumHellkiteTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null
&& permanent.isLand(game)
&& permanent.isControlledBy(getControllerId())) {
Permanent sourcePermanent = game.getPermanent(getSourceId());
if (sourcePermanent != null) {
for (Effect effect : getEffects()) {
if (effect instanceof AkoumHellkiteDamageEffect) {
effect.setTargetPointer(new FixedTarget(permanent, game));
}
return true;
}
if (permanent == null) { return false; }
if (!permanent.isLand(game) || !permanent.isControlledBy(getControllerId())) { return false; }
Permanent sourcePermanent = game.getPermanent(getSourceId());
if (sourcePermanent == null) { return false; }
for (Effect effect : getEffects()) {
if (effect instanceof AkoumHellkiteDamageEffect) {
effect.setTargetPointer(new FixedTarget(permanent, game));
return true;
}
}
// The Hellkit somehow lost it's damage effect but not it's landfall ability
return false;
}
@ -116,24 +118,22 @@ class AkoumHellkiteDamageEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent land = getTargetPointer().getFirstTargetPermanentOrLKI(game, source);
if (land == null) { return false; }
int damage = land.hasSubtype(SubType.MOUNTAIN, game) ? 2 : 1;
// Get target for damange
Player player = game.getPlayer(source.getFirstTarget());
if (land != null && player != null) {
if (land.hasSubtype(SubType.MOUNTAIN, game)) {
player.damage(2, source.getSourceId(), source, game);
} else {
player.damage(1, source.getSourceId(), source, game);
}
return true;
}
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (land != null && permanent != null) {
if (land.hasSubtype(SubType.MOUNTAIN, game)) {
permanent.damage(2, source.getSourceId(), source, game);
} else {
permanent.damage(1, source.getSourceId(), source, game);
}
return true;
if (player == null && permanent == null) { return false; }
if (player != null) {
// Target is a player
player.damage(damage, source.getSourceId(), source, game);
} else {
// Target is a permanent
permanent.damage(damage, source.getSourceId(), source, game);
}
return false;
return true;
}
}

View file

@ -37,8 +37,10 @@ public final class AkroanHorse extends CardImpl {
// Defender
this.addAbility(DefenderAbility.getInstance());
// When Akroan Horse enters the battlefield, an opponent gains control of it.
this.addAbility(new EntersBattlefieldTriggeredAbility(new AkroanHorseChangeControlEffect(), false));
// At the beginning of your upkeep, each opponent create a 1/1 white Soldier creature token.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new AkroanHorseCreateTokenEffect(), TargetController.YOU, false));
}
@ -60,7 +62,7 @@ class AkroanHorseChangeControlEffect extends OneShotEffect {
this.staticText = "an opponent gains control of it";
}
public AkroanHorseChangeControlEffect(final AkroanHorseChangeControlEffect effect) {
private AkroanHorseChangeControlEffect(final AkroanHorseChangeControlEffect effect) {
super(effect);
}
@ -88,7 +90,7 @@ class AkroanHorseChangeControlEffect extends OneShotEffect {
class AkroanHorseGainControlEffect extends ContinuousEffectImpl {
UUID controller;
private final UUID controller;
public AkroanHorseGainControlEffect(Duration duration, UUID controller) {
super(duration, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl);
@ -107,14 +109,18 @@ class AkroanHorseGainControlEffect extends ContinuousEffectImpl {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (targetPointer != null) {
Permanent permanent;
if (targetPointer == null) {
permanent = game.getPermanent(source.getFirstTarget());
} else {
permanent = game.getPermanent(targetPointer.getFirst(game, source));
}
if (permanent != null) {
return permanent.changeControllerId(controller, game, source);
}
return false;
if (permanent == null) { return false; }
return permanent.changeControllerId(controller, game, source);
}
@Override
@ -130,7 +136,7 @@ class AkroanHorseCreateTokenEffect extends OneShotEffect {
this.staticText = "each opponent creates a 1/1 white Soldier creature token";
}
public AkroanHorseCreateTokenEffect(final AkroanHorseCreateTokenEffect effect) {
private AkroanHorseCreateTokenEffect(final AkroanHorseCreateTokenEffect effect) {
super(effect);
}

View file

@ -106,7 +106,7 @@ class AkromaVisionOfIxidorEffect extends OneShotEffect {
StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE,
source.getControllerId(), source.getSourceId(), game
)) {
Abilities abilities = permanent.getAbilities(game);
Abilities<Ability> abilities = permanent.getAbilities(game);
int count = classes
.stream()
.map(clazz -> abilities.stream().anyMatch(clazz::isInstance))

View file

@ -65,27 +65,26 @@ class AliFromCairoReplacementEffect extends ReplacementEffectImpl {
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null
&& (controller.getLife() > 0) &&(controller.getLife() - event.getAmount()) < 1
&& event.getPlayerId().equals(controller.getId())
) {
return true;
}
}
return false;
if (permanent == null) { return false; }
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) { return false; }
return (controller.getLife() > 0) && (controller.getLife() - event.getAmount()) < 1
&& event.getPlayerId().equals(controller.getId());
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
// 10/1/2008: The ability doesn't change how much damage is dealt;
// it just changes how much life that damage makes you lose.
// An effect such as Spirit Link will see the full amount of damage being dealt.
event.setAmount(controller.getLife() - 1);
}
if (controller == null) { return false; }
// 10/1/2008: The ability doesn't change how much damage is dealt;
// it just changes how much life that damage makes you lose.
// An effect such as Spirit Link will see the full amount of damage being dealt.
event.setAmount(controller.getLife() - 1);
// TODO: Is this supposed to be false? Seem suspicious
return false;
}
}

View file

@ -70,20 +70,20 @@ class AlignedHedronNetworkExileEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) { return false;}
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent == null) { return false; }
// If Whale leaves the battlefield before its triggered ability resolves,
// the target creature won't be exiled.
if (controller != null && permanent != null) {
Set<Card> toExile = new LinkedHashSet<>();
for (Permanent creature : game.getBattlefield().getActivePermanents(filter, controller.getId(), source.getSourceId(), game)) {
toExile.add(creature);
}
if (!toExile.isEmpty()) {
controller.moveCardsToExile(toExile, source, game, true, CardUtil.getCardExileZoneId(game, source), permanent.getIdName());
new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility()).apply(game, source);
}
return true;
}
return false;
Set<Card> toExile = new LinkedHashSet<>(game.getBattlefield().getActivePermanents(filter, controller.getId(), source.getSourceId(), game));
if (toExile.isEmpty()) { return false; }
controller.moveCardsToExile(toExile, source, game, true, CardUtil.getCardExileZoneId(game, source), permanent.getIdName());
new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility()).apply(game, source);
return true;
}
}

View file

@ -9,6 +9,7 @@ import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ExileSpellEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.Outcome;
@ -34,10 +35,18 @@ public final class AllHallowsEve extends CardImpl {
this.getSpellAbility().addEffect(new ExileSpellEffect());
this.getSpellAbility().addEffect(new AddCountersSourceEffect(
CounterType.SCREAM.createInstance(), StaticValue.get(2), true, true
).setText("with 2 scream counters on it"));
).setText("with two scream counters on it"));
// At the beginning of your upkeep, if All Hallow's Eve is exiled with a scream counter on it, remove a scream counter from it. If there are no more scream counters on it, put it into your graveyard and each player returns all creature cards from their graveyard to the battlefield.
this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfUpkeepTriggeredAbility(Zone.EXILED, new AllHallowsEveEffect(), TargetController.YOU, false), AllHallowsEveCondition.instance, "At the beginning of your upkeep, if {this} is exiled with a scream counter on it, remove a scream counter from it. If there are no more scream counters on it, put it into your graveyard and each player returns all creature cards from their graveyard to the battlefield."));
// At the beginning of your upkeep, if All Hallow's Eve is exiled with a scream counter on it, remove a scream counter from it.
// If there are no more scream counters on it, put it into your graveyard and each player returns all creature cards from their graveyard to the battlefield.
Ability ability = new BeginningOfUpkeepTriggeredAbility(
Zone.EXILED,
new RemoveCounterSourceEffect(CounterType.SCREAM.createInstance(1)),
TargetController.YOU,
false
);
ability.addEffect(new AllHallowsEveEffect());
this.addAbility(ability);
}
private AllHallowsEve(final AllHallowsEve card) {
@ -50,23 +59,12 @@ public final class AllHallowsEve extends CardImpl {
}
}
enum AllHallowsEveCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
MageObject sourceObject = source.getSourceObjectIfItStillExists(game);
return sourceObject != null
&& game.getState().getZone(source.getSourceId()) == Zone.EXILED
&& sourceObject instanceof Card
&& ((Card) sourceObject).getMainCard().getCounters(game).getCount(CounterType.SCREAM) > 0;
}
}
class AllHallowsEveEffect extends OneShotEffect {
AllHallowsEveEffect() {
super(Outcome.PutCreatureInPlay);
staticText = "If there are no more scream counters on it, put it into your graveyard " +
"and each player returns all creature cards from their graveyard to the battlefield.";
}
private AllHallowsEveEffect(final AllHallowsEveEffect effect) {
@ -80,13 +78,15 @@ class AllHallowsEveEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Card card = (Card) source.getSourceObject(game);
Card allHallowsEveCard = (Card) source.getSourceObject(game);
if (allHallowsEveCard == null) { return false; }
Player controller = game.getPlayer(source.getControllerId());
if (card == null || controller == null) {
return false;
}
controller.moveCards(card, Zone.GRAVEYARD, source, game);
Cards cards = new CardsImpl();
if (controller == null) { return false; }
if (allHallowsEveCard.getCounters(game).getCount(CounterType.SCREAM) > 0) { return false; }
controller.moveCards(allHallowsEveCard, Zone.GRAVEYARD, source, game);
Cards allCreatureCardsInGraveyards = new CardsImpl();
game.getState()
.getPlayersInRange(source.getControllerId(), game)
.stream()
@ -96,8 +96,9 @@ class AllHallowsEveEffect extends OneShotEffect {
.map(g -> g.getCards(game))
.flatMap(Collection::stream)
.filter(card1 -> card1.isCreature(game))
.forEach(cards::add);
controller.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, true, null);
.forEach(allCreatureCardsInGraveyards::add);
controller.moveCards(allCreatureCardsInGraveyards.getCards(game), Zone.BATTLEFIELD, source, game, false, false, true, null);
return true;
}
}

View file

@ -71,8 +71,8 @@ class AltarOfTheLostManaCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
MageObject object = game.getObject(source.getSourceId());
if (game != null && game.inCheckPlayableState()) {
if (object instanceof Card && game.getState().getZone(source.getSourceId()).equals(Zone.GRAVEYARD)) {
if (game.inCheckPlayableState()) {
if (object instanceof Card && game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) {
for (Ability ability : ((Card) object).getAbilities(game)) {
if (ability instanceof FlashbackAbility) {
return true;

View file

@ -37,7 +37,8 @@ public class AminatousAugury extends CardImpl {
public AminatousAugury(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{6}{U}{U}");
// Exile the top eight cards of your library. You may put a land card from among them onto the battlefield.
// Exile the top eight cards of your library.
// You may put a land card from among them onto the battlefield.
// Until end of turn, for each nonland card type, you may cast a card of that type from among the exiled cards
// without paying its mana cost.
this.getSpellAbility().addEffect(new AminatousAuguryEffect());
@ -58,9 +59,10 @@ class AminatousAuguryEffect extends OneShotEffect {
public AminatousAuguryEffect() {
super(Outcome.PlayForFree);
staticText = "Exile the top eight cards of your library. You may put a land card from among them onto the"
+ " battlefield. Until end of turn, for each nonland card type, you may cast a card of that type from"
+ " among the exiled cards without paying its mana cost.";
staticText = "Exile the top eight cards of your library. " +
"You may put a land card from among them onto the battlefield. " +
"Until end of turn, for each nonland card type, " +
"you may cast a card of that type from among the exiled cards without paying its mana cost.";
}
public AminatousAuguryEffect(final AminatousAuguryEffect effect) {
@ -74,41 +76,42 @@ class AminatousAuguryEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) { return false; }
MageObject sourceObject = source.getSourceObject(game);
if (controller != null && sourceObject != null) {
// move cards from library to exile
controller.moveCardsToExile(controller.getLibrary().getTopCards(game, 8), source, game, true, source.getSourceId(), CardUtil.createObjectRealtedWindowTitle(source, game, null));
ExileZone auguryExileZone = game.getExile().getExileZone(source.getSourceId());
if (auguryExileZone == null) {
return true;
}
Cards cardsToCast = new CardsImpl();
cardsToCast.addAll(auguryExileZone.getCards(game));
// put a land card from among them onto the battlefield
TargetCard target = new TargetCard(
Zone.EXILED,
StaticFilters.FILTER_CARD_LAND_A
);
if (cardsToCast.count(StaticFilters.FILTER_CARD_LAND, game) > 0) {
if (controller.chooseUse(Outcome.PutLandInPlay, "Put a land from among the exiled cards into play?", source, game)) {
if (controller.choose(Outcome.PutLandInPlay, cardsToCast, target, game)) {
Card card = cardsToCast.get(target.getFirstTarget(), game);
if (card != null) {
cardsToCast.remove(card);
controller.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, true, null);
}
}
if (sourceObject == null) { return false; }
// move cards from library to exile
controller.moveCardsToExile(controller.getLibrary().getTopCards(game, 8), source, game, true, source.getSourceId(), CardUtil.createObjectRealtedWindowTitle(source, game, null));
ExileZone auguryExileZone = game.getExile().getExileZone(source.getSourceId());
if (auguryExileZone == null) { return true; }
Cards cardsToCast = new CardsImpl();
cardsToCast.addAll(auguryExileZone.getCards(game));
// put a land card from among them onto the battlefield
TargetCard target = new TargetCard(Zone.EXILED, StaticFilters.FILTER_CARD_LAND_A);
if (cardsToCast.count(StaticFilters.FILTER_CARD_LAND, game) == 0) { return true; }
if (controller.chooseUse(Outcome.PutLandInPlay, "Put a land from among the exiled cards into play?", source, game)) {
if (controller.choose(Outcome.PutLandInPlay, cardsToCast, target, game)) {
Card card = cardsToCast.get(target.getFirstTarget(), game);
if (card != null) {
cardsToCast.remove(card);
controller.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, true, null);
}
}
for (Card card : cardsToCast.getCards(StaticFilters.FILTER_CARD_NON_LAND, game)) {
AminatousAuguryCastFromExileEffect effect = new AminatousAuguryCastFromExileEffect();
effect.setTargetPointer(new FixedTarget(card, game));
game.addEffect(effect, source);
}
}
return false;
for (Card card : cardsToCast.getCards(StaticFilters.FILTER_CARD_NON_LAND, game)) {
AminatousAuguryCastFromExileEffect effect = new AminatousAuguryCastFromExileEffect();
effect.setTargetPointer(new FixedTarget(card, game));
game.addEffect(effect, source);
}
// TODO: I think this should be returning true
return true;
}
}
@ -136,51 +139,54 @@ class AminatousAuguryCastFromExileEffect extends AsThoughEffectImpl {
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
Player player = game.getPlayer(affectedControllerId);
EnumSet<CardType> usedCardTypes = EnumSet.noneOf(CardType.class);
if (player == null) { return false; }
if (game.getState().getValue(source.getSourceId().toString() + "cardTypes") != null) {
if (!affectedControllerId.equals(source.getControllerId())) { return false; }
EnumSet<CardType> usedCardTypes;
if (game.getState().getValue(source.getSourceId().toString() + "cardTypes") == null) {
// The effect has not been applied fully yet, so there are no previously cast times
usedCardTypes = EnumSet.noneOf(CardType.class);
} else {
usedCardTypes = (EnumSet<CardType>) game.getState().getValue(source.getSourceId().toString() + "cardTypes");
}
if (player != null
&& objectId != null
&& objectId.equals(getTargetPointer().getFirst(game, source))
&& affectedControllerId.equals(source.getControllerId())) {
Card card = game.getCard(objectId);
if (card != null
&& game.getState().getZone(objectId) == Zone.EXILED) {
EnumSet<CardType> unusedCardTypes = EnumSet.noneOf(CardType.class);
for (CardType cardT : card.getCardType(game)) {
if (!usedCardTypes.contains(cardT)) {
unusedCardTypes.add(cardT);
}
}
if (!unusedCardTypes.isEmpty()) {
if (!game.inCheckPlayableState()) { // some actions may not be done while the game only checks if a card can be cast
// Select the card type to consume and remove all not seleczted card types
if (unusedCardTypes.size() > 1) {
Choice choice = new ChoiceImpl(true);
choice.setMessage("Which card type do you want to consume?");
Set<String> choices = choice.getChoices();
for (CardType cardType : unusedCardTypes) {
choices.add(cardType.toString());
}
player.choose(Outcome.Detriment, choice, game);
for (Iterator<CardType> iterator = unusedCardTypes.iterator(); iterator.hasNext();) {
CardType next = iterator.next();
if (!next.toString().equals(choice.getChoice())) {
iterator.remove();
}
}
usedCardTypes.add(CardType.fromString(choice.getChoice()));
}
usedCardTypes.addAll(unusedCardTypes);
game.getState().setValue(source.getSourceId().toString() + "cardTypes", usedCardTypes);
}
player.setCastSourceIdWithAlternateMana(objectId, null, card.getSpellAbility().getCosts());
return true;
}
if (objectId == null || !objectId.equals(getTargetPointer().getFirst(game, source))) { return false; }
if (game.getState().getZone(objectId) != Zone.EXILED) { return false; }
Card card = game.getCard(objectId);
if (card == null) { return false; }
// Figure out which of the current card's types have not been cast before
EnumSet<CardType> unusedCardTypes = EnumSet.noneOf(CardType.class);
for (CardType cardT : card.getCardType(game)) {
if (!usedCardTypes.contains(cardT)) {
unusedCardTypes.add(cardT);
}
}
return false;
// The current card has only card types that have been cast before, so it can't be cast
if (unusedCardTypes.isEmpty()) { return false; }
// some actions may not be done while the game only checks if a card can be cast
if (!game.inCheckPlayableState()) {
// Select the card type to consume and remove all not selected card types
if (unusedCardTypes.size() > 1) {
Choice choice = new ChoiceImpl(true);
choice.setMessage("Which card type do you want to consume?");
Set<String> choices = choice.getChoices();
for (CardType cardType : unusedCardTypes) {
choices.add(cardType.toString());
}
player.choose(Outcome.Detriment, choice, game);
unusedCardTypes.removeIf(next -> !next.toString().equals(choice.getChoice()));
usedCardTypes.add(CardType.fromString(choice.getChoice()));
}
usedCardTypes.addAll(unusedCardTypes);
game.getState().setValue(source.getSourceId().toString() + "cardTypes", usedCardTypes);
}
player.setCastSourceIdWithAlternateMana(objectId, null, card.getSpellAbility().getCosts());
return true;
}
}

View file

@ -61,16 +61,17 @@ class AnHavvaConstableEffect extends ContinuousEffectImpl {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
MageObject mageObject = game.getObject(source.getSourceId());
if (mageObject != null) {
FilterCreaturePermanent filter = new FilterCreaturePermanent("green creatures");
filter.add(new ColorPredicate(ObjectColor.GREEN));
int number = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game);
mageObject.getToughness().setValue(number + 1);
return true;
}
}
return false;
if (controller == null) { return false; }
MageObject mageObject = game.getObject(source.getSourceId());
if (mageObject == null) { return false; }
FilterCreaturePermanent filter = new FilterCreaturePermanent("green creatures");
filter.add(new ColorPredicate(ObjectColor.GREEN));
int numberOfGreenCreatures = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game);
mageObject.getToughness().setValue(1 + numberOfGreenCreatures);
return true;
}
}

View file

@ -102,13 +102,14 @@ class ArcaneAdaptationEffect extends ContinuousEffectImpl {
// commander in command zone
for (CommandObject commandObject : game.getState().getCommand()) {
if (commandObject instanceof Commander) {
Card card = game.getCard(((Commander) commandObject).getId());
Card card = game.getCard((commandObject).getId());
if (card != null && card.isOwnedBy(controller.getId())
&& card.isCreature(game) && !card.hasSubtype(subType, game)) {
game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType);
}
}
}
// TODO: Why is this not using the for-in loop like all the others?
// creature spells you control
for (Iterator<StackObject> iterator = game.getStack().iterator(); iterator.hasNext(); ) {
StackObject stackObject = iterator.next();

View file

@ -1,6 +1,7 @@
package mage.cards.a;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.DealsDamageToOpponentTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
@ -38,7 +39,7 @@ public final class AtemsisAllSeeing extends CardImpl {
// {2}{U}, {T}: Draw two cards, then discard a card.
Ability ability = new SimpleActivatedAbility(
new DrawDiscardControllerEffect(2, 1), new ManaCostsImpl("{2}{U}")
new DrawDiscardControllerEffect(2, 1), new ManaCostsImpl<>("{2}{U}")
);
ability.addCost(new TapSourceCost());
this.addAbility(ability);
@ -88,7 +89,7 @@ class AtemsisAllSeeingEffect extends OneShotEffect {
.getHand()
.getCards(game)
.stream()
.map(card -> card.getManaValue())
.map(MageObject::getManaValue)
.distinct()
.count() > 5) {
opponent.lost(game);

View file

@ -35,11 +35,11 @@ public final class AuraFinesse extends CardImpl {
public AuraFinesse(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U}");
// Attach target Aura you control to target creature.
this.getSpellAbility().addEffect(new AuraFinesseEffect());
this.getSpellAbility().addTarget(new TargetPermanent(filter));
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
// Draw a card.
this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("<br>"));
}
@ -70,26 +70,28 @@ class AuraFinesseEffect extends OneShotEffect {
return new AuraFinesseEffect(this);
}
// 15/06/2010 As Aura Finesse resolves, if either target is illegal,
// the spell resolves but the Aura doesnt move. You still draw a card.
// If both targets are illegal, Aura Finesse doesnt resolve and you dont draw a card.
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Permanent aura = game.getPermanent(source.getFirstTarget());
Permanent creature = game.getPermanent(source.getTargets().get(1).getFirstTarget());
if (aura != null && creature != null) {
Permanent oldCreature = game.getPermanent(aura.getAttachedTo());
if (oldCreature != null && !oldCreature.equals(creature)) {
Target auraTarget = aura.getSpellAbility().getTargets().get(0);
if (!auraTarget.canTarget(creature.getId(), game)) {
game.informPlayers(aura.getLogName() + " was not attched to " +creature.getLogName() + " because it's no legal target for the aura" );
} else if (oldCreature.removeAttachment(aura.getId(), source, game)) {
game.informPlayers(aura.getLogName() + " was unattached from " + oldCreature.getLogName() + " and attached to " + creature.getLogName());
creature.addAttachment(aura.getId(), source, game);
}
if (controller == null) { return false; }
Permanent aura = game.getPermanent(source.getFirstTarget());
Permanent creature = game.getPermanent(source.getTargets().get(1).getFirstTarget());
if (aura != null && creature != null) {
Permanent oldCreature = game.getPermanent(aura.getAttachedTo());
if (oldCreature != null && !oldCreature.equals(creature)) {
Target auraTarget = aura.getSpellAbility().getTargets().get(0);
if (!auraTarget.canTarget(creature.getId(), game)) {
game.informPlayers(aura.getLogName() + " was not attched to " +creature.getLogName() + " because it's no legal target for the aura" );
} else if (oldCreature.removeAttachment(aura.getId(), source, game)) {
game.informPlayers(aura.getLogName() + " was unattached from " + oldCreature.getLogName() + " and attached to " + creature.getLogName());
creature.addAttachment(aura.getId(), source, game);
}
}
return true;
}
return false;
return true;
}
}

View file

@ -19,7 +19,7 @@ import java.util.UUID;
*/
public final class AuriokEdgewright extends CardImpl {
protected static String effectText = "<i>Metalcraft</i> &mdash; Auriok Edgewright has double strike as long as you control three or more artifacts.";
private static final String effectText = "<i>Metalcraft</i> &mdash; Auriok Edgewright has double strike as long as you control three or more artifacts.";
public AuriokEdgewright(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}");

View file

@ -70,14 +70,9 @@ class AutumnWillowEffect extends AsThoughEffectImpl {
@Override
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
if (affectedControllerId.equals(source.getFirstTarget())) {
Permanent creature = game.getPermanent(sourceId);
if (creature != null) {
if (sourceId.equals(source.getSourceId())) {
return true;
}
}
}
return false;
if (!affectedControllerId.equals(source.getFirstTarget())) { return false; }
Permanent creature = game.getPermanent(sourceId);
return creature != null &&sourceId.equals(source.getSourceId());
}
}

View file

@ -66,9 +66,6 @@ class AvatarOfWoeCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
if (AvatarOfWoe.graveyardCount.calculate(game, source, null) >= 10) {
return true;
}
return false;
return AvatarOfWoe.graveyardCount.calculate(game, source, null) >= 10;
}
}

View file

@ -11,7 +11,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
@ -24,8 +24,6 @@ import java.util.UUID;
*/
public final class AzoriusAethermage extends CardImpl {
private static final String rule = "Whenever a permanent is returned to your hand, ";
public AzoriusAethermage(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}");
@ -35,8 +33,8 @@ public final class AzoriusAethermage extends CardImpl {
this.toughness = new MageInt(1);
// Whenever a permanent is returned to your hand, you may pay {1}. If you do, draw a card.
Effect effect = new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{1}"));
this.addAbility(new AzoriusAEthermageAbility(Zone.BATTLEFIELD, Zone.BATTLEFIELD, Zone.HAND, effect, new FilterPermanent(), rule, false));
Effect effect = new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{1}"));
this.addAbility(new AzoriusAEthermageAbility(effect));
}
private AzoriusAethermage(final AzoriusAethermage card) {
@ -51,25 +49,14 @@ public final class AzoriusAethermage extends CardImpl {
class AzoriusAEthermageAbility extends TriggeredAbilityImpl {
protected FilterPermanent filter;
protected Zone fromZone;
protected Zone toZone;
protected String rule;
private static final String rule = "Whenever a permanent is returned to your hand, ";
public AzoriusAEthermageAbility(Zone zone, Zone fromZone, Zone toZone, Effect effect, FilterPermanent filter, String rule, boolean optional) {
super(zone, effect, optional);
this.fromZone = fromZone;
this.toZone = toZone;
this.rule = rule;
this.filter = filter;
public AzoriusAEthermageAbility(Effect effect) {
super(Zone.BATTLEFIELD, effect, false);
}
public AzoriusAEthermageAbility(final AzoriusAEthermageAbility ability) {
private AzoriusAEthermageAbility(final AzoriusAEthermageAbility ability) {
super(ability);
this.fromZone = ability.fromZone;
this.toZone = ability.toZone;
this.rule = ability.rule;
this.filter = ability.filter;
}
@Override
@ -80,35 +67,29 @@ class AzoriusAEthermageAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if ((fromZone == null || zEvent.getFromZone() == fromZone)
&& (toZone == null || zEvent.getToZone() == toZone)) {
Permanent permanentThatMoved = null;
if (zEvent.getTarget() != null) {
permanentThatMoved = zEvent.getTarget();
}
//The controller's hand is where the permanent moved to.
return permanentThatMoved != null
&& filter.match(permanentThatMoved, sourceId, controllerId, game)
&& zEvent.getPlayerId().equals(controllerId);
if (zEvent.getFromZone() != Zone.BATTLEFIELD || zEvent.getToZone() != Zone.HAND) {
return false;
}
return false;
if (!zEvent.getPlayerId().equals(controllerId)) {
return false;
}
Permanent permanentThatMoved = zEvent.getTarget();
if (permanentThatMoved == null) {
return false;
}
return StaticFilters.FILTER_PERMANENT_CREATURE.match(permanentThatMoved, sourceId, controllerId, game);
}
@Override
public String getTriggerPhrase() {
return rule ;
return rule;
}
@Override
public AzoriusAEthermageAbility copy() {
return new AzoriusAEthermageAbility(this);
}
public Zone getFromZone() {
return fromZone;
}
public Zone getToZone() {
return toZone;
}
}

View file

@ -38,7 +38,9 @@ public final class AzorsGateway extends CardImpl {
this.addSuperType(SuperType.LEGENDARY);
this.secondSideCardClazz = mage.cards.s.SanctumOfTheSun.class;
// {1}, {T}: Draw a card, then exile a card from your hand. If cards with five or more different converted mana costs are exiled with Azor's Gateway, you gain 5 life, untap Azor's Gateway, and transform it.
// {1}, {T}: Draw a card, then exile a card from your hand.
// If cards with five or more different converted mana costs are exiled with Azor's Gateway,
// you gain 5 life, untap Azor's Gateway, and transform it.
this.addAbility(new TransformAbility());
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AzorsGatewayEffect(), new GenericManaCost(1));
ability.addCost(new TapSourceCost());
@ -59,7 +61,9 @@ class AzorsGatewayEffect extends OneShotEffect {
public AzorsGatewayEffect() {
super(Outcome.Benefit);
this.staticText = "Draw a card, then exile a card from your hand. If cards with five or more different mana values are exiled with {this}, you gain 5 life, untap Azor's Gateway, and transform it";
this.staticText = "Draw a card, then exile a card from your hand. " +
"If cards with five or more different mana values are exiled with {this}, " +
"you gain 5 life, untap Azor's Gateway, and transform it";
}
public AzorsGatewayEffect(final AzorsGatewayEffect effect) {
@ -74,30 +78,32 @@ class AzorsGatewayEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
UUID exileId = CardUtil.getCardExileZoneId(game, source);
if (controller == null) { return false; }
MageObject sourceObject = source.getSourceObject(game);
if (controller != null && exileId != null && sourceObject != null) {
controller.drawCards(1, source, game);
TargetCardInHand target = new TargetCardInHand();
controller.choose(outcome, target, source.getSourceId(), game);
Card cardToExile = game.getCard(target.getFirstTarget());
if (cardToExile != null) {
controller.moveCardsToExile(cardToExile, source, game, true, exileId, sourceObject.getIdName());
}
Set<Integer> usedCMC = new HashSet<>();
ExileZone exileZone = game.getExile().getExileZone(exileId);
if (exileZone != null) {
for (Card card : exileZone.getCards(game)) {
usedCMC.add(card.getManaValue());
}
if (usedCMC.size() > 4) {
controller.gainLife(4, game, source);
new UntapSourceEffect().apply(game, source);
new TransformSourceEffect().apply(game, source);
}
}
return true;
if (sourceObject == null) { return false; }
UUID exileId = CardUtil.getCardExileZoneId(game, source);
controller.drawCards(1, source, game);
TargetCardInHand target = new TargetCardInHand();
controller.choose(outcome, target, source.getSourceId(), game);
Card cardToExile = game.getCard(target.getFirstTarget());
if (cardToExile != null) {
controller.moveCardsToExile(cardToExile, source, game, true, exileId, sourceObject.getIdName());
}
return false;
Set<Integer> usedCMC = new HashSet<>();
ExileZone exileZone = game.getExile().getExileZone(exileId);
if (exileZone != null) {
for (Card card : exileZone.getCards(game)) {
usedCMC.add(card.getManaValue());
}
if (usedCMC.size() > 4) {
controller.gainLife(4, game, source);
new UntapSourceEffect().apply(game, source);
new TransformSourceEffect().apply(game, source);
}
}
return true;
}
}

View file

@ -162,7 +162,7 @@ class BaneAlleyBrokerReturnToHandEffect extends OneShotEffect {
if (card == null) {
return false;
}
return card != null && player.moveCards(card, Zone.HAND, source, game);
return player.moveCards(card, Zone.HAND, source, game);
}
}

View file

@ -34,6 +34,7 @@ public final class Banefire extends CardImpl {
// Banefire deals X damage to any target.
this.getSpellAbility().addEffect(new BaneFireEffect());
this.getSpellAbility().addTarget(new TargetAnyTarget());
// If X is 5 or more, Banefire can't be countered and the damage can't be prevented.
this.addAbility(new SimpleStaticAbility(Zone.STACK, new BanefireCantCounterEffect()));
}
@ -50,8 +51,8 @@ public final class Banefire extends CardImpl {
class testCondition implements Condition {
private DynamicValue xValue;
private int limit;
private final DynamicValue xValue;
private final int limit;
public testCondition(DynamicValue xValue, int limit) {
this.xValue = xValue;
@ -105,7 +106,7 @@ class BaneFireEffect extends OneShotEffect {
class BanefireCantCounterEffect extends ContinuousRuleModifyingEffectImpl {
Condition condition = new testCondition(ManacostVariableValue.REGULAR, 5);
private Condition condition = new testCondition(ManacostVariableValue.REGULAR, 5);
public BanefireCantCounterEffect() {
super(Duration.WhileOnStack, Outcome.Benefit);
@ -129,18 +130,14 @@ class BanefireCantCounterEffect extends ContinuousRuleModifyingEffectImpl {
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getType() == GameEvent.EventType.COUNTER) {
Card card = game.getCard(source.getSourceId());
if (card != null) {
UUID spellId = card.getSpellAbility().getId();
if (event.getTargetId().equals(spellId)) {
if (condition.apply(game, source)) {
return true;
}
}
}
}
return false;
}
if (event.getType() != GameEvent.EventType.COUNTER) { return false; }
Card card = game.getCard(source.getSourceId());
if (card == null) { return false; }
UUID spellId = card.getSpellAbility().getId();
if (!event.getTargetId().equals(spellId)) { return false; }
return condition.apply(game, source);
}
}

View file

@ -65,10 +65,10 @@ class BathaHerdEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
int xValue = ((BecomesMonstrousSourceTriggeredAbility) source).getMonstrosityValue();
return new CreateTokenEffect(new TuskenRaiderToken(), xValue).apply(game, source);
}
return false;
if (controller == null) { return false; }
int xValue = ((BecomesMonstrousSourceTriggeredAbility) source).getMonstrosityValue();
return new CreateTokenEffect(new TuskenRaiderToken(), xValue).apply(game, source);
}
}

View file

@ -70,34 +70,32 @@ class BatheInLightEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source));
if (target != null) {
ChoiceColor colorChoice = new ChoiceColor();
if (!controller.choose(Outcome.Benefit, colorChoice, game)) {
return false;
}
game.informPlayers(target.getName() + ": " + controller.getLogName() + " has chosen " + colorChoice.getChoice());
game.getState().setValue(target.getId() + "_color", colorChoice.getColor());
if (controller == null) { return false; }
ObjectColor protectColor = (ObjectColor) game.getState().getValue(target.getId() + "_color");
if (protectColor != null) {
ContinuousEffect effect = new ProtectionChosenColorTargetEffect();
game.addEffect(effect, source);
ObjectColor color = target.getColor(game);
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) {
if (!permanent.getId().equals(target.getId()) && permanent.getColor(game).shares(color)) {
game.getState().setValue(permanent.getId() + "_color", colorChoice.getColor());
effect.setTargetPointer(new FixedTarget(permanent, game));
game.addEffect(effect, source);
}
}
Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source));
if (target == null) { return false; }
}
return true;
ChoiceColor colorChoice = new ChoiceColor();
if (!controller.choose(Outcome.Benefit, colorChoice, game)) { return false; }
game.informPlayers(target.getName() + ": " + controller.getLogName() + " has chosen " + colorChoice.getChoice());
game.getState().setValue(target.getId() + "_color", colorChoice.getColor());
ObjectColor protectColor = (ObjectColor) game.getState().getValue(target.getId() + "_color");
if (protectColor == null) { return true; }
ContinuousEffect effect = new ProtectionChosenColorTargetEffect();
game.addEffect(effect, source);
ObjectColor color = target.getColor(game);
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) {
if (!permanent.getId().equals(target.getId()) && permanent.getColor(game).shares(color)) {
game.getState().setValue(permanent.getId() + "_color", colorChoice.getColor());
effect.setTargetPointer(new FixedTarget(permanent, game));
game.addEffect(effect, source);
}
}
return false;
return true;
}
}
@ -128,19 +126,20 @@ class ProtectionChosenColorTargetEffect extends ContinuousEffectImpl {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
ObjectColor color = (ObjectColor) game.getState().getValue(permanent.getId() + "_color");
if (color != null && (protectionAbility == null || !color.equals(chosenColor))) {
chosenColor = color;
FilterObject protectionFilter = new FilterObject(chosenColor.getDescription());
protectionFilter.add(new ColorPredicate(chosenColor));
protectionAbility = new ProtectionAbility(protectionFilter);
}
if (protectionAbility != null) {
permanent.addAbility(protectionAbility, source.getSourceId(), game);
return true;
}
if (permanent == null) { return false; }
ObjectColor color = (ObjectColor) game.getState().getValue(permanent.getId() + "_color");
if (color != null && (protectionAbility == null || !color.equals(chosenColor))) {
chosenColor = color;
FilterObject protectionFilter = new FilterObject<>(chosenColor.getDescription());
protectionFilter.add(new ColorPredicate(chosenColor));
protectionAbility = new ProtectionAbility(protectionFilter);
}
if (protectionAbility != null) {
permanent.addAbility(protectionAbility, source.getSourceId(), game);
return true;
}
return false;
}
}

View file

@ -66,7 +66,7 @@ class BattlefieldThaumaturgeSpellsCostReductionEffect extends CostModificationEf
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
int reduceAmount = 0;
int reduceAmount;
if (game.inCheckPlayableState()) {
// checking state (search max possible targets)
reduceAmount = getMaxPossibleTargetCreatures(abilityToModify, game);
@ -117,7 +117,7 @@ class BattlefieldThaumaturgeSpellsCostReductionEffect extends CostModificationEf
&& abilityToModify.isControlledBy(source.getControllerId())) {
Spell spell = (Spell) game.getStack().getStackObject(abilityToModify.getId());
if (spell != null) {
return spell != null && StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(spell, game);
return StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(spell, game);
} else {
Card sourceCard = game.getCard(abilityToModify.getSourceId());
return sourceCard != null && StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(sourceCard, game);

View file

@ -24,15 +24,17 @@ public final class BehemothSledge extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{G}{W}");
this.subtype.add(SubType.EQUIPMENT);
// Equipped creature gets +2/+2 and has trample and lifelink.
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(2, 2));
ability.addEffect(new GainAbilityAttachedEffect(TrampleAbility.getInstance(), AttachmentType.EQUIPMENT).setText("and has trample"));
ability.addEffect(new GainAbilityAttachedEffect(LifelinkAbility.getInstance(), AttachmentType.EQUIPMENT).setText("and lifelink"));
this.addAbility(ability);
// Equip {3}
this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(3)));
}
protected BehemothSledge(BehemothSledge me) {
private BehemothSledge(BehemothSledge me) {
super(me);
}

View file

@ -64,122 +64,123 @@ class BendOrBreakEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
if (controller == null) { return false; }
// Map of players and their piles
Map<UUID, List<List<Permanent>>> playerPermanents = new LinkedHashMap<>();
// Map of players and their piles
Map<UUID, List<List<Permanent>>> playerPermanents = new LinkedHashMap<>();
PlayerList playerList = game.getState().getPlayerList().copy();
while (!playerList.get().equals(source.getControllerId()) && controller.canRespond()) {
playerList.getNext();
}
Player currentPlayer = game.getPlayer(playerList.get());
Player nextPlayer;
UUID firstNextPlayer = null;
while (!getNextPlayerInDirection(true, playerList).equals(firstNextPlayer) && controller.canRespond()) {
nextPlayer = game.getPlayer(playerList.get());
if (nextPlayer == null) {
return false;
}
if (firstNextPlayer == null) {
firstNextPlayer = nextPlayer.getId();
}
if (!nextPlayer.canRespond()) {
continue;
}
// Each player separates all nontoken lands they control into two piles
if (currentPlayer != null && game.getState().getPlayersInRange(controller.getId(), game).contains(currentPlayer.getId())) {
List<Permanent> firstPile = new ArrayList<>();
List<Permanent> secondPile = new ArrayList<>();
FilterControlledLandPermanent filter = new FilterControlledLandPermanent("lands you control to assign to the first pile (lands not chosen will be assigned to the second pile)");
TargetPermanent target = new TargetControlledPermanent(0, Integer.MAX_VALUE, filter, true);
if (target.canChoose(source.getSourceId(), currentPlayer.getId(), game)) {
// TODO: add support for AI (50/50), need AI hints mechanic here
currentPlayer.chooseTarget(Outcome.Neutral, target, source, game);
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, currentPlayer.getId(), game)) {
if (target.getTargets().contains(permanent.getId())) {
firstPile.add(permanent);
} else {
secondPile.add(permanent);
}
}
StringBuilder sb = new StringBuilder("First pile of ").append(currentPlayer.getLogName()).append(": ");
sb.append(firstPile.stream().map(Permanent::getLogName).collect(Collectors.joining(", ")));
game.informPlayers(sb.toString());
sb = new StringBuilder("Second pile of ").append(currentPlayer.getLogName()).append(": ");
sb.append(secondPile.stream().map(Permanent::getLogName).collect(Collectors.joining(", ")));
game.informPlayers(sb.toString());
}
List<List<Permanent>> playerPiles = new ArrayList<>();
playerPiles.add(firstPile);
playerPiles.add(secondPile);
playerPermanents.put(currentPlayer.getId(), playerPiles);
}
currentPlayer = nextPlayer;
}
// For each player, one of their piles is chosen by one of their opponents of their choice
for (Map.Entry<UUID, List<List<Permanent>>> playerPiles : playerPermanents.entrySet()) {
Player player = game.getPlayer(playerPiles.getKey());
if (player != null) {
FilterPlayer filter = new FilterPlayer("opponent");
List<PlayerIdPredicate> opponentPredicates = new ArrayList<>();
for (UUID opponentId : game.getOpponents(player.getId())) {
opponentPredicates.add(new PlayerIdPredicate(opponentId));
}
filter.add(Predicates.or(opponentPredicates));
Target target = new TargetPlayer(1, 1, true, filter);
target.setTargetController(player.getId());
target.setAbilityController(source.getControllerId());
if (player.chooseTarget(outcome, target, source, game)) {
Player chosenOpponent = game.getPlayer(target.getFirstTarget());
if (chosenOpponent != null) {
List<Permanent> firstPile = playerPiles.getValue().get(0);
List<Permanent> secondPile = playerPiles.getValue().get(1);
game.informPlayers(player.getLogName() + " chose " + chosenOpponent.getLogName() + " to choose their pile");
if (chosenOpponent.choosePile(outcome, "Piles of " + player.getName(), firstPile, secondPile, game)) {
List<List<Permanent>> lists = playerPiles.getValue();
lists.clear();
lists.add(firstPile);
lists.add(secondPile);
game.informPlayers(player.getLogName() + " will have their first pile destroyed");
} else {
List<List<Permanent>> lists = playerPiles.getValue();
lists.clear();
lists.add(secondPile);
lists.add(firstPile);
game.informPlayers(player.getLogName() + " will have their second pile destroyed");
}
}
}
}
}
// Destroy all lands in the chosen piles. Tap all lands in the other piles
for (Map.Entry<UUID, List<List<Permanent>>> playerPiles : playerPermanents.entrySet()) {
Player player = game.getPlayer(playerPiles.getKey());
if (player != null) {
List<Permanent> pileToSac = playerPiles.getValue().get(0);
List<Permanent> pileToTap = playerPiles.getValue().get(1);
for (Permanent permanent : pileToSac) {
if (permanent != null) {
permanent.destroy(source, game, false);
}
}
for (Permanent permanent : pileToTap) {
if (permanent != null) {
permanent.tap(source, game);
}
}
}
}
return true;
PlayerList playerList = game.getState().getPlayerList().copy();
while (!playerList.get().equals(source.getControllerId()) && controller.canRespond()) {
playerList.getNext();
}
return false;
Player currentPlayer = game.getPlayer(playerList.get());
Player nextPlayer;
UUID firstNextPlayer = null;
while (!getNextPlayerInDirection(true, playerList).equals(firstNextPlayer) && controller.canRespond()) {
nextPlayer = game.getPlayer(playerList.get());
if (nextPlayer == null) {
return false;
}
if (firstNextPlayer == null) {
firstNextPlayer = nextPlayer.getId();
}
if (!nextPlayer.canRespond()) {
continue;
}
// Each player separates all nontoken lands they control into two piles
if (currentPlayer == null || !game.getState().getPlayersInRange(controller.getId(), game).contains(currentPlayer.getId())) {
continue;
}
List<Permanent> firstPile = new ArrayList<>();
List<Permanent> secondPile = new ArrayList<>();
FilterControlledLandPermanent filter = new FilterControlledLandPermanent("lands you control to assign to the first pile (lands not chosen will be assigned to the second pile)");
TargetPermanent target = new TargetControlledPermanent(0, Integer.MAX_VALUE, filter, true);
if (!target.canChoose(source.getSourceId(), currentPlayer.getId(), game)) { continue; }
// TODO: add support for AI (50/50), need AI hints mechanic here
currentPlayer.chooseTarget(Outcome.Neutral, target, source, game);
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, currentPlayer.getId(), game)) {
if (target.getTargets().contains(permanent.getId())) {
firstPile.add(permanent);
} else {
secondPile.add(permanent);
}
}
StringBuilder sb = new StringBuilder("First pile of ").append(currentPlayer.getLogName()).append(": ");
sb.append(firstPile.stream().map(Permanent::getLogName).collect(Collectors.joining(", ")));
game.informPlayers(sb.toString());
sb = new StringBuilder("Second pile of ").append(currentPlayer.getLogName()).append(": ");
sb.append(secondPile.stream().map(Permanent::getLogName).collect(Collectors.joining(", ")));
game.informPlayers(sb.toString());
List<List<Permanent>> playerPiles = new ArrayList<>();
playerPiles.add(firstPile);
playerPiles.add(secondPile);
playerPermanents.put(currentPlayer.getId(), playerPiles);
currentPlayer = nextPlayer;
}
// For each player, one of their piles is chosen by one of their opponents of their choice
for (Map.Entry<UUID, List<List<Permanent>>> playerPiles : playerPermanents.entrySet()) {
Player player = game.getPlayer(playerPiles.getKey());
if (player == null) { continue; }
FilterPlayer filter = new FilterPlayer("opponent");
List<PlayerIdPredicate> opponentPredicates = new ArrayList<>();
for (UUID opponentId : game.getOpponents(player.getId())) {
opponentPredicates.add(new PlayerIdPredicate(opponentId));
}
filter.add(Predicates.or(opponentPredicates));
Target target = new TargetPlayer(1, 1, true, filter);
target.setTargetController(player.getId());
target.setAbilityController(source.getControllerId());
if (!player.chooseTarget(outcome, target, source, game)) { continue; }
Player chosenOpponent = game.getPlayer(target.getFirstTarget());
if (chosenOpponent == null) { continue; }
List<Permanent> firstPile = playerPiles.getValue().get(0);
List<Permanent> secondPile = playerPiles.getValue().get(1);
game.informPlayers(player.getLogName() + " chose " + chosenOpponent.getLogName() + " to choose their pile");
if (chosenOpponent.choosePile(outcome, "Piles of " + player.getName(), firstPile, secondPile, game)) {
List<List<Permanent>> lists = playerPiles.getValue();
lists.clear();
lists.add(firstPile);
lists.add(secondPile);
game.informPlayers(player.getLogName() + " will have their first pile destroyed");
} else {
List<List<Permanent>> lists = playerPiles.getValue();
lists.clear();
lists.add(secondPile);
lists.add(firstPile);
game.informPlayers(player.getLogName() + " will have their second pile destroyed");
}
}
// Destroy all lands in the chosen piles. Tap all lands in the other piles
for (Map.Entry<UUID, List<List<Permanent>>> playerPiles : playerPermanents.entrySet()) {
Player player = game.getPlayer(playerPiles.getKey());
if (player == null) { continue; }
List<Permanent> pileToSac = playerPiles.getValue().get(0);
List<Permanent> pileToTap = playerPiles.getValue().get(1);
for (Permanent permanent : pileToSac) {
if (permanent != null) {
permanent.destroy(source, game, false);
}
}
for (Permanent permanent : pileToTap) {
if (permanent != null) {
permanent.tap(source, game);
}
}
}
return true;
}
private UUID getNextPlayerInDirection(boolean left, PlayerList playerList) {

View file

@ -63,19 +63,18 @@ class BenevolentOfferingEffect1 extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Target target = new TargetOpponent(true);
target.choose(Outcome.Sacrifice, source.getControllerId(), source.getSourceId(), game);
Player opponent = game.getPlayer(target.getFirstTarget());
if (opponent != null) {
Effect effect = new CreateTokenTargetEffect(new SpiritWhiteToken(), 3);
effect.setTargetPointer(new FixedTarget(opponent.getId()));
effect.apply(game, source);
new CreateTokenEffect(new SpiritWhiteToken(), 3).apply(game, source);
return true;
}
}
return false;
if (controller == null) { return false; }
Target target = new TargetOpponent(true);
target.choose(Outcome.Sacrifice, source.getControllerId(), source.getSourceId(), game);
Player opponent = game.getPlayer(target.getFirstTarget());
if (opponent == null) { return false; }
Effect effect = new CreateTokenTargetEffect(new SpiritWhiteToken(), 3);
effect.setTargetPointer(new FixedTarget(opponent.getId()));
effect.apply(game, source);
new CreateTokenEffect(new SpiritWhiteToken(), 3).apply(game, source);
return true;
}
}
@ -98,18 +97,18 @@ class BenevolentOfferingEffect2 extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Target target = new TargetOpponent(true);
target.choose(Outcome.Sacrifice, source.getControllerId(), source.getSourceId(), game);
Player opponent = game.getPlayer(target.getFirstTarget());
if (opponent != null) {
int count = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), game) * 2;
controller.gainLife(count, game, source);
count = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, opponent.getId(), game) * 2;
opponent.gainLife(count, game, source);
return true;
}
}
return false;
if (controller == null) { return false; }
Target target = new TargetOpponent(true);
target.choose(Outcome.Sacrifice, source.getControllerId(), source.getSourceId(), game);
Player opponent = game.getPlayer(target.getFirstTarget());
if (opponent == null) { return false; }
int count = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), game) * 2;
controller.gainLife(count, game, source);
count = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, opponent.getId(), game) * 2;
opponent.gainLife(count, game, source);
return true;
}
}

View file

@ -67,7 +67,7 @@ public final class BenthicExplorers extends CardImpl {
class BenthicExplorersCost extends CostImpl {
TargetLandPermanent target;
private final TargetLandPermanent target;
public BenthicExplorersCost(TargetLandPermanent target) {
this.target = target;
@ -155,59 +155,60 @@ class BenthicExplorersManaEffect extends ManaEffect {
@Override
public Mana produceMana(Game game, Ability source) {
Mana mana = new Mana();
if (game == null) {
return mana;
}
if (game == null) { return mana; }
Choice choice = ManaType.getChoiceOfManaTypes(getManaTypes(game, source), false);
if (!choice.getChoices().isEmpty()) {
Player player = game.getPlayer(source.getControllerId());
if (choice.getChoices().size() == 1) {
choice.setChoice(choice.getChoices().iterator().next());
} else {
if (player == null
|| !player.choose(Outcome.Neutral, choice, game)) {
return mana;
}
}
if (choice.getChoice() != null) {
switch (choice.getChoice()) {
case "Black":
mana.setBlack(1);
break;
case "Blue":
mana.setBlue(1);
break;
case "Red":
mana.setRed(1);
break;
case "Green":
mana.setGreen(1);
break;
case "White":
mana.setWhite(1);
break;
case "Colorless":
mana.setColorless(1);
break;
}
if (choice.getChoices().isEmpty()) { return mana; }
Player player = game.getPlayer(source.getControllerId());
if (choice.getChoices().size() == 1) {
choice.setChoice(choice.getChoices().iterator().next());
} else {
if (player == null
|| !player.choose(Outcome.Neutral, choice, game)) {
return mana;
}
}
if (choice.getChoice() == null) { return mana; }
switch (choice.getChoice()) {
case "Black":
mana.setBlack(1);
break;
case "Blue":
mana.setBlue(1);
break;
case "Red":
mana.setRed(1);
break;
case "Green":
mana.setGreen(1);
break;
case "White":
mana.setWhite(1);
break;
case "Colorless":
mana.setColorless(1);
break;
}
return mana;
}
private Set<ManaType> getManaTypes(Game game, Ability source) {
Set<ManaType> types = EnumSet.noneOf(ManaType.class);
if (game == null
|| game.getPhase() == null) {
if (game == null || game.getPhase() == null) {
return types;
}
Permanent land = (Permanent) game.getState().getValue("UntapTargetCost" + source.getSourceId().toString());
if (land != null) {
Abilities<ActivatedManaAbilityImpl> mana = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD);
for (ActivatedManaAbilityImpl ability : mana) {
if (ability.definesMana(game)) {
types.addAll(ability.getProducableManaTypes(game));
}
if (land == null) { return types; }
Abilities<ActivatedManaAbilityImpl> mana = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD);
for (ActivatedManaAbilityImpl ability : mana) {
if (ability.definesMana(game)) {
types.addAll(ability.getProducableManaTypes(game));
}
}
return types;

View file

@ -127,15 +127,15 @@ class BerserkDestroyEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
//create delayed triggered ability
Effect effect = new BerserkDelayedDestroyEffect();
effect.setTargetPointer(new FixedTarget(this.getTargetPointer().getFirst(game, source), game));
AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect);
game.addDelayedTriggeredAbility(delayedAbility, source);
return true;
}
return false;
if (controller == null) { return false; }
//create delayed triggered ability
Effect effect = new BerserkDelayedDestroyEffect();
effect.setTargetPointer(new FixedTarget(this.getTargetPointer().getFirst(game, source), game));
AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect);
game.addDelayedTriggeredAbility(delayedAbility, source);
return true;
}
}
@ -158,15 +158,15 @@ class BerserkDelayedDestroyEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source));
if (permanent != null) {
AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class);
if (watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(permanent, game))) {
return permanent.destroy(source, game, false);
}
}
}
return false;
if (controller == null) { return false; }
Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source));
if (permanent == null) { return false; }
AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class);
if (watcher == null) { return false; }
return watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(permanent, game))
&& permanent.destroy(source, game, false);
}
}

View file

@ -26,7 +26,6 @@ public final class BiomanticMastery extends CardImpl {
// Draw a card for each creature target player controls, then draw a card for each creature another target player controls.
this.getSpellAbility().addEffect(new BiomanticMasteryEffect());
this.getSpellAbility().addTarget(new TargetPlayer(2));
}
private BiomanticMastery(final BiomanticMastery card) {
@ -58,16 +57,15 @@ class BiomanticMasteryEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
for (UUID playerId : getTargetPointer().getTargets(game, source)) {
Player player = game.getPlayer(playerId);
if (player != null) {
int creatures = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game);
controller.drawCards(creatures, source, game);
}
}
return true;
if (controller == null) { return false; }
for (UUID playerId : getTargetPointer().getTargets(game, source)) {
Player player = game.getPlayer(playerId);
if (player == null) { continue; }
int creatures = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game);
controller.drawCards(creatures, source, game);
}
return false;
return true;
}
}

View file

@ -63,23 +63,27 @@ class BitterFeudEntersBattlefieldEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) { return false; }
Permanent permanent = game.getPermanentEntering(source.getSourceId());
if (controller != null && permanent != null) {
TargetPlayer target = new TargetPlayer(2, 2, true);
controller.chooseTarget(outcome, target, source, game);
Player player1 = game.getPlayer(target.getFirstTarget());
if (target.getTargets().size() > 1) {
Player player2 = game.getPlayer(target.getTargets().get(1));
if (player1 != null && player2 != null) {
game.getState().setValue(source.getSourceId() + "_player1", player1);
game.getState().setValue(source.getSourceId() + "_player2", player2);
game.informPlayers(permanent.getLogName() + ": " + controller.getLogName() + " has chosen " + player1.getLogName() + " and " + player2.getLogName());
permanent.addInfo("chosen players", "<font color = 'blue'>Chosen players: " + player1.getName() + ", " + player2.getName() + "</font>", game);
return true;
}
}
}
return false;
if (permanent == null) { return false; }
TargetPlayer target = new TargetPlayer(2, 2, true);
controller.chooseTarget(outcome, target, source, game);
Player player1 = game.getPlayer(target.getFirstTarget());
if (player1 == null) { return false; }
if (target.getTargets().size() <= 1) { return false; }
Player player2 = game.getPlayer(target.getTargets().get(1));
if (player2 == null) { return false; }
game.getState().setValue(source.getSourceId() + "_player1", player1);
game.getState().setValue(source.getSourceId() + "_player2", player2);
game.informPlayers(permanent.getLogName() + ": " + controller.getLogName() + " has chosen " + player1.getLogName() + " and " + player2.getLogName());
permanent.addInfo("chosen players", "<font color = 'blue'>Chosen players: " + player1.getName() + ", " + player2.getName() + "</font>", game);
return true;
}
@Override
@ -91,8 +95,8 @@ class BitterFeudEntersBattlefieldEffect extends OneShotEffect {
class BitterFeudEffect extends ReplacementEffectImpl {
Player player1;
Player player2;
private Player player1;
private Player player2;
public BitterFeudEffect() {
super(Duration.WhileOnBattlefield, Outcome.Damage);
@ -101,6 +105,8 @@ class BitterFeudEffect extends ReplacementEffectImpl {
public BitterFeudEffect(final BitterFeudEffect effect) {
super(effect);
this.player1 = effect.player1;
this.player2 = effect.player2;
}
@Override
@ -110,54 +116,50 @@ class BitterFeudEffect extends ReplacementEffectImpl {
@Override
public boolean checksEventType(GameEvent event, Game game) {
switch (event.getType()) {
case DAMAGE_PERMANENT:
case DAMAGE_PLAYER:
return true;
default:
return false;
}
return event.getType() == GameEvent.EventType.DAMAGE_PERMANENT && event.getType() == GameEvent.EventType.DAMAGE_PLAYER;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
player1 = (Player) game.getState().getValue(source.getSourceId() + "_player1");
player2 = (Player) game.getState().getValue(source.getSourceId() + "_player2");
if (player1 != null && player2 != null) {
UUID targetPlayerId = null;
switch (event.getType()) {
case DAMAGE_PLAYER:
targetPlayerId = event.getTargetId();
break;
case DAMAGE_PERMANENT:
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null) {
targetPlayerId = permanent.getControllerId();
}
break;
default:
return false;
}
if (player1 == null) { return false; }
if (player1.getId().equals(targetPlayerId) || player2.getId().equals(targetPlayerId)) {
UUID sourcePlayerId = null;
MageObject damageSource = game.getObject(event.getSourceId());
if (damageSource instanceof StackObject) {
sourcePlayerId = ((StackObject) damageSource).getControllerId();
} else if (damageSource instanceof Permanent) {
sourcePlayerId = ((Permanent) damageSource).getControllerId();
} else if (damageSource instanceof Card) {
sourcePlayerId = ((Card) damageSource).getOwnerId();
}
if (sourcePlayerId != null
&& (player1.getId().equals(sourcePlayerId) || player2.getId().equals(sourcePlayerId))
&& !sourcePlayerId.equals(targetPlayerId)) {
return true;
}
}
player2 = (Player) game.getState().getValue(source.getSourceId() + "_player2");
if (player2 == null) { return false; }
UUID targetPlayerId;
switch (event.getType()) {
case DAMAGE_PLAYER:
targetPlayerId = event.getTargetId();
break;
case DAMAGE_PERMANENT:
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent == null) { return false; }
targetPlayerId = permanent.getControllerId();
break;
default:
return false;
}
return false;
if (!player1.getId().equals(targetPlayerId) && !player2.getId().equals(targetPlayerId)) { return false; }
UUID sourcePlayerId;
MageObject damageSource = game.getObject(event.getSourceId());
if (damageSource instanceof StackObject) {
sourcePlayerId = ((StackObject) damageSource).getControllerId();
} else if (damageSource instanceof Permanent) {
sourcePlayerId = ((Permanent) damageSource).getControllerId();
} else if (damageSource instanceof Card) {
sourcePlayerId = ((Card) damageSource).getOwnerId();
} else {
return false;
}
return sourcePlayerId != null
&& (player1.getId().equals(sourcePlayerId) || player2.getId().equals(sourcePlayerId))
&& !sourcePlayerId.equals(targetPlayerId);
}
@Override

View file

@ -57,12 +57,12 @@ class BlasphemousCostReductionEffect extends CostModificationEffectImpl {
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
int reductionAmount = game.getBattlefield().count(StaticFilters.FILTER_PERMANENT_CREATURE, source.getSourceId(), source.getControllerId(), game);
CardUtil.reduceCost(abilityToModify, reductionAmount);
return true;
}
return false;
if (player == null) { return false; }
int reductionAmount = game.getBattlefield().count(StaticFilters.FILTER_PERMANENT_CREATURE, source.getSourceId(), source.getControllerId(), game);
CardUtil.reduceCost(abilityToModify, reductionAmount);
return true;
}
@Override

View file

@ -89,15 +89,16 @@ class BlazingEffigyWatcher extends Watcher {
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.DAMAGED_PERMANENT) {
if (!event.getSourceId().equals(event.getTargetId())) {
MageObjectReference damageSourceRef = new MageObjectReference(event.getSourceId(), game);
MageObjectReference damageTargetRef = new MageObjectReference(event.getTargetId(), game);
if (game.getPermanentOrLKIBattlefield(event.getSourceId()) != null && game.getPermanentOrLKIBattlefield(event.getSourceId()).getName().equals("Blazing Effigy")) {
damagedObjects.putIfAbsent(damageTargetRef, 0);
damagedObjects.compute(damageTargetRef, (k, damage) -> damage + event.getAmount());
}
}
if (event.getType() != GameEvent.EventType.DAMAGED_PERMANENT) { return; }
if (event.getSourceId().equals(event.getTargetId())) { return; }
// TODO: Should damageSourceRef be used for anything?
MageObjectReference damageSourceRef = new MageObjectReference(event.getSourceId(), game);
MageObjectReference damageTargetRef = new MageObjectReference(event.getTargetId(), game);
if (game.getPermanentOrLKIBattlefield(event.getSourceId()) != null && game.getPermanentOrLKIBattlefield(event.getSourceId()).getName().equals("Blazing Effigy")) {
damagedObjects.putIfAbsent(damageTargetRef, 0);
damagedObjects.compute(damageTargetRef, (k, damage) -> damage + event.getAmount());
}
}

View file

@ -23,9 +23,9 @@ public final class BlinkmothInfusion extends CardImpl {
public BlinkmothInfusion(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{12}{U}{U}");
// Affinity for artifacts
this.addAbility(new AffinityForArtifactsAbility());
// Untap all artifacts.
this.getSpellAbility().addEffect(new UntapAllArtifactsEffect());
}
@ -54,13 +54,12 @@ class UntapAllArtifactsEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
for (Permanent artifact: game.getBattlefield().getAllActivePermanents(new FilterArtifactPermanent(), game)) {
artifact.untap(game);
}
return true;
if (player == null) { return false; }
for (Permanent artifact: game.getBattlefield().getAllActivePermanents(new FilterArtifactPermanent(), game)) {
artifact.untap(game);
}
return false;
return true;
}
@Override

View file

@ -32,7 +32,6 @@ public final class BloodBaronOfVizkopa extends CardImpl {
// As long as you have 30 or more life and an opponent has 10 or less life, Blood Baron of Vizkopa gets +6/+6 and has flying.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BloodBaronOfVizkopaEffect()));
}
private BloodBaronOfVizkopa(final BloodBaronOfVizkopa card) {
@ -53,7 +52,7 @@ class BloodBaronOfVizkopaEffect extends ContinuousEffectImpl {
staticText = "As long as you have 30 or more life and an opponent has 10 or less life, {this} gets +6/+6 and has flying";
}
public BloodBaronOfVizkopaEffect(final BloodBaronOfVizkopaEffect effect) {
private BloodBaronOfVizkopaEffect(final BloodBaronOfVizkopaEffect effect) {
super(effect);
}
@ -64,41 +63,45 @@ class BloodBaronOfVizkopaEffect extends ContinuousEffectImpl {
@Override
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
if (conditionState(source, game)) {
Permanent creature = game.getPermanent(source.getSourceId());
if (creature != null) {
switch (layer) {
case PTChangingEffects_7:
if (sublayer == SubLayer.ModifyPT_7c) {
creature.addPower(6);
creature.addToughness(6);
}
break;
case AbilityAddingRemovingEffects_6:
if (sublayer == SubLayer.NA) {
creature.addAbility(FlyingAbility.getInstance(), source.getSourceId(), game);
}
break;
default:
if (!conditionState(source, game)) { return false; }
Permanent creature = game.getPermanent(source.getSourceId());
if (creature == null) { return false; }
switch (layer) {
case PTChangingEffects_7:
if (sublayer == SubLayer.ModifyPT_7c) {
creature.addPower(6);
creature.addToughness(6);
}
return true;
}
break;
case AbilityAddingRemovingEffects_6:
if (sublayer == SubLayer.NA) {
creature.addAbility(FlyingAbility.getInstance(), source.getSourceId(), game);
}
break;
default:
return false;
}
return false;
return true;
}
protected boolean conditionState(Ability source, Game game) {
private boolean conditionState(Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && controller.getLife() >= 30) {
for (UUID opponentId : game.getState().getPlayersInRange(controller.getId(), game)) {
if (controller.hasOpponent(opponentId, game)) {
Player opponent = game.getPlayer(opponentId);
if (opponent != null && opponent.getLife() < 11) {
return true;
}
}
}
if (controller == null) { return false; }
if (controller.getLife() < 30) { return false; }
for (UUID opponentId : game.getState().getPlayersInRange(controller.getId(), game)) {
if (!controller.hasOpponent(opponentId, game)) { return false; }
Player opponent = game.getPlayer(opponentId);
if (opponent == null) { return false; }
return opponent.getLife() < 11;
}
return false;
}
@ -109,8 +112,6 @@ class BloodBaronOfVizkopaEffect extends ContinuousEffectImpl {
@Override
public boolean hasLayer(Layer layer) {
return (layer == Layer.AbilityAddingRemovingEffects_6 || layer == layer.PTChangingEffects_7);
return (layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.PTChangingEffects_7);
}
}

View file

@ -67,31 +67,34 @@ class BloodlineShamanEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) { return false; }
MageObject sourceObject = game.getObject(source.getSourceId());
if (sourceObject == null) { return false; }
Choice typeChoice = new ChoiceCreatureType(sourceObject);
if (controller != null && sourceObject != null && controller.choose(outcome, typeChoice, game)) {
game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice());
FilterCard filterSubtype = new FilterCard();
filterSubtype.add(SubType.byDescription(typeChoice.getChoice()).getPredicate());
if (!controller.choose(outcome, typeChoice, game)) { return false; }
// Reveal the top card of your library.
if (controller.getLibrary().hasCards()) {
Card card = controller.getLibrary().getFromTop(game);
Cards cards = new CardsImpl(card);
controller.revealCards(sourceObject.getIdName(), cards, game);
game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice());
FilterCard filterSubtype = new FilterCard();
filterSubtype.add(SubType.byDescription(typeChoice.getChoice()).getPredicate());
if (card != null) {
// If that card is a creature card of the chosen type, put it into your hand.
if (filterSubtype.match(card, game)) {
controller.moveCards(card, Zone.HAND, source, game);
// Otherwise, put it into your graveyard.
} else {
controller.moveCards(card, Zone.GRAVEYARD, source, game);
}
// Reveal the top card of your library.
if (controller.getLibrary().hasCards()) {
Card card = controller.getLibrary().getFromTop(game);
Cards cards = new CardsImpl(card);
controller.revealCards(sourceObject.getIdName(), cards, game);
if (card != null) {
// If that card is a creature card of the chosen type, put it into your hand.
if (filterSubtype.match(card, game)) {
controller.moveCards(card, Zone.HAND, source, game);
// Otherwise, put it into your graveyard.
} else {
controller.moveCards(card, Zone.GRAVEYARD, source, game);
}
}
return true;
}
return false;
return true;
}
}

View file

@ -30,8 +30,7 @@ public final class Blustersquall extends CardImpl {
this.getSpellAbility().addEffect(new TapTargetEffect());
// Overload {3}{U} (You may cast this spell for its overload cost. If you do, change its text by replacing all instances of "target" with "each.")
this.addAbility(new OverloadAbility(this, new BlustersqallTapAllEffect(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL), new ManaCostsImpl("{3}{U}")));
this.addAbility(new OverloadAbility(this, new BlustersqallTapAllEffect(), new ManaCostsImpl("{3}{U}")));
}
private Blustersquall(final Blustersquall card) {
@ -46,22 +45,18 @@ public final class Blustersquall extends CardImpl {
class BlustersqallTapAllEffect extends OneShotEffect {
protected FilterCreaturePermanent filter;
BlustersqallTapAllEffect(FilterCreaturePermanent filter) {
BlustersqallTapAllEffect() {
super(Outcome.Tap);
this.filter = filter;
staticText = "Tap each creature you don't control";
}
private BlustersqallTapAllEffect(final BlustersqallTapAllEffect effect) {
super(effect);
this.filter = effect.filter;
}
@Override
public boolean apply(Game game, Ability source) {
for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) {
for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL, source.getControllerId(), source.getSourceId(), game)) {
creature.tap(source, game);
}
return true;

View file

@ -64,7 +64,7 @@ public final class BoneyardScourge extends CardImpl {
class DiesWhileInGraveyardTriggeredAbility extends TriggeredAbilityImpl {
protected FilterCreaturePermanent filter;
private final FilterCreaturePermanent filter;
public DiesWhileInGraveyardTriggeredAbility(Effect effect, FilterCreaturePermanent filter) {
super(Zone.GRAVEYARD, effect, false);
@ -89,22 +89,19 @@ class DiesWhileInGraveyardTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (!zEvent.isDiesEvent()) { return false; }
for (Zone z : Zone.values()) {
if (game.getShortLivingLKI(sourceId, z) && z != Zone.GRAVEYARD) {
return false;
}
}
if (zEvent.isDiesEvent()) {
if (filter.match(zEvent.getTarget(), sourceId, controllerId, game)) {
return true;
}
}
return false;
return filter.match(zEvent.getTarget(), sourceId, controllerId, game);
}
@Override
public String getTriggerPhrase() {
return "Whenever " + filter.getMessage() + " dies while {this} is in your graveyard, " ;
}
}

View file

@ -54,7 +54,8 @@ class BoonweaverGiantEffect extends OneShotEffect {
public BoonweaverGiantEffect() {
super(Outcome.UnboostCreature);
this.staticText = "you may search your graveyard, hand, and/or library for an Aura card and put it onto the battlefield attached to {this}. If you search your library this way, shuffle.";
this.staticText = "you may search your graveyard, hand, and/or library for an Aura card and put it onto the battlefield attached to {this}." +
"If you search your library this way, shuffle.";
}
public BoonweaverGiantEffect(final BoonweaverGiantEffect effect) {
@ -69,45 +70,40 @@ class BoonweaverGiantEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
if (controller == null) { return false; }
FilterCard filter = new FilterCard("Aura card");
filter.add(CardType.ENCHANTMENT.getPredicate());
filter.add(SubType.AURA.getPredicate());
Card card = null;
Zone zone = null;
// Choose card from graveyard
if (controller.chooseUse(Outcome.Neutral, "Search your graveyard for an Aura card?", source, game)) {
TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(filter);
if (controller.choose(Outcome.PutCardInPlay, controller.getGraveyard(), target, game)) {
card = game.getCard(target.getFirstTarget());
if (card != null) {
zone = Zone.GRAVEYARD;
}
}
}
// Choose card from your hand
if (card == null && controller.chooseUse(Outcome.Neutral, "Search your Hand for an Aura card?", source, game)) {
TargetCardInHand target = new TargetCardInHand(filter);
if (controller.choose(Outcome.PutCardInPlay, controller.getHand(), target, game)) {
card = game.getCard(target.getFirstTarget());
if (card != null) {
zone = Zone.HAND;
}
}
}
// Choose a card from your library
if (card == null) {
TargetCardInLibrary target = new TargetCardInLibrary(filter);
if (controller.searchLibrary(target, source, game)) {
card = game.getCard(target.getFirstTarget());
if (card != null) {
zone = Zone.LIBRARY;
}
}
controller.shuffleLibrary(source, game);
}
// aura card found - attach it
// Aura card found - attach it
if (card != null) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {

View file

@ -109,13 +109,13 @@ class BosiumStripReplacementEffect extends ReplacementEffectImpl {
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Card card = (Card) game.getState().getValue("BosiumStrip");
if (card != null) {
((ZoneChangeEvent) event).setToZone(Zone.EXILED);
}
}
return false;
if (controller == null) { return false; }
Card card = (Card) game.getState().getValue("BosiumStrip");
if (card == null) { return false; }
((ZoneChangeEvent) event).setToZone(Zone.EXILED);
return true;
}
@Override
@ -126,16 +126,16 @@ class BosiumStripReplacementEffect extends ReplacementEffectImpl {
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.getToZone() == Zone.GRAVEYARD) {
Card card = game.getCard(event.getSourceId());
if (card != null
&& StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(card, game)) {
CastFromGraveyardWatcher watcher = game.getState().getWatcher(CastFromGraveyardWatcher.class);
return watcher != null
&& watcher.spellWasCastFromGraveyard(event.getTargetId(),
game.getState().getZoneChangeCounter(event.getTargetId()));
}
}
return false;
if (zEvent.getToZone() != Zone.GRAVEYARD) { return false; }
Card card = game.getCard(event.getSourceId());
if (card == null) { return false; }
if (!StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(card, game)) { return false; }
CastFromGraveyardWatcher watcher = game.getState().getWatcher(CastFromGraveyardWatcher.class);
return watcher != null
&& watcher.spellWasCastFromGraveyard(event.getTargetId(),
game.getState().getZoneChangeCounter(event.getTargetId()));
}
}

View file

@ -26,9 +26,10 @@ public final class BountyOfTheLuxa extends CardImpl {
public BountyOfTheLuxa(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{U}");
//At the beginning of your precombat main phase, remove all flood counters from Bounty of the Luxa. If no counters were removed this way, put a flood counter on Bounty of the Luxa and draw a card. Otherwise, add {C}{G}{U}.
// At the beginning of your precombat main phase, remove all flood counters from Bounty of the Luxa.
// If no counters were removed this way, put a flood counter on Bounty of the Luxa and draw a card.
// Otherwise, add {C}{G}{U}.
this.addAbility(new BeginningOfPreCombatMainTriggeredAbility(new BountyOfTheLuxaEffect(), TargetController.YOU, false));
}
private BountyOfTheLuxa(final BountyOfTheLuxa card) {
@ -46,7 +47,9 @@ class BountyOfTheLuxaEffect extends OneShotEffect {
public BountyOfTheLuxaEffect() {
super(Outcome.Benefit);
staticText = "remove all flood counters from {this}. If no counters were removed this way, put a flood counter on {this} and draw a card. Otherwise, add {C}{G}{U}";
staticText = "remove all flood counters from {this}. " +
"If no counters were removed this way, put a flood counter on {this} and draw a card. " +
"Otherwise, add {C}{G}{U}";
}
public BountyOfTheLuxaEffect(final BountyOfTheLuxaEffect effect) {
@ -65,26 +68,25 @@ class BountyOfTheLuxaEffect extends OneShotEffect {
if (bountyOfLuxa != null && bountyOfLuxa.getZoneChangeCounter(game) != source.getSourceObjectZoneChangeCounter()) {
bountyOfLuxa = null;
}
if (controller != null) {
if (bountyOfLuxa != null
&& bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD) > 0) {
bountyOfLuxa.removeCounters(CounterType.FLOOD.createInstance(bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD)), source, game);
if (bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD) == 0) {
Mana manaToAdd = new Mana();
manaToAdd.increaseColorless();
manaToAdd.increaseGreen();
manaToAdd.increaseBlue();
controller.getManaPool().addMana(manaToAdd, game, source);
}
} else {
if (bountyOfLuxa != null) {
new AddCountersSourceEffect(CounterType.FLOOD.createInstance()).apply(game, source);
}
controller.drawCards(1, source, game);
if (controller == null) { return false; }
if (bountyOfLuxa != null
&& bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD) > 0) {
bountyOfLuxa.removeCounters(CounterType.FLOOD.createInstance(bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD)), source, game);
if (bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD) == 0) {
Mana manaToAdd = new Mana();
manaToAdd.increaseColorless();
manaToAdd.increaseGreen();
manaToAdd.increaseBlue();
controller.getManaPool().addMana(manaToAdd, game, source);
}
return true;
} else {
if (bountyOfLuxa != null) {
new AddCountersSourceEffect(CounterType.FLOOD.createInstance()).apply(game, source);
}
controller.drawCards(1, source, game);
}
return false;
return true;
}
}

View file

@ -72,24 +72,23 @@ class BraceForImpactPreventDamageTargetEffect extends PreventionEffectImpl {
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
GameEvent preventEvent = new PreventDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), event.getAmount(), ((DamageEvent) event).isCombatDamage());
if (!game.replaceEvent(preventEvent)) {
int prevented = 0;
int damage = event.getAmount();
event.setAmount(0);
game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), damage));
prevented = damage;
if (game.replaceEvent(preventEvent)) { return false; }
int prevented;
int damage = event.getAmount();
event.setAmount(0);
game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), damage));
prevented = damage;
// add counters now
if (prevented > 0) {
Permanent targetPermanent = game.getPermanent(source.getTargets().getFirstTarget());
if (targetPermanent != null) {
targetPermanent.addCounters(CounterType.P1P1.createInstance(prevented), source.getControllerId(), source, game);
game.informPlayers("Brace for Impact: Prevented " + prevented + " damage ");
game.informPlayers("Brace for Impact: Adding " + prevented + " +1/+1 counters to " + targetPermanent.getName());
}
// add counters now
if (prevented > 0) {
Permanent targetPermanent = game.getPermanent(source.getTargets().getFirstTarget());
if (targetPermanent != null) {
targetPermanent.addCounters(CounterType.P1P1.createInstance(prevented), source.getControllerId(), source, game);
game.informPlayers("Brace for Impact: Prevented " + prevented + " damage ");
game.informPlayers("Brace for Impact: Adding " + prevented + " +1/+1 counters to " + targetPermanent.getName());
}
}
return false;
return true;
}
@Override

View file

@ -57,7 +57,7 @@ public final class BridgeFromBelow extends CardImpl {
class BridgeFromBelowAbility extends TriggeredAbilityImpl {
protected FilterCreaturePermanent filter;
private final FilterCreaturePermanent filter;
public BridgeFromBelowAbility(Effect effect, FilterCreaturePermanent filter) {
super(Zone.GRAVEYARD, effect, false);
@ -82,14 +82,12 @@ class BridgeFromBelowAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.isDiesEvent()) {
Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD);
if (permanent != null
&& filter.match(permanent, sourceId, controllerId, game)) {
return true;
}
}
return false;
if (!zEvent.isDiesEvent()) { return false; }
Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD);
if (permanent == null) { return false; }
return filter.match(permanent, sourceId, controllerId, game);
}
@Override

View file

@ -64,24 +64,24 @@ class BrightflameEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent target = game.getPermanent(targetPointer.getFirst(game, source));
int damageDealt = 0;
if (target != null) {
ObjectColor color = target.getColor(game);
damageDealt += target.damage(amount.calculate(game, source, this), source.getSourceId(), source, game);
for (Permanent p : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) {
if (!target.getId().equals(p.getId()) && p.getColor(game).shares(color)) {
damageDealt += p.damage(amount.calculate(game, source, this), source.getSourceId(), source, game, false, true);
}
}
Player you = game.getPlayer(source.getControllerId());
if (you != null && damageDealt > 0) {
you.gainLife(damageDealt, game, source);
Permanent target = game.getPermanent(targetPointer.getFirst(game, source));
if (target == null) { return false; }
ObjectColor color = target.getColor(game);
damageDealt += target.damage(amount.calculate(game, source, this), source.getSourceId(), source, game);
for (Permanent p : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) {
if (!target.getId().equals(p.getId()) && p.getColor(game).shares(color)) {
damageDealt += p.damage(amount.calculate(game, source, this), source.getSourceId(), source, game, false, true);
}
return true;
}
return false;
Player you = game.getPlayer(source.getControllerId());
if (you != null && damageDealt > 0) {
you.gainLife(damageDealt, game, source);
}
return true;
}
@Override

View file

@ -75,31 +75,30 @@ class BrimazKingOfOreskosEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) { return false; }
if (controller != null) {
Token token = new CatSoldierCreatureToken();
token.putOntoBattlefield(1, game, source, source.getControllerId());
Permanent attackingCreature = game.getPermanent(getTargetPointer().getFirst(game, source));
if (attackingCreature != null && game.getState().getCombat() != null) {
// Possible ruling (see Aetherplasm)
// The token you created is blocking the attacking creature,
// even if the block couldn't legally be declared (for example, if that creature
// enters the battlefield tapped, or it can't block, or the attacking creature
// has protection from it)
CombatGroup combatGroup = game.getState().getCombat().findGroup(attackingCreature.getId());
if (combatGroup != null) {
for (UUID tokenId : token.getLastAddedTokenIds()) {
Permanent catToken = game.getPermanent(tokenId);
if (catToken != null) {
combatGroup.addBlocker(tokenId, source.getControllerId(), game);
game.getCombat().addBlockingGroup(tokenId, attackingCreature.getId(), controller.getId(), game);
}
}
combatGroup.pickBlockerOrder(attackingCreature.getControllerId(), game);
}
}
return true;
Token token = new CatSoldierCreatureToken();
token.putOntoBattlefield(1, game, source, source.getControllerId());
Permanent attackingCreature = game.getPermanent(getTargetPointer().getFirst(game, source));
if (attackingCreature == null || game.getState().getCombat() == null) { return true; }
// Possible ruling (see Aetherplasm)
// The token you created is blocking the attacking creature,
// even if the block couldn't legally be declared (for example, if that creature
// enters the battlefield tapped, or it can't block, or the attacking creature
// has protection from it)
CombatGroup combatGroup = game.getState().getCombat().findGroup(attackingCreature.getId());
if (combatGroup == null) { return true; }
for (UUID tokenId : token.getLastAddedTokenIds()) {
Permanent catToken = game.getPermanent(tokenId);
if (catToken == null) { continue; }
combatGroup.addBlocker(tokenId, source.getControllerId(), game);
game.getCombat().addBlockingGroup(tokenId, attackingCreature.getId(), controller.getId(), game);
}
return false;
combatGroup.pickBlockerOrder(attackingCreature.getControllerId(), game);
return true;
}
}

View file

@ -68,26 +68,27 @@ class BrineHagEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) { return false; }
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (sourcePermanent != null) {
List<Permanent> list = new ArrayList<>();
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Player player = game.getPlayer(playerId);
if (player != null) {
for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game)) {
if (sourcePermanent.getDealtDamageByThisTurn().contains(new MageObjectReference(creature.getId(), game))) {
list.add(creature);
}
}
if (sourcePermanent == null) { return false; }
List<Permanent> list = new ArrayList<>();
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Player player = game.getPlayer(playerId);
if (player == null) { continue; }
for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game)) {
if (sourcePermanent.getDealtDamageByThisTurn().contains(new MageObjectReference(creature.getId(), game))) {
list.add(creature);
}
}
if (!list.isEmpty()) {
FilterCreaturePermanent filter = new FilterCreaturePermanent();
filter.add(new PermanentInListPredicate(list));
game.addEffect(new SetPowerToughnessAllEffect(0, 2, Duration.Custom, filter, true), source);
}
return true;
}
return false;
if (!list.isEmpty()) {
FilterCreaturePermanent filter = new FilterCreaturePermanent();
filter.add(new PermanentInListPredicate(list));
game.addEffect(new SetPowerToughnessAllEffect(0, 2, Duration.Custom, filter, true), source);
}
return true;
}
}

View file

@ -32,8 +32,9 @@ public final class BroodhatchNantuko extends CardImpl {
// Whenever Broodhatch Nantuko is dealt damage, you may create that many 1/1 green Insect creature tokens.
this.addAbility(new DealtDamageToSourceTriggeredAbility(new BroodhatchNantukoDealDamageEffect(), true, false));
// Morph {2}{G}
this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{G}")));
this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{2}{G}")));
}
private BroodhatchNantuko(final BroodhatchNantuko card) {
@ -65,12 +66,11 @@ class BroodhatchNantukoDealDamageEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
int amount = (Integer) getValue("damage");
if (amount > 0) {
return new CreateTokenEffect(new InsectToken(), amount).apply(game, source);
}
}
return false;
if (player == null) { return false; }
int amount = (Integer) getValue("damage");
if (amount <= 0) { return false; }
return new CreateTokenEffect(new InsectToken(), amount).apply(game, source);
}
}

View file

@ -19,7 +19,7 @@ import mage.game.permanent.token.DragonToken;
*/
public final class BroodmateDragon extends CardImpl {
private static DragonToken dragonToken = new DragonToken();
private static final DragonToken dragonToken = new DragonToken();
public BroodmateDragon(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{R}{G}");

View file

@ -75,8 +75,10 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
UUID bruna = source.getSourceId();
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) { return false; }
UUID bruna = source.getSourceId();
FilterPermanent filterAura = new FilterPermanent("Aura");
FilterCard filterAuraCard = new FilterCard("Aura card");
@ -88,13 +90,9 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect {
filterAuraCard.add(SubType.AURA.getPredicate());
filterAuraCard.add(new AuraCardCanAttachToPermanentId(bruna));
if (controller == null) {
return false;
}
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (sourcePermanent == null) {
return false;
}
if (sourcePermanent == null) { return false; }
List<Permanent> fromBattlefield = new ArrayList<>();
List<Card> fromHandGraveyard = new ArrayList<>();
@ -104,16 +102,17 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect {
&& controller.chooseUse(Outcome.Benefit, "Attach an Aura from the battlefield?", source, game)) {
Target targetAura = new TargetPermanent(filterAura);
targetAura.setNotTarget(true);
if (controller.choose(Outcome.Benefit, targetAura, source.getSourceId(), game)) {
Permanent aura = game.getPermanent(targetAura.getFirstTarget());
if (aura != null) {
Target target = aura.getSpellAbility().getTargets().get(0);
if (target != null) {
fromBattlefield.add(aura);
filterAura.add(Predicates.not(new CardIdPredicate(aura.getId())));
}
}
}
if (!controller.choose(Outcome.Benefit, targetAura, source.getSourceId(), game)) { continue; }
Permanent aura = game.getPermanent(targetAura.getFirstTarget());
if (aura == null) { continue; }
Target target = aura.getSpellAbility().getTargets().get(0);
if (target == null) { continue; }
fromBattlefield.add(aura);
filterAura.add(Predicates.not(new CardIdPredicate(aura.getId())));
countBattlefield = game.getBattlefield().getAllActivePermanents(filterAura, game).size() - sourcePermanent.getAttachments().size();
}
@ -122,16 +121,16 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect {
&& countHand > 0
&& controller.chooseUse(Outcome.Benefit, "Attach an Aura from your hand?", source, game)) {
TargetCard targetAura = new TargetCard(Zone.HAND, filterAuraCard);
if (controller.choose(Outcome.Benefit, controller.getHand(), targetAura, game)) {
Card aura = game.getCard(targetAura.getFirstTarget());
if (aura != null) {
Target target = aura.getSpellAbility().getTargets().get(0);
if (target != null) {
fromHandGraveyard.add(aura);
filterAuraCard.add(Predicates.not(new CardIdPredicate(aura.getId())));
}
}
}
if (!controller.choose(Outcome.Benefit, controller.getHand(), targetAura, game)) { continue; }
Card aura = game.getCard(targetAura.getFirstTarget());
if (aura == null) { continue; }
Target target = aura.getSpellAbility().getTargets().get(0);
if (target == null) { continue; }
fromHandGraveyard.add(aura);
filterAuraCard.add(Predicates.not(new CardIdPredicate(aura.getId())));
countHand = controller.getHand().count(filterAuraCard, game);
}
@ -140,18 +139,20 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect {
&& countGraveyard > 0
&& controller.chooseUse(Outcome.Benefit, "Attach an Aura from your graveyard?", source, game)) {
TargetCard targetAura = new TargetCard(Zone.GRAVEYARD, filterAuraCard);
if (controller.choose(Outcome.Benefit, controller.getGraveyard(), targetAura, game)) {
Card aura = game.getCard(targetAura.getFirstTarget());
if (aura != null) {
Target target = aura.getSpellAbility().getTargets().get(0);
if (target != null) {
fromHandGraveyard.add(aura);
filterAuraCard.add(Predicates.not(new CardIdPredicate(aura.getId())));
}
}
}
if (!controller.choose(Outcome.Benefit, controller.getGraveyard(), targetAura, game)) { continue; }
Card aura = game.getCard(targetAura.getFirstTarget());
if (aura == null) { continue; }
Target target = aura.getSpellAbility().getTargets().get(0);
if (target == null) { continue; }
fromHandGraveyard.add(aura);
filterAuraCard.add(Predicates.not(new CardIdPredicate(aura.getId())));
countGraveyard = controller.getGraveyard().count(filterAuraCard, game);
}
// Move permanents
for (Permanent aura : fromBattlefield) {
Permanent attachedTo = game.getPermanent(aura.getAttachedTo());
@ -160,13 +161,14 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect {
}
sourcePermanent.addAttachment(aura.getId(), source, game);
}
// Move cards
for (Card aura : fromHandGraveyard) {
if (aura != null) {
game.getState().setValue("attachTo:" + aura.getId(), sourcePermanent);
controller.moveCards(aura, Zone.BATTLEFIELD, source, game);
sourcePermanent.addAttachment(aura.getId(), source, game);
}
if (aura == null) { continue; }
game.getState().setValue("attachTo:" + aura.getId(), sourcePermanent);
controller.moveCards(aura, Zone.BATTLEFIELD, source, game);
sourcePermanent.addAttachment(aura.getId(), source, game);
}
return true;
}

View file

@ -70,13 +70,12 @@ class BudokaGardenerEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
if (game.getBattlefield().count(filterLands, source.getSourceId(), source.getControllerId(), game) >= 10) {
new FlipSourceEffect(new DokaiWeaverofLife()).apply(game, source);
}
return true;
if (controller == null) { return false; }
if (game.getBattlefield().count(filterLands, source.getSourceId(), source.getControllerId(), game) < 10) {
return false;
}
return false;
return new FlipSourceEffect(new DokaiWeaverofLife()).apply(game, source);
}
@Override

View file

@ -15,7 +15,7 @@ import java.util.UUID;
public final class BullElephant extends CardImpl {
private static FilterControlledLandPermanent controlledForest = new FilterControlledLandPermanent("Forests");
private static final FilterControlledLandPermanent controlledForest = new FilterControlledLandPermanent("Forests");
static {
controlledForest.add(SubType.FOREST.getPredicate());
@ -25,10 +25,14 @@ public final class BullElephant extends CardImpl {
public BullElephant(UUID cardId, CardSetInfo cardSetInfo) {
super(cardId, cardSetInfo, new CardType[]{CardType.CREATURE}, "{3}{G}");
this.subtype.add(SubType.ELEPHANT);
power = new MageInt(4);
toughness = new MageInt(4);
//When Bull Elephant enters the battlefield, sacrifice it unless you return two Forests you control to their owner's hand.
addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(2, 2, controlledForest, false)))));
// When Bull Elephant enters the battlefield, sacrifice it unless you return two Forests you control to their owner's hand.
addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ReturnToHandChosenControlledPermanentCost(
new TargetControlledPermanent(2, 2, controlledForest, false)
))));
}
public BullElephant(BullElephant other) {

View file

@ -32,7 +32,6 @@ public final class BurnFromWithin extends CardImpl {
// If that creature would die this turn, exile it instead.
this.getSpellAbility().addEffect(new BurnFromWithinEffect());
this.getSpellAbility().addTarget(new TargetAnyTarget());
}
private BurnFromWithin(final BurnFromWithin card) {
@ -49,7 +48,9 @@ class BurnFromWithinEffect extends OneShotEffect {
public BurnFromWithinEffect() {
super(Outcome.Benefit);
this.staticText = "{this} deals X damage to any target. If a creature is dealt damage this way, it loses indestructible until end of turn. If that creature would die this turn, exile it instead";
this.staticText = "{this} deals X damage to any target. " +
"If a creature is dealt damage this way, it loses indestructible until end of turn. " +
"If that creature would die this turn, exile it instead";
}
public BurnFromWithinEffect(final BurnFromWithinEffect effect) {
@ -64,25 +65,31 @@ class BurnFromWithinEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source));
int amount = source.getManaCostsToPay().getX();
if (creature != null) {
game.addEffect(new DiesReplacementEffect(new MageObjectReference(creature, game), Duration.EndOfTurn), source);
int damageDealt = creature.damage(amount, source.getSourceId(), source, game, false, true);
if (damageDealt > 0) {
ContinuousEffect effect = new LoseAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn);
effect.setTargetPointer(new FixedTarget(creature.getId(), game));
game.addEffect(effect, source);
}
return true;
}
Player targetPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source));
if (targetPlayer != null) {
targetPlayer.damage(amount, source.getSourceId(), source, game);
return true;
if (controller == null) { return false; }
int amount = source.getManaCostsToPay().getX();
// Target is a creature
Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source));
if (creature != null) {
game.addEffect(new DiesReplacementEffect(new MageObjectReference(creature, game), Duration.EndOfTurn), source);
int damageDealt = creature.damage(amount, source.getSourceId(), source, game, false, true);
if (damageDealt > 0) {
ContinuousEffect effect = new LoseAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn);
effect.setTargetPointer(new FixedTarget(creature.getId(), game));
game.addEffect(effect, source);
}
return true;
}
// Target is a player
Player targetPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source));
if (targetPlayer != null) {
targetPlayer.damage(amount, source.getSourceId(), source, game);
return true;
}
// No valid target
return false;
}
}

View file

@ -145,7 +145,7 @@ class BurningCinderFuryOfCrimsonChaosFireEffect extends OneShotEffect {
class BurningCinderFuryOfCrimsonChaosFireCreatureGainControlEffect extends ContinuousEffectImpl {
private UUID controller;
private final UUID controller;
public BurningCinderFuryOfCrimsonChaosFireCreatureGainControlEffect(Duration duration, UUID controller) {
super(duration, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl);

View file

@ -63,20 +63,19 @@ class BurningOfXinyeEffect extends OneShotEffect{
boolean abilityApplied = false;
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
abilityApplied |= playerDestroys(game, source, controller);
}
Player opponent = game.getPlayer(source.getFirstTarget());
if (controller != null) {
if (opponent != null) {
abilityApplied |= playerDestroys(game, source, opponent);
}
return abilityApplied;
}
public boolean playerDestroys(Game game, Ability source,Player player){
private boolean playerDestroys(Game game, Ability source, Player player){
boolean abilityApplied = false;
int realCount = game.getBattlefield().countAll(filter, player.getId(), game);
@ -88,10 +87,10 @@ class BurningOfXinyeEffect extends OneShotEffect{
player.choose(Outcome.Sacrifice, target, source.getSourceId(), game);
}
for ( int idx = 0; idx < target.getTargets().size(); idx++) {
Permanent permanent = game.getPermanent(target.getTargets().get(idx));
for (UUID targetId : target.getTargets()) {
Permanent permanent = game.getPermanent(targetId);
if ( permanent != null ) {
if (permanent != null) {
abilityApplied |= permanent.destroy(source, game, false);
}
}
@ -103,5 +102,4 @@ class BurningOfXinyeEffect extends OneShotEffect{
public BurningOfXinyeEffect copy() {
return new BurningOfXinyeEffect(this);
}
}

View file

@ -37,10 +37,11 @@ public final class KnowledgePool extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}");
// Imprint - When Knowledge Pool enters the battlefield, each player exiles the top three cards of their library
this.addAbility(new EntersBattlefieldTriggeredAbility(new KnowledgePoolEffect1(), false).setAbilityWord(AbilityWord.IMPRINT));
this.addAbility(new EntersBattlefieldTriggeredAbility(new KnowledgePoolExileThreeCardsEffect(), false).setAbilityWord(AbilityWord.IMPRINT));
// Whenever a player casts a spell from their hand, that player exiles it. If the player does, they may cast another nonland card exiled with Knowledge Pool without paying that card's mana cost.
this.addAbility(new KnowledgePoolAbility());
// Whenever a player casts a spell from their hand, that player exiles it.
// If the player does, they may cast another nonland card exiled with Knowledge Pool without paying that card's mana cost.
this.addAbility(new KnowledgePoolWhenCastFromHandAbility());
}
private KnowledgePool(final KnowledgePool card) {
@ -51,58 +52,62 @@ public final class KnowledgePool extends CardImpl {
public KnowledgePool copy() {
return new KnowledgePool(this);
}
}
class KnowledgePoolEffect1 extends OneShotEffect {
class KnowledgePoolExileThreeCardsEffect extends OneShotEffect {
public KnowledgePoolEffect1() {
public KnowledgePoolExileThreeCardsEffect() {
super(Outcome.Neutral);
staticText = "each player exiles the top three cards of their library";
}
public KnowledgePoolEffect1(final KnowledgePoolEffect1 effect) {
public KnowledgePoolExileThreeCardsEffect(final KnowledgePoolExileThreeCardsEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) { return false; }
MageObject sourceObject = game.getObject(source.getSourceId());
if (controller == null || sourceObject == null) {
return false;
}
if (sourceObject == null) { return false; }
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Player player = game.getPlayer(playerId);
if (player != null) {
player.moveCardsToExile(player.getLibrary().getTopCards(game, 3), source, game, true,
CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()),
sourceObject.getIdName() + " (" + sourceObject.getZoneChangeCounter(game) + ')');
}
if (player == null) { continue; }
player.moveCardsToExile(
player.getLibrary().getTopCards(game, 3),
source,
game,
true,
CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()),
sourceObject.getIdName() + " (" + sourceObject.getZoneChangeCounter(game) + ')'
);
}
return true;
}
@Override
public KnowledgePoolEffect1 copy() {
return new KnowledgePoolEffect1(this);
public KnowledgePoolExileThreeCardsEffect copy() {
return new KnowledgePoolExileThreeCardsEffect(this);
}
}
class KnowledgePoolAbility extends TriggeredAbilityImpl {
class KnowledgePoolWhenCastFromHandAbility extends TriggeredAbilityImpl {
public KnowledgePoolAbility() {
super(Zone.BATTLEFIELD, new KnowledgePoolEffect2(), false);
public KnowledgePoolWhenCastFromHandAbility() {
super(Zone.BATTLEFIELD, new KnowledgePoolExileAndPlayEffect(), false);
}
public KnowledgePoolAbility(final KnowledgePoolAbility ability) {
private KnowledgePoolWhenCastFromHandAbility(final KnowledgePoolWhenCastFromHandAbility ability) {
super(ability);
}
@Override
public KnowledgePoolAbility copy() {
return new KnowledgePoolAbility(this);
public KnowledgePoolWhenCastFromHandAbility copy() {
return new KnowledgePoolWhenCastFromHandAbility(this);
}
@Override
@ -112,72 +117,76 @@ class KnowledgePoolAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (event.getZone() == Zone.HAND) {
Spell spell = game.getStack().getSpell(event.getTargetId());
if (spell != null) {
for (Effect effect : this.getEffects()) {
effect.setTargetPointer(new FixedTarget(event.getTargetId()));
}
return true;
}
}
return false;
}
if (event.getZone() != Zone.HAND) { return false; }
Spell spell = game.getStack().getSpell(event.getTargetId());
if (spell == null) { return false; }
for (Effect effect : this.getEffects()) {
effect.setTargetPointer(new FixedTarget(event.getTargetId()));
}
return true;
}
}
class KnowledgePoolEffect2 extends OneShotEffect {
class KnowledgePoolExileAndPlayEffect extends OneShotEffect {
private static FilterNonlandCard filter = new FilterNonlandCard("nonland card exiled with Knowledge Pool");
public KnowledgePoolEffect2() {
public KnowledgePoolExileAndPlayEffect() {
super(Outcome.Neutral);
staticText = "Whenever a player casts a spell from their hand, that player exiles it. If the player does, they may cast another nonland card exiled with {this} without paying that card's mana cost";
}
public KnowledgePoolEffect2(final KnowledgePoolEffect2 effect) {
private KnowledgePoolExileAndPlayEffect(final KnowledgePoolExileAndPlayEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source));
if (spell == null) {
if (spell == null) { return false; }
Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (sourceObject == null ) { return false; }
Player spellController = game.getPlayer(spell.getControllerId());
if (spellController == null) { return false; }
UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), sourceObject.getZoneChangeCounter(game));
if (!spellController.moveCardsToExile(spell, source, game, true, exileZoneId, sourceObject.getIdName())) {
// The card didn't make it to exile, none of Knowledge Pool's effect applied
return false;
}
Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId());
Player spellController = game.getPlayer(spell.getControllerId());
if (spellController != null
&& sourceObject != null) {
UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), sourceObject.getZoneChangeCounter(game));
if (exileZoneId == null) {
return false;
}
if (spellController.moveCardsToExile(spell, source, game, true, exileZoneId, sourceObject.getIdName())) {
if (spellController.chooseUse(Outcome.PlayForFree, "Cast another nonland card exiled with " + sourceObject.getLogName() + " without paying that card's mana cost?", source, game)) {
FilterNonlandCard realFilter = filter.copy();
realFilter.add(Predicates.not(new CardIdPredicate(spell.getSourceId())));
TargetCardInExile target = new TargetCardInExile(0, 1, realFilter, source.getSourceId());
target.setNotTarget(true);
if (spellController.choose(Outcome.PlayForFree, game.getExile().getExileZone(exileZoneId), target, game)) {
Card card = game.getCard(target.getFirstTarget());
if (card != null
&& !card.getId().equals(spell.getSourceId())) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
spellController.cast(spellController.chooseAbilityForCast(card, game, true), game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
}
}
}
return true;
}
// From here on down the function returns true since at least part of the effect went off
if (!spellController.chooseUse(Outcome.PlayForFree, "Cast another nonland card exiled with " + sourceObject.getLogName() + " without paying that card's mana cost?", source, game)) {
// Pleyer didn't want to cast another spell BUT their original spell was exiled with Knowledge Pool, so return true.
return true;
}
return false;
FilterNonlandCard filter = new FilterNonlandCard("nonland card exiled with Knowledge Pool");
filter.add(Predicates.not(new CardIdPredicate(spell.getSourceId())));
TargetCardInExile target = new TargetCardInExile(0, 1, filter, source.getSourceId());
target.setNotTarget(true);
if (!spellController.choose(Outcome.PlayForFree, game.getExile().getExileZone(exileZoneId), target, game)) {
// Player chose to not cast any ofthe spells
return true;
}
Card card = game.getCard(target.getFirstTarget());
if (card == null || card.getId().equals(spell.getSourceId())) { return true; }
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
spellController.cast(spellController.chooseAbilityForCast(card, game, true), game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
return true;
}
@Override
public KnowledgePoolEffect2 copy() {
return new KnowledgePoolEffect2(this);
public KnowledgePoolExileAndPlayEffect copy() {
return new KnowledgePoolExileAndPlayEffect(this);
}
}

View file

@ -70,16 +70,15 @@ class PossibilityStormTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (event.getZone() == Zone.HAND) {
Spell spell = game.getStack().getSpell(event.getTargetId());
if (spell != null) {
for (Effect effect : this.getEffects()) {
effect.setTargetPointer(new FixedTarget(event.getTargetId()));
}
return true;
}
if (event.getZone() != Zone.HAND) { return false; }
Spell spell = game.getStack().getSpell(event.getTargetId());
if (spell == null) { return false; }
for (Effect effect : this.getEffects()) {
effect.setTargetPointer(new FixedTarget(event.getTargetId()));
}
return false;
return true;
}
@Override
@ -107,43 +106,44 @@ class PossibilityStormEffect extends OneShotEffect {
spell = ((Spell) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.STACK));
noLongerOnStack = true;
}
if (spell == null) { return false; }
Player spellController = game.getPlayer(spell.getControllerId());
if (spellController == null) { return false; }
MageObject sourceObject = source.getSourceObject(game);
if (sourceObject != null && spell != null) {
Player spellController = game.getPlayer(spell.getControllerId());
if (spellController != null) {
if (!noLongerOnStack) {
spellController.moveCardsToExile(spell, source, game, true, source.getSourceId(), sourceObject.getIdName());
}
if (spellController.getLibrary().hasCards()) {
Library library = spellController.getLibrary();
Card card;
do {
card = library.getFromTop(game);
if (card != null) {
spellController.moveCardsToExile(card, source, game, true, source.getSourceId(), sourceObject.getIdName());
}
} while (library.hasCards() && card != null && !sharesType(card, spell.getCardType(game), game));
if (sourceObject == null) { return false; }
if (card != null && sharesType(card, spell.getCardType(game), game)
&& !card.isLand(game)
&& card.getSpellAbility().canChooseTarget(game, spellController.getId())) {
if (spellController.chooseUse(Outcome.PlayForFree, "Cast " + card.getLogName() + " without paying cost?", source, game)) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
spellController.cast(spellController.chooseAbilityForCast(card, game, true), game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
}
}
if (!noLongerOnStack) {
spellController.moveCardsToExile(spell, source, game, true, source.getSourceId(), sourceObject.getIdName());
}
ExileZone exile = game.getExile().getExileZone(source.getSourceId());
if (exile != null) {
spellController.putCardsOnBottomOfLibrary(exile, game, source, false);
}
if (!spellController.getLibrary().hasCards()) { return true; }
Library library = spellController.getLibrary();
Card card;
do {
card = library.getFromTop(game);
if (card != null) {
spellController.moveCardsToExile(card, source, game, true, source.getSourceId(), sourceObject.getIdName());
}
} while (library.hasCards() && card != null && !sharesType(card, spell.getCardType(game), game));
}
return true;
if (card != null && sharesType(card, spell.getCardType(game), game)
&& !card.isLand(game)
&& card.getSpellAbility().canChooseTarget(game, spellController.getId())) {
if (spellController.chooseUse(Outcome.PlayForFree, "Cast " + card.getLogName() + " without paying cost?", source, game)) {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
spellController.cast(spellController.chooseAbilityForCast(card, game, true), game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
}
}
return false;
ExileZone exile = game.getExile().getExileZone(source.getSourceId());
if (exile != null) {
spellController.putCardsOnBottomOfLibrary(exile, game, source, false);
}
return true;
}
private boolean sharesType(Card card, List<CardType> cardTypes, Game game) {

View file

@ -27,7 +27,9 @@ public final class ThievesAuction extends CardImpl {
public ThievesAuction(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}{R}{R}");
// Exile all nontoken permanents. Starting with you, each player chooses one of the exiled cards and puts it onto the battlefield tapped under their control. Repeat this process until all cards exiled this way have been chosen.
// Exile all nontoken permanents.
// Starting with you, each player chooses one of the exiled cards and puts it onto the battlefield tapped under their control.
// Repeat this process until all cards exiled this way have been chosen.
this.getSpellAbility().addEffect(new ThievesAuctionEffect());
}
@ -54,7 +56,7 @@ class ThievesAuctionEffect extends OneShotEffect {
this.staticText = "Exile all nontoken permanents. Starting with you, each player chooses one of the exiled cards and puts it onto the battlefield tapped under their control. Repeat this process until all cards exiled this way have been chosen";
}
ThievesAuctionEffect(final ThievesAuctionEffect effect) {
private ThievesAuctionEffect(final ThievesAuctionEffect effect) {
super(effect);
}
@ -66,36 +68,39 @@ class ThievesAuctionEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
// Exile all nontoken permanents.
Cards exiledCards = new CardsImpl();
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) {
exiledCards.add(permanent);
controller.moveCardsToExile(permanent, source, game, true, CardUtil.getCardExileZoneId(game, source.getSourceId()), "Thieves' Auction");
}
// Starting with you, each player
PlayerList playerList = game.getState().getPlayersInRange(controller.getId(), game);
Player player = playerList.getCurrent(game);
while (player != null && !exiledCards.isEmpty() && !game.hasEnded()) {
if (player.canRespond()) {
// chooses one of the exiled cards
TargetCard target = new TargetCardInExile(new FilterCard());
if (player.choose(Outcome.PutCardInPlay, exiledCards, target, game)) {
// and puts it onto the battlefield tapped under their control.
Card chosenCard = exiledCards.get(target.getFirstTarget(), game);
if (chosenCard != null) {
player.moveCards(chosenCard, Zone.BATTLEFIELD, source, game, true, false, false, null);
}
exiledCards.remove(chosenCard);
} else {
break;
}
}
// Repeat this process until all cards exiled this way have been chosen.
player = playerList.getNext(game, false);
}
return true;
if (controller == null) { return false; }
// Exile all nontoken permanents.
Cards exiledCards = new CardsImpl();
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) {
exiledCards.add(permanent);
controller.moveCardsToExile(permanent, source, game, true, CardUtil.getCardExileZoneId(game, source.getSourceId()), "Thieves' Auction");
}
return false;
// Starting with you, each player
PlayerList playerList = game.getState().getPlayersInRange(controller.getId(), game);
Player player = playerList.getCurrent(game);
while (player != null && !exiledCards.isEmpty() && !game.hasEnded()) {
if (!player.canRespond()) { continue; }
// chooses one of the exiled cards
TargetCard target = new TargetCardInExile(new FilterCard());
if (player.choose(Outcome.PutCardInPlay, exiledCards, target, game)) {
// and puts it onto the battlefield tapped under their control.
Card chosenCard = exiledCards.get(target.getFirstTarget(), game);
if (chosenCard != null) {
player.moveCards(chosenCard, Zone.BATTLEFIELD, source, game, true, false, false, null);
}
exiledCards.remove(chosenCard);
} else {
// TODO Why does this break?
break;
}
// Repeat this process until all cards exiled this way have been chosen.
player = playerList.getNext(game, false);
}
return true;
}
}

View file

@ -0,0 +1,54 @@
package org.mage.test.cards.single.dis;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class AzoriusAethermageTest extends CardTestPlayerBase {
/**
* Whenever you bounce a permanent (tokens included) you may pay {1}, if you do, draw a card
*/
@Test
public void testBouncedLand() {
/*
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); // Used for paying ability cost
addCard(Zone.BATTLEFIELD, playerA, "Island", 2*3);
addCard(Zone.BATTLEFIELD, playerA, "Toggo, Goblin Weaponsmith");
addCard(Zone.HAND, playerA, "Boomerang",3);
// Permanents to bounce
addCard(Zone.HAND, playerA, "Plains", 1);
addCard(Zone.BATTLEFIELD, playerA, "Azorius Aethermage");
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plains"); // Create a Rock token with Toggo
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boomerang", "Plains");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA, true);
setChoice(playerA, "Yes");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boomerang", "Rock");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA, true);
setChoice(playerA, "Yes");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boomerang", "Azorius Aethermage");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA, true);
setChoice(playerA, "Yes");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
setStopAt(1, PhaseStep.END_TURN);
setStrictChooseMode(true);
execute();
assertAllCommandsUsed();
// 3 cards bounced: plains, token, and aethermage, but the token never makes it to the hand -> +2 cards in hand
// 3 cards drawn -> +3 cards in hand
assertHandCount(playerA, (1+1) + (1) + (1+1));
*/
}
}

View file

@ -0,0 +1,108 @@
package org.mage.test.cards.single.hou;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class AbandonedSarcophagusTest extends CardTestPlayerBase {
/**
* You may cast non-land card with cycling from your graveyard
*/
@Test
public void castNonLandFromGraveyard() {
addCard(Zone.BATTLEFIELD, playerA, "Abandoned Sarcophagus");
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
addCard(Zone.GRAVEYARD, playerA, "Astral Drift"); // {2}{W} Enchantment
addCard(Zone.GRAVEYARD, playerA, "Ash Barrens"); // Land
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Astral Drift");
// Can't play lands with this ability
checkPlayableAbility("before play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Play Ash Barrens", false);
setStrictChooseMode(true);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Astral Drift", 1);
}
/**
* You can only cast the card from the graveyard, you CANNOT cycle it
*/
@Test
public void cantCycleFromGraveyard() {
addCard(Zone.BATTLEFIELD, playerA, "Abandoned Sarcophagus");
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
addCard(Zone.GRAVEYARD, playerA, "Astral Drift"); // {2}{W} Enchantment
addCard(Zone.GRAVEYARD, playerA, "Ash Barrens"); // Land
checkPlayableAbility("before play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cycling", false);
checkPlayableAbility("before play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Basic landcycling", false);
setStrictChooseMode(true);
execute();
assertAllCommandsUsed();
}
/**
* When a card with cycling is cycled it still goes to the graveyard
*/
@Test
public void cycledCardGoesToGraveyard() {
addCard(Zone.LIBRARY, playerA, "Forest", 5);
addCard(Zone.BATTLEFIELD, playerA, "Abandoned Sarcophagus");
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
addCard(Zone.HAND, playerA, "Astral Drift"); // {2}{W} Enchantment
addCard(Zone.HAND, playerA, "Ash Barrens"); // Land
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Basic landcycling");
addTarget(playerA, "Forest");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cycling");
setStopAt(1, PhaseStep.END_TURN);
setStrictChooseMode(true);
execute();
assertAllCommandsUsed();
assertHandCount(playerA, 2);
assertGraveyardCount(playerA, 2);
}
/**
* When a card goes to the graveyard and it WAS NOT cycled, it gets exiled
*/
@Test
public void nonCycledCardGoesToExile() {
addCard(Zone.BATTLEFIELD, playerA, "Abandoned Sarcophagus");
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 6);
addCard(Zone.HAND, playerA, "Astral Drift"); // {2}{W} Enchantment
addCard(Zone.HAND, playerA, "Ash Barrens"); // Land
addCard(Zone.HAND, playerA, "Beast Within", 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Astral Drift");
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ash Barrens");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Beast Within", "Astral Drift");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Beast Within", "Ash Barrens");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
setStrictChooseMode(true);
execute();
assertAllCommandsUsed();
assertExileCount(playerA, 2);
}
}