mirror of
https://github.com/correl/mage.git
synced 2024-12-25 03:00:15 +00:00
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:
parent
a38ec84581
commit
2685d9f8b4
10 changed files with 62 additions and 38 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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":
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 <i>(in addition to the mana the land produces)</i>.";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<br>
|
||||
* 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();
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue