From 2685d9f8b4740b4743ccf74aa337c3569b6c93a9 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 11 Jan 2018 06:12:27 +0100 Subject: [PATCH] Fixed some possible null pointer exceptions (found in server log). Market Festival, Kindred Summons, Profane Processions, New Blood, Kindred Charge , Bishop of Binding, Metzal Tower of Triumph, Chrome Mox --- .../src/mage/cards/b/BishopOfBinding.java | 8 +++++--- Mage.Sets/src/mage/cards/c/ChromeMox.java | 9 ++++++++- Mage.Sets/src/mage/cards/k/KindredCharge.java | 12 ++++++++---- .../src/mage/cards/k/KindredSummons.java | 19 ++++++++++++------- .../src/mage/cards/m/MarketFestival.java | 11 +++++------ .../mage/cards/m/MetzaliTowerOfTriumph.java | 8 +++++--- Mage.Sets/src/mage/cards/n/NewBlood.java | 8 +++----- .../src/mage/cards/p/ProfaneProcession.java | 2 +- ...tureEntersBattlefieldTriggeredAbility.java | 16 ++++++++-------- .../mage/game/permanent/PermanentImpl.java | 7 +++++++ 10 files changed, 62 insertions(+), 38 deletions(-) diff --git a/Mage.Sets/src/mage/cards/b/BishopOfBinding.java b/Mage.Sets/src/mage/cards/b/BishopOfBinding.java index 903d923eab7..ea0b73fdd79 100644 --- a/Mage.Sets/src/mage/cards/b/BishopOfBinding.java +++ b/Mage.Sets/src/mage/cards/b/BishopOfBinding.java @@ -132,9 +132,11 @@ class BishopOfBindingExiledCardsPowerCount implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, sourceAbility.getSourceId(), sourceAbility.getSourceObjectZoneChangeCounter())); - Card exiledCard = exileZone.getRandom(game); - if (exiledCard != null) { - return exiledCard.getPower().getValue(); + if (exileZone != null) { + Card exiledCard = exileZone.getRandom(game); + if (exiledCard != null) { + return exiledCard.getPower().getValue(); + } } return 0; } diff --git a/Mage.Sets/src/mage/cards/c/ChromeMox.java b/Mage.Sets/src/mage/cards/c/ChromeMox.java index 292d9cd2a5b..8358706f9b6 100644 --- a/Mage.Sets/src/mage/cards/c/ChromeMox.java +++ b/Mage.Sets/src/mage/cards/c/ChromeMox.java @@ -182,7 +182,14 @@ class ChromeMoxManaEffect extends ManaEffect { if (choice.getChoices().size() == 1) { choice.setChoice(choice.getChoices().iterator().next()); } else { - player.choose(outcome, choice, game); + while (!player.choose(outcome, choice, game)) { + if (!player.canRespond()) { + return false; + } + } + if (choice.getChoice() == null) { + return false; + } } switch (choice.getChoice()) { case "Black": diff --git a/Mage.Sets/src/mage/cards/k/KindredCharge.java b/Mage.Sets/src/mage/cards/k/KindredCharge.java index 46ef8164c35..fda4299dfb9 100644 --- a/Mage.Sets/src/mage/cards/k/KindredCharge.java +++ b/Mage.Sets/src/mage/cards/k/KindredCharge.java @@ -34,10 +34,10 @@ import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbil import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseCreatureTypeEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.abilities.effects.common.ExileTargetEffect; -import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; @@ -57,7 +57,7 @@ public class KindredCharge extends CardImpl { public KindredCharge(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}{R}"); - // Choose a creature type. For each creature you control of the chosen type, create a token that's a copy of that creature. + // Choose a creature type. For each creature you control of the chosen type, create a token that's a copy of that creature. // Those tokens gain haste. Exile them at the beginning of the next end step. this.getSpellAbility().addEffect(new ChooseCreatureTypeEffect(Outcome.Copy)); this.getSpellAbility().addEffect(new KindredChargeEffect()); @@ -95,7 +95,11 @@ class KindredChargeEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null && sourceObject != null) { - String creatureType = game.getState().getValue(sourceObject.getId() + "_type").toString(); + Object object = game.getState().getValue(sourceObject.getId() + "_type"); + if (object == null) { + return false; + } + String creatureType = object.toString(); FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature you control of the chosen type"); filter.add(new SubtypePredicate(SubType.byDescription(creatureType))); for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controller.getId(), game)) { diff --git a/Mage.Sets/src/mage/cards/k/KindredSummons.java b/Mage.Sets/src/mage/cards/k/KindredSummons.java index a34f76dc977..5adea872223 100644 --- a/Mage.Sets/src/mage/cards/k/KindredSummons.java +++ b/Mage.Sets/src/mage/cards/k/KindredSummons.java @@ -34,9 +34,9 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseCreatureTypeEffect; +import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Card; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.CardType; @@ -48,6 +48,7 @@ import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.players.Player; + /** * * @author Saga @@ -55,10 +56,10 @@ import mage.players.Player; public class KindredSummons extends CardImpl { public KindredSummons(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{5}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{5}{G}{G}"); - // Choose a creature type. Reveal cards from the top of your library until you reveal X creature cards of the chosen type, - // where X is the number of creatures you control of that type. Put those cards onto the battlefield, + // Choose a creature type. Reveal cards from the top of your library until you reveal X creature cards of the chosen type, + // where X is the number of creatures you control of that type. Put those cards onto the battlefield, // then shuffle the rest of the revealed cards into your library. this.getSpellAbility().addEffect(new ChooseCreatureTypeEffect(Outcome.PutCreatureInPlay)); this.getSpellAbility().addEffect(new KindredSummonsEffect()); @@ -78,8 +79,8 @@ class KindredSummonsEffect extends OneShotEffect { public KindredSummonsEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "Reveal cards from the top of your library until you reveal X creature cards of the chosen type, " + - "where X is the number of creatures you control of that type. Put those cards onto the battlefield, " + this.staticText = "Reveal cards from the top of your library until you reveal X creature cards of the chosen type, " + + "where X is the number of creatures you control of that type. Put those cards onto the battlefield, " + "then shuffle the rest of the revealed cards into your library"; } @@ -97,7 +98,11 @@ class KindredSummonsEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { - String creatureType = game.getState().getValue(sourceObject.getId() + "_type").toString(); + Object object = game.getState().getValue(sourceObject.getId() + "_type"); + if (object == null) { + return false; + } + String creatureType = object.toString(); FilterControlledCreaturePermanent filterPermanent = new FilterControlledCreaturePermanent("creature you control of the chosen type"); filterPermanent.add(new SubtypePredicate(SubType.byDescription(creatureType))); int numberOfCards = game.getBattlefield().countAll(filterPermanent, source.getControllerId(), game); diff --git a/Mage.Sets/src/mage/cards/m/MarketFestival.java b/Mage.Sets/src/mage/cards/m/MarketFestival.java index c8f0680272a..930a9adb431 100644 --- a/Mage.Sets/src/mage/cards/m/MarketFestival.java +++ b/Mage.Sets/src/mage/cards/m/MarketFestival.java @@ -39,8 +39,8 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.choices.ChoiceColor; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; @@ -57,10 +57,9 @@ import mage.target.common.TargetLandPermanent; public class MarketFestival extends CardImpl { public MarketFestival(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); this.subtype.add(SubType.AURA); - // Enchant land TargetPermanent auraTarget = new TargetLandPermanent(); this.getSpellAbility().addTarget(auraTarget); @@ -108,14 +107,12 @@ class MarketFestivalTriggeredAbility extends TriggeredManaAbility { return enchantment != null && event.getSourceId().equals(enchantment.getAttachedTo()); } - @Override public String getRule() { return "Whenever enchanted land is tapped for mana, its controller adds two mana in any combination of colors to his or her mana pool (in addition to the mana the land produces)."; } } - class MarketFestivalManaEffect extends ManaEffect { public MarketFestivalManaEffect() { @@ -152,7 +149,9 @@ class MarketFestivalManaEffect extends ManaEffect { return false; } } - + if (choiceColor.getChoice() == null) { // Possible after reconnect? + return false; + } choiceColor.increaseMana(mana); } checkToFirePossibleEvents(mana, game, source); diff --git a/Mage.Sets/src/mage/cards/m/MetzaliTowerOfTriumph.java b/Mage.Sets/src/mage/cards/m/MetzaliTowerOfTriumph.java index b22efae84d9..b060d0513c6 100644 --- a/Mage.Sets/src/mage/cards/m/MetzaliTowerOfTriumph.java +++ b/Mage.Sets/src/mage/cards/m/MetzaliTowerOfTriumph.java @@ -126,9 +126,11 @@ class MetzaliTowerOfTriumphEffect extends OneShotEffect { available.add(permanent); } } - Permanent permanent = available.get(RandomUtil.nextInt(available.size())); - if (permanent != null) { - permanent.destroy(source.getSourceId(), game, false); + if (!available.isEmpty()) { + Permanent permanent = available.get(RandomUtil.nextInt(available.size())); + if (permanent != null) { + permanent.destroy(source.getSourceId(), game, false); + } } return true; } diff --git a/Mage.Sets/src/mage/cards/n/NewBlood.java b/Mage.Sets/src/mage/cards/n/NewBlood.java index a6f3905c73e..e65704f83e2 100644 --- a/Mage.Sets/src/mage/cards/n/NewBlood.java +++ b/Mage.Sets/src/mage/cards/n/NewBlood.java @@ -27,6 +27,7 @@ */ package mage.cards.n; +import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; @@ -52,10 +53,6 @@ import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; -import java.util.LinkedHashSet; -import java.util.UUID; -import java.util.stream.Collectors; - /** * * @author LevelX2 @@ -124,7 +121,7 @@ class NewBloodEffect extends OneShotEffect { class ChangeCreatureTypeTargetEffect extends ContinuousEffectImpl { private SubType fromSubType; - private SubType toSubType; + private final SubType toSubType; public ChangeCreatureTypeTargetEffect(SubType fromSubType, SubType toSubType, Duration duration) { super(duration, Layer.TextChangingEffects_3, SubLayer.NA, Outcome.Benefit); @@ -153,6 +150,7 @@ class ChangeCreatureTypeTargetEffect extends ContinuousEffectImpl { } } if (typeChoice.getChoice() == null) { + discard(); return; } fromSubType = SubType.byDescription(typeChoice.getChoice()); diff --git a/Mage.Sets/src/mage/cards/p/ProfaneProcession.java b/Mage.Sets/src/mage/cards/p/ProfaneProcession.java index be2b250fcf9..bafe4c068da 100644 --- a/Mage.Sets/src/mage/cards/p/ProfaneProcession.java +++ b/Mage.Sets/src/mage/cards/p/ProfaneProcession.java @@ -105,7 +105,7 @@ class ProfaneProcessionEffect extends OneShotEffect { new ExileTargetEffect(exileId, sourceObject.getIdName()).setTargetPointer(targetPointer).apply(game, source); game.applyEffects(); ExileZone exileZone = game.getExile().getExileZone(exileId); - if (exileZone.size() > 2) { + if (exileZone != null && exileZone.size() > 2) { new TransformSourceEffect(true).apply(game, source); } return true; diff --git a/Mage/src/main/java/mage/abilities/common/CreatureEntersBattlefieldTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/CreatureEntersBattlefieldTriggeredAbility.java index 3f9f31d2bfd..85b39c3a7d2 100644 --- a/Mage/src/main/java/mage/abilities/common/CreatureEntersBattlefieldTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/CreatureEntersBattlefieldTriggeredAbility.java @@ -27,11 +27,12 @@ */ package mage.abilities.common; -import mage.constants.Zone; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; +import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; @@ -51,7 +52,7 @@ public class CreatureEntersBattlefieldTriggeredAbility extends TriggeredAbilityI /** * optional = false
* opponentController = false - * + * * @param effect */ public CreatureEntersBattlefieldTriggeredAbility(Effect effect) { @@ -60,7 +61,7 @@ public class CreatureEntersBattlefieldTriggeredAbility extends TriggeredAbilityI /** * opponentController = false - * + * * @param effect * @param optional */ @@ -69,7 +70,7 @@ public class CreatureEntersBattlefieldTriggeredAbility extends TriggeredAbilityI } /** - * + * * @param effect * @param optional * @param opponentController @@ -78,7 +79,7 @@ public class CreatureEntersBattlefieldTriggeredAbility extends TriggeredAbilityI this(Zone.BATTLEFIELD, effect, optional, opponentController); } - + /** * @param zone * @param effect @@ -104,7 +105,6 @@ public class CreatureEntersBattlefieldTriggeredAbility extends TriggeredAbilityI } } - public CreatureEntersBattlefieldTriggeredAbility(CreatureEntersBattlefieldTriggeredAbility ability) { super(ability); this.opponentController = ability.opponentController; @@ -118,7 +118,7 @@ public class CreatureEntersBattlefieldTriggeredAbility extends TriggeredAbilityI @Override public boolean checkTrigger(GameEvent event, Game game) { - Permanent permanent = game.getPermanent(event.getTargetId()); + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (filter.match(permanent, sourceId, controllerId, game) && (permanent.getControllerId().equals(this.controllerId) ^ opponentController)) { if (!this.getTargets().isEmpty()) { @@ -137,7 +137,7 @@ public class CreatureEntersBattlefieldTriggeredAbility extends TriggeredAbilityI @Override public String getRule() { - return "Whenever a " + filter.getMessage() +" enters the battlefield under " + return "Whenever a " + filter.getMessage() + " enters the battlefield under " + (opponentController ? "an opponent's control, " : "your control, ") + super.getRule(); } diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index b97a5af04d8..37111ccd779 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -60,12 +60,15 @@ import mage.target.TargetCard; import mage.util.CardUtil; import mage.util.GameLog; import mage.util.ThreadLocalStringBuilder; +import org.apache.log4j.Logger; /** * @author BetaSteward_at_googlemail.com */ public abstract class PermanentImpl extends CardImpl implements Permanent { + private static final Logger logger = Logger.getLogger(PermanentImpl.class); + public class MarkedDamageInfo { public MarkedDamageInfo(Counter counter, MageObject sourceObject) { @@ -699,6 +702,10 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } } } + if (getSpellAbility() == null) { + logger.info("FATAL : no spell ability for attach to permanent: " + getName()); + return; + } if (!getSpellAbility().getTargets().isEmpty() && (getSpellAbility().getTargets().get(0) instanceof TargetCard)) { Card attachedToCard = game.getCard(this.getAttachedTo()); if (attachedToCard != null) {