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

This commit is contained in:
LevelX2 2018-01-11 06:12:27 +01:00
parent a38ec84581
commit 2685d9f8b4
10 changed files with 62 additions and 38 deletions

View file

@ -132,10 +132,12 @@ class BishopOfBindingExiledCardsPowerCount implements DynamicValue {
@Override @Override
public int calculate(Game game, Ability sourceAbility, Effect effect) { public int calculate(Game game, Ability sourceAbility, Effect effect) {
ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, sourceAbility.getSourceId(), sourceAbility.getSourceObjectZoneChangeCounter())); ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, sourceAbility.getSourceId(), sourceAbility.getSourceObjectZoneChangeCounter()));
if (exileZone != null) {
Card exiledCard = exileZone.getRandom(game); Card exiledCard = exileZone.getRandom(game);
if (exiledCard != null) { if (exiledCard != null) {
return exiledCard.getPower().getValue(); return exiledCard.getPower().getValue();
} }
}
return 0; return 0;
} }

View file

@ -182,7 +182,14 @@ class ChromeMoxManaEffect extends ManaEffect {
if (choice.getChoices().size() == 1) { if (choice.getChoices().size() == 1) {
choice.setChoice(choice.getChoices().iterator().next()); choice.setChoice(choice.getChoices().iterator().next());
} else { } 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()) { switch (choice.getChoice()) {
case "Black": case "Black":

View file

@ -34,10 +34,10 @@ import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbil
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ChooseCreatureTypeEffect; 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.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.abilities.effects.common.CreateTokenCopyTargetEffect;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
@ -95,7 +95,11 @@ class KindredChargeEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source.getSourceId()); MageObject sourceObject = game.getObject(source.getSourceId());
if (controller != null && sourceObject != null) { 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"); FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature you control of the chosen type");
filter.add(new SubtypePredicate(SubType.byDescription(creatureType))); filter.add(new SubtypePredicate(SubType.byDescription(creatureType)));
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controller.getId(), game)) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controller.getId(), game)) {

View file

@ -34,9 +34,9 @@ import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.abilities.effects.common.ChooseCreatureTypeEffect;
import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.Card;
import mage.cards.Cards; import mage.cards.Cards;
import mage.cards.CardsImpl; import mage.cards.CardsImpl;
import mage.constants.CardType; import mage.constants.CardType;
@ -48,6 +48,7 @@ import mage.filter.common.FilterCreatureCard;
import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
/** /**
* *
* @author Saga * @author Saga
@ -55,7 +56,7 @@ import mage.players.Player;
public class KindredSummons extends CardImpl { public class KindredSummons extends CardImpl {
public KindredSummons(UUID ownerId, CardSetInfo setInfo) { 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, // 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, // where X is the number of creatures you control of that type. Put those cards onto the battlefield,
@ -78,8 +79,8 @@ class KindredSummonsEffect extends OneShotEffect {
public KindredSummonsEffect() { public KindredSummonsEffect() {
super(Outcome.PutCreatureInPlay); super(Outcome.PutCreatureInPlay);
this.staticText = "Reveal cards from the top of your library until you reveal X creature cards of the chosen type, " + 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, " + "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"; + "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()); Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game); MageObject sourceObject = source.getSourceObject(game);
if (controller != null && sourceObject != null) { 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"); FilterControlledCreaturePermanent filterPermanent = new FilterControlledCreaturePermanent("creature you control of the chosen type");
filterPermanent.add(new SubtypePredicate(SubType.byDescription(creatureType))); filterPermanent.add(new SubtypePredicate(SubType.byDescription(creatureType)));
int numberOfCards = game.getBattlefield().countAll(filterPermanent, source.getControllerId(), game); int numberOfCards = game.getBattlefield().countAll(filterPermanent, source.getControllerId(), game);

View file

@ -39,8 +39,8 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.choices.ChoiceColor; import mage.choices.ChoiceColor;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
@ -57,10 +57,9 @@ import mage.target.common.TargetLandPermanent;
public class MarketFestival extends CardImpl { public class MarketFestival extends CardImpl {
public MarketFestival(UUID ownerId, CardSetInfo setInfo) { 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); this.subtype.add(SubType.AURA);
// Enchant land // Enchant land
TargetPermanent auraTarget = new TargetLandPermanent(); TargetPermanent auraTarget = new TargetLandPermanent();
this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addTarget(auraTarget);
@ -108,14 +107,12 @@ class MarketFestivalTriggeredAbility extends TriggeredManaAbility {
return enchantment != null && event.getSourceId().equals(enchantment.getAttachedTo()); return enchantment != null && event.getSourceId().equals(enchantment.getAttachedTo());
} }
@Override @Override
public String getRule() { 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 <i>(in addition to the mana the land produces)</i>."; return "Whenever enchanted land is tapped for mana, its controller adds two mana in any combination of colors to his or her mana pool <i>(in addition to the mana the land produces)</i>.";
} }
} }
class MarketFestivalManaEffect extends ManaEffect { class MarketFestivalManaEffect extends ManaEffect {
public MarketFestivalManaEffect() { public MarketFestivalManaEffect() {
@ -152,7 +149,9 @@ class MarketFestivalManaEffect extends ManaEffect {
return false; return false;
} }
} }
if (choiceColor.getChoice() == null) { // Possible after reconnect?
return false;
}
choiceColor.increaseMana(mana); choiceColor.increaseMana(mana);
} }
checkToFirePossibleEvents(mana, game, source); checkToFirePossibleEvents(mana, game, source);

View file

@ -126,10 +126,12 @@ class MetzaliTowerOfTriumphEffect extends OneShotEffect {
available.add(permanent); available.add(permanent);
} }
} }
if (!available.isEmpty()) {
Permanent permanent = available.get(RandomUtil.nextInt(available.size())); Permanent permanent = available.get(RandomUtil.nextInt(available.size()));
if (permanent != null) { if (permanent != null) {
permanent.destroy(source.getSourceId(), game, false); permanent.destroy(source.getSourceId(), game, false);
} }
}
return true; return true;
} }
return false; return false;

View file

@ -27,6 +27,7 @@
*/ */
package mage.cards.n; package mage.cards.n;
import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.Mode; import mage.abilities.Mode;
@ -52,10 +53,6 @@ import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import java.util.LinkedHashSet;
import java.util.UUID;
import java.util.stream.Collectors;
/** /**
* *
* @author LevelX2 * @author LevelX2
@ -124,7 +121,7 @@ class NewBloodEffect extends OneShotEffect {
class ChangeCreatureTypeTargetEffect extends ContinuousEffectImpl { class ChangeCreatureTypeTargetEffect extends ContinuousEffectImpl {
private SubType fromSubType; private SubType fromSubType;
private SubType toSubType; private final SubType toSubType;
public ChangeCreatureTypeTargetEffect(SubType fromSubType, SubType toSubType, Duration duration) { public ChangeCreatureTypeTargetEffect(SubType fromSubType, SubType toSubType, Duration duration) {
super(duration, Layer.TextChangingEffects_3, SubLayer.NA, Outcome.Benefit); super(duration, Layer.TextChangingEffects_3, SubLayer.NA, Outcome.Benefit);
@ -153,6 +150,7 @@ class ChangeCreatureTypeTargetEffect extends ContinuousEffectImpl {
} }
} }
if (typeChoice.getChoice() == null) { if (typeChoice.getChoice() == null) {
discard();
return; return;
} }
fromSubType = SubType.byDescription(typeChoice.getChoice()); fromSubType = SubType.byDescription(typeChoice.getChoice());

View file

@ -105,7 +105,7 @@ class ProfaneProcessionEffect extends OneShotEffect {
new ExileTargetEffect(exileId, sourceObject.getIdName()).setTargetPointer(targetPointer).apply(game, source); new ExileTargetEffect(exileId, sourceObject.getIdName()).setTargetPointer(targetPointer).apply(game, source);
game.applyEffects(); game.applyEffects();
ExileZone exileZone = game.getExile().getExileZone(exileId); ExileZone exileZone = game.getExile().getExileZone(exileId);
if (exileZone.size() > 2) { if (exileZone != null && exileZone.size() > 2) {
new TransformSourceEffect(true).apply(game, source); new TransformSourceEffect(true).apply(game, source);
} }
return true; return true;

View file

@ -27,11 +27,12 @@
*/ */
package mage.abilities.common; package mage.abilities.common;
import mage.constants.Zone;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game; import mage.game.Game;
import mage.game.events.EntersTheBattlefieldEvent;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType; import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
@ -104,7 +105,6 @@ public class CreatureEntersBattlefieldTriggeredAbility extends TriggeredAbilityI
} }
} }
public CreatureEntersBattlefieldTriggeredAbility(CreatureEntersBattlefieldTriggeredAbility ability) { public CreatureEntersBattlefieldTriggeredAbility(CreatureEntersBattlefieldTriggeredAbility ability) {
super(ability); super(ability);
this.opponentController = ability.opponentController; this.opponentController = ability.opponentController;
@ -118,7 +118,7 @@ public class CreatureEntersBattlefieldTriggeredAbility extends TriggeredAbilityI
@Override @Override
public boolean checkTrigger(GameEvent event, Game game) { 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) if (filter.match(permanent, sourceId, controllerId, game)
&& (permanent.getControllerId().equals(this.controllerId) ^ opponentController)) { && (permanent.getControllerId().equals(this.controllerId) ^ opponentController)) {
if (!this.getTargets().isEmpty()) { if (!this.getTargets().isEmpty()) {
@ -137,7 +137,7 @@ public class CreatureEntersBattlefieldTriggeredAbility extends TriggeredAbilityI
@Override @Override
public String getRule() { 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, ") + (opponentController ? "an opponent's control, " : "your control, ")
+ super.getRule(); + super.getRule();
} }

View file

@ -60,12 +60,15 @@ import mage.target.TargetCard;
import mage.util.CardUtil; import mage.util.CardUtil;
import mage.util.GameLog; import mage.util.GameLog;
import mage.util.ThreadLocalStringBuilder; import mage.util.ThreadLocalStringBuilder;
import org.apache.log4j.Logger;
/** /**
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
public abstract class PermanentImpl extends CardImpl implements Permanent { public abstract class PermanentImpl extends CardImpl implements Permanent {
private static final Logger logger = Logger.getLogger(PermanentImpl.class);
public class MarkedDamageInfo { public class MarkedDamageInfo {
public MarkedDamageInfo(Counter counter, MageObject sourceObject) { 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)) { if (!getSpellAbility().getTargets().isEmpty() && (getSpellAbility().getTargets().get(0) instanceof TargetCard)) {
Card attachedToCard = game.getCard(this.getAttachedTo()); Card attachedToCard = game.getCard(this.getAttachedTo());
if (attachedToCard != null) { if (attachedToCard != null) {