diff --git a/Mage.Sets/src/mage/cards/a/AAT1.java b/Mage.Sets/src/mage/cards/a/AAT1.java index 173888758e..3e17724d22 100644 --- a/Mage.Sets/src/mage/cards/a/AAT1.java +++ b/Mage.Sets/src/mage/cards/a/AAT1.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; @@ -21,8 +19,9 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author Styxo */ public final class AAT1 extends CardImpl { @@ -74,7 +73,8 @@ public final class AAT1 extends CardImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Card card = game.getCard(event.getTargetId()); - if (event.getPlayerId().equals(game.getControllerId(sourceId)) + if (card != null + && event.getPlayerId().equals(game.getControllerId(sourceId)) && card.isCreature() && game.getState().getZone(card.getId()) == Zone.GRAVEYARD && event.getData().equals("repair")) { diff --git a/Mage.Sets/src/mage/cards/a/Aluren.java b/Mage.Sets/src/mage/cards/a/Aluren.java index 8397fa65c9..a0c485b682 100644 --- a/Mage.Sets/src/mage/cards/a/Aluren.java +++ b/Mage.Sets/src/mage/cards/a/Aluren.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.SourceIsSpellCondition; @@ -17,29 +15,31 @@ import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * 10/4/2004 The mana cost of the creatures being cast is still the stated cost on the card, - * even though you did not pay the cost. + * 10/4/2004 The mana cost of the creatures being cast is still the stated cost on the card, + * even though you did not pay the cost. * 10/4/2004 Aluren checks the actual printed cost on the creature card, and is not affected - * by things which allow you to cast the spell for less. - * 10/4/2004 You can't choose to cast a creature as though it had flash via Aluren and still pay the mana cost. - * You either cast the creature normally, or via Aluren without paying the mana cost. - * 10/4/2004 You can't use Aluren when casting a creature using another alternate means, - * such as the Morph ability. - * 8/1/2008 If creature with X in its cost is cast this way, X can only be 0. - * + * by things which allow you to cast the spell for less. + * 10/4/2004 You can't choose to cast a creature as though it had flash via Aluren and still pay the mana cost. + * You either cast the creature normally, or via Aluren without paying the mana cost. + * 10/4/2004 You can't use Aluren when casting a creature using another alternate means, + * such as the Morph ability. + * 8/1/2008 If creature with X in its cost is cast this way, X can only be 0. + * * @author emerald000 */ public final class Aluren extends CardImpl { - + private static final FilterCreatureCard filter = new FilterCreatureCard("creature cards with converted mana cost 3 or less"); - + static { filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 4)); } - + public Aluren(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{G}"); // Any player may play creature cards with converted mana cost 3 or less without paying their mana cost @@ -63,15 +63,15 @@ public final class Aluren extends CardImpl { } class AlurenRuleEffect extends ContinuousEffectImpl { - + private static final FilterCreatureCard filter = new FilterCreatureCard("creature cards with converted mana cost 3 or less"); - + static { filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 4)); } - - private static AlternativeCostSourceAbility alternativeCastingCostAbility = new AlternativeCostSourceAbility(null, SourceIsSpellCondition.instance, null, filter, true); - + + private static AlternativeCostSourceAbility alternativeCastingCostAbility = new AlternativeCostSourceAbility(null, SourceIsSpellCondition.instance, null, filter, true); + public AlurenRuleEffect() { super(Duration.WhileOnBattlefield, Outcome.Detriment); staticText = "Any player may cast creature cards with converted mana cost 3 or less without paying their mana cost"; @@ -90,12 +90,12 @@ class AlurenRuleEffect extends ContinuousEffectImpl { public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - for (UUID playerId: game.getState().getPlayersInRange(controller.getId(), game)){ + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { player.getAlternativeSourceCosts().add(alternativeCastingCostAbility); } - } + } return true; } return false; @@ -110,47 +110,4 @@ class AlurenRuleEffect extends ContinuousEffectImpl { public boolean hasLayer(Layer layer) { return layer == Layer.RulesEffects; } -} - -//class AlurenEffect extends CostModificationEffectImpl { -// -// AlurenEffect() { -// super(Duration.WhileOnBattlefield, Outcome.PlayForFree, CostModificationType.SET_COST); -// this.staticText = "Any player may play creature cards with converted mana cost 3 or less without paying their mana cost"; -// } -// -// AlurenEffect(final AlurenEffect effect) { -// super(effect); -// } -// -// @Override -// public boolean apply(Game game, Ability source, Ability abilityToModify) { -// SpellAbility spellAbility = (SpellAbility) abilityToModify; -// spellAbility.getManaCostsToPay().clear(); -// return true; -// } -// -// @Override -// public boolean applies(Ability abilityToModify, Ability source, Game game) { -// if (abilityToModify instanceof SpellAbility) { -// Card sourceCard = game.getCard(abilityToModify.getSourceId()); -// StackObject stackObject = game.getStack().getStackObject(abilityToModify.getSourceId()); -// if (stackObject != null && stackObject instanceof Spell) { -// if (sourceCard != null && sourceCard.isCreature() && sourceCard.getConvertedManaCost() <= 3) { -// Player player = game.getPlayer(stackObject.getControllerId()); -// String message = "Cast " + sourceCard.getName() + " without paying its mana costs?"; -// if (player != null && -// (CardUtil.isCheckPlayableMode(abilityToModify) || player.chooseUse(outcome, message, game))) { -// return true; -// } -// } -// } -// } -// return false; -// } -// -// @Override -// public AlurenEffect copy() { -// return new AlurenEffect(this); -// } -//} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java b/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java index ee192097ff..56674534e0 100644 --- a/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java +++ b/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java @@ -1,9 +1,5 @@ - package mage.cards.a; -import java.util.Iterator; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; @@ -20,8 +16,11 @@ import mage.game.stack.Spell; import mage.game.stack.StackObject; import mage.players.Player; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class ArcaneAdaptation extends CardImpl { @@ -70,14 +69,14 @@ class ConspyEffect extends ContinuousEffectImpl { // in graveyard for (UUID cardId : controller.getGraveyard()) { Card card = game.getCard(cardId); - if (card.isCreature() && !card.hasSubtype(subType, game)) { + if (card != null && card.isCreature() && !card.hasSubtype(subType, game)) { game.getState().getCreateCardAttribute(card, game).getSubtype().add(subType); } } // on Hand for (UUID cardId : controller.getHand()) { Card card = game.getCard(cardId); - if (card.isCreature() && !card.hasSubtype(subType, game)) { + if (card != null && card.isCreature() && !card.hasSubtype(subType, game)) { game.getState().getCreateCardAttribute(card, game).getSubtype().add(subType); } } @@ -97,13 +96,13 @@ class ConspyEffect extends ContinuousEffectImpl { for (UUID commanderId : controller.getCommandersIds()) { if (game.getState().getZone(commanderId) == Zone.COMMAND) { Card card = game.getCard(commanderId); - if (card.isCreature() && !card.hasSubtype(subType, game)) { + if (card != null && card.isCreature() && !card.hasSubtype(subType, game)) { game.getState().getCreateCardAttribute(card, game).getSubtype().add(subType); } } } // creature spells you control - for (Iterator iterator = game.getStack().iterator(); iterator.hasNext();) { + for (Iterator iterator = game.getStack().iterator(); iterator.hasNext(); ) { StackObject stackObject = iterator.next(); if (stackObject instanceof Spell && stackObject.isControlledBy(source.getControllerId()) diff --git a/Mage.Sets/src/mage/cards/a/ArcaneArtisan.java b/Mage.Sets/src/mage/cards/a/ArcaneArtisan.java index 52fe2bd0c7..99cceae788 100644 --- a/Mage.Sets/src/mage/cards/a/ArcaneArtisan.java +++ b/Mage.Sets/src/mage/cards/a/ArcaneArtisan.java @@ -1,4 +1,3 @@ - package mage.cards.a; import mage.MageInt; @@ -97,26 +96,29 @@ class ArcaneArtisanCreateTokenEffect extends OneShotEffect { return false; } Card card = game.getCard(target.getFirstTarget()); - player.moveCards(card, Zone.EXILED, source, game); - if (!card.isCreature()) { + if (!player.moveCards(card, Zone.EXILED, source, game)) { return false; } - CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(player.getId()); - effect.setTargetPointer(new FixedTarget(card.getId(), game)); - effect.apply(game, source); - Object object = game.getState().getValue(CardUtil.getCardZoneString("_tokensCreated", source.getSourceId(), game)); - Set tokensCreated; - if (object != null) { - tokensCreated = (Set) object; - } else { - tokensCreated = new HashSet<>(); - } - for (Permanent perm : effect.getAddedPermanent()) { - if (perm != null) { - tokensCreated.add(perm.getId()); + + if (card.isCreature()) { + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(player.getId()); + effect.setTargetPointer(new FixedTarget(card.getId(), game)); + effect.apply(game, source); + Object object = game.getState().getValue(CardUtil.getCardZoneString("_tokensCreated", source.getSourceId(), game)); + Set tokensCreated; + if (object != null) { + tokensCreated = (Set) object; + } else { + tokensCreated = new HashSet<>(); } + for (Permanent perm : effect.getAddedPermanent()) { + if (perm != null) { + tokensCreated.add(perm.getId()); + } + } + game.getState().setValue(CardUtil.getCardZoneString("_tokensCreated", source.getSourceId(), game), tokensCreated); } - game.getState().setValue(CardUtil.getCardZoneString("_tokensCreated", source.getSourceId(), game), tokensCreated); + return true; } } diff --git a/Mage.Sets/src/mage/cards/b/BombSquad.java b/Mage.Sets/src/mage/cards/b/BombSquad.java index 154cdb4d63..b0cd273ca4 100644 --- a/Mage.Sets/src/mage/cards/b/BombSquad.java +++ b/Mage.Sets/src/mage/cards/b/BombSquad.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; @@ -26,20 +24,22 @@ import mage.players.Player; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * 10/4/2004: If the creature regenerates, the fuse counters are still removed and - * the four damage is still dealt. - * 10/4/2004: If there are two Bomb Squads on the battlefield when a creature ends - * up with 4 or more fuse counters, both Bomb Squad abilities will trigger - * causing 4 damage each even though the first to resolve will destroy the - * creature. + * 10/4/2004: If the creature regenerates, the fuse counters are still removed and + * the four damage is still dealt. + * 10/4/2004: If there are two Bomb Squads on the battlefield when a creature ends + * up with 4 or more fuse counters, both Bomb Squad abilities will trigger + * causing 4 damage each even though the first to resolve will destroy the + * creature. * * @author LevelX2 */ public final class BombSquad extends CardImpl { public BombSquad(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.subtype.add(SubType.DWARF); this.power = new MageInt(1); @@ -150,6 +150,7 @@ class BombSquadDamgeEffect extends OneShotEffect { class BombSquadBeginningEffect extends OneShotEffect { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with a fuse counter on it"); + static { filter.add(new CounterPredicate(CounterType.FUSE)); } @@ -171,6 +172,9 @@ class BombSquadBeginningEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Card card = game.getCard(source.getSourceId()); + if (card == null) { + return false; + } for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { permanent.addCounters(CounterType.FUSE.createInstance(), source, game); diff --git a/Mage.Sets/src/mage/cards/b/BorderlandExplorer.java b/Mage.Sets/src/mage/cards/b/BorderlandExplorer.java index b74b8f771c..f68f3ba599 100644 --- a/Mage.Sets/src/mage/cards/b/BorderlandExplorer.java +++ b/Mage.Sets/src/mage/cards/b/BorderlandExplorer.java @@ -1,9 +1,5 @@ - package mage.cards.b; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -22,8 +18,11 @@ import mage.target.Target; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetDiscard; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** - * * @author fireshoes */ public final class BorderlandExplorer extends CardImpl { @@ -127,11 +126,13 @@ class BorderlandExplorerEffect extends OneShotEffect { Cards cardsPlayer = cardsToReveal.get(playerId); if (cardsPlayer != null) { for (UUID cardId : cardsPlayer) { - Cards cards = new CardsImpl(game.getCard(cardId)); Card card = game.getCard(cardId); - player.revealCards(sourceObject.getIdName() + " (" + player.getName() + ')', cards, game); - player.moveCards(card, Zone.HAND, source, game); - player.shuffleLibrary(source, game); + Cards cards = new CardsImpl(game.getCard(cardId)); + if (card != null && !cards.isEmpty()) { + player.revealCards(sourceObject.getIdName() + " (" + player.getName() + ')', cards, game); + player.moveCards(card, Zone.HAND, source, game); + player.shuffleLibrary(source, game); + } } } } diff --git a/Mage/src/main/java/mage/game/Game.java b/Mage/src/main/java/mage/game/Game.java index 8ab4089a44..83640eaf62 100644 --- a/Mage/src/main/java/mage/game/Game.java +++ b/Mage/src/main/java/mage/game/Game.java @@ -1,10 +1,5 @@ - package mage.game; -import java.io.Serializable; -import java.util.*; -import java.util.stream.Collectors; - import mage.MageItem; import mage.MageObject; import mage.abilities.Ability; @@ -45,6 +40,10 @@ import mage.players.Players; import mage.util.MessageToClient; import mage.util.functions.ApplyToPermanent; +import java.io.Serializable; +import java.util.*; +import java.util.stream.Collectors; + public interface Game extends MageItem, Serializable { MatchType getGameType(); @@ -98,6 +97,7 @@ public interface Game extends MageItem, Serializable { Map> getLKI(); + // Result must be checked for null. Possible errors search pattern: (\S*) = game.getCard.+\n(?!.+\1 != null) Card getCard(UUID cardId); Optional getAbility(UUID abilityId, UUID sourceId); @@ -106,6 +106,7 @@ public interface Game extends MageItem, Serializable { void addPlayer(Player player, Deck deck); + // Result must be checked for null. Possible errors search pattern: (\S*) = game.getPlayer.+\n(?!.+\1 != null) Player getPlayer(UUID playerId); Player getPlayerOrPlaneswalkerController(UUID playerId); @@ -130,7 +131,7 @@ public interface Game extends MageItem, Serializable { } - default boolean isActivePlayer(UUID playerId){ + default boolean isActivePlayer(UUID playerId) { return getActivePlayerId().equals(playerId); } @@ -294,9 +295,9 @@ public interface Game extends MageItem, Serializable { /** * Creates and fires an damage prevention event * - * @param damageEvent damage event that will be replaced (instanceof check - * will be done) - * @param source ability that's the source of the prevention effect + * @param damageEvent damage event that will be replaced (instanceof check + * will be done) + * @param source ability that's the source of the prevention effect * @param game * @param amountToPrevent max preventable amount * @return true prevention was successfull / false prevention was replaced @@ -306,12 +307,12 @@ public interface Game extends MageItem, Serializable { /** * Creates and fires an damage prevention event * - * @param event damage event that will be replaced (instanceof check will be - * done) - * @param source ability that's the source of the prevention effect + * @param event damage event that will be replaced (instanceof check will be + * done) + * @param source ability that's the source of the prevention effect * @param game * @param preventAllDamage true if there is no limit to the damage that can - * be prevented + * be prevented * @return true prevention was successfull / false prevention was replaced */ PreventionEffectData preventDamage(GameEvent event, Ability source, Game game, boolean preventAllDamage);