Fixed NPE errors for some cards (#5471)

This commit is contained in:
Oleg Agafonov 2019-01-08 07:15:39 +04:00
parent d70743d4a5
commit 063be44523
12 changed files with 122 additions and 139 deletions

View file

@ -1,4 +1,3 @@
package mage.player.ai;
import mage.MageObject;
@ -25,7 +24,6 @@ import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class SimulatedPlayer2 extends ComputerPlayer {
@ -173,6 +171,7 @@ public class SimulatedPlayer2 extends ComputerPlayer {
// allActions.add(new SimulatedAction(sim, actions));
// }
// }
/**
* if suggested abilities exist, return only those from playables
*
@ -191,11 +190,13 @@ public class SimulatedPlayer2 extends ComputerPlayer {
List<Ability> filtered = new ArrayList<>();
for (Ability ability : playables) {
Card card = game.getCard(ability.getSourceId());
for (String s : suggested) {
if (s.equals(card.getName())) {
logger.debug("matched: " + s);
forced = true;
filtered.add(ability);
if (card != null) {
for (String s : suggested) {
if (s.equals(card.getName())) {
logger.debug("matched: " + s);
forced = true;
filtered.add(ability);
}
}
}
}
@ -216,26 +217,28 @@ public class SimulatedPlayer2 extends ComputerPlayer {
for (Ability option : options) {
if (!option.getTargets().isEmpty() && option.getTargets().get(0).getMaxNumberOfTargets() == 1) {
Card card = game.getCard(ability.getSourceId());
for (String s : suggested) {
String[] groups = s.split(";");
logger.trace("s=" + s + ";groups=" + groups.length);
if (groups.length == 2) {
if (groups[0].equals(card.getName()) && groups[1].startsWith("name=")) {
// extract target and compare to suggested
String targetName = groups[1].split("=")[1];
Player player = game.getPlayer(option.getFirstTarget());
if (player != null && targetName.equals(player.getName())) {
System.out.println("matched(option): " + s);
filtered.add(option);
return filtered;
} else {
Card target = game.getCard(option.getFirstTarget());
if (target != null && target.getName().equals(targetName)) {
if (card != null) {
for (String s : suggested) {
String[] groups = s.split(";");
logger.trace("s=" + s + ";groups=" + groups.length);
if (groups.length == 2) {
if (groups[0].equals(card.getName()) && groups[1].startsWith("name=")) {
// extract target and compare to suggested
String targetName = groups[1].split("=")[1];
Player player = game.getPlayer(option.getFirstTarget());
if (player != null && targetName.equals(player.getName())) {
System.out.println("matched(option): " + s);
filtered.add(option);
return filtered;
} else {
Card target = game.getCard(option.getFirstTarget());
if (target != null && target.getName().equals(targetName)) {
System.out.println("matched(option): " + s);
filtered.add(option);
return filtered;
}
System.out.println("not equal UUID for target, player=" + player);
}
System.out.println("not equal UUID for target, player=" + player);
}
}
}

View file

@ -1,19 +1,7 @@
package mage.server.util;
import java.io.File;
import java.lang.reflect.Constructor;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import mage.abilities.Ability;
import mage.cards.Card;
import mage.cards.Cards;
import mage.cards.repository.CardCriteria;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
@ -25,6 +13,16 @@ import mage.game.Game;
import mage.players.Player;
import mage.util.RandomUtil;
import java.io.File;
import java.lang.reflect.Constructor;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* @author JayDi85
*/
@ -111,6 +109,9 @@ public final class SystemUtil {
for (UUID cardID : cardsList) {
Card card = game.getCard(cardID);
if (card == null) {
continue;
}
// basic info (card + set)
String cardInfo = card.getName() + " - " + card.getExpansionSetCode();
@ -225,7 +226,7 @@ public final class SystemUtil {
* <br/>
* <b>Implementation note:</b><br/>
* 1. Read init.txt line by line<br/>
* 2. Parse line using for searching groups like: [group 1]
* 2. Parse line using for searching groups like: [group 1]
* 3. Parse line using the following format: line ::=
* <zone>:<nickname>:<card name>:<amount><br/>
* 4. If zone equals to 'hand', add card to player's library<br/>
@ -537,8 +538,8 @@ public final class SystemUtil {
/**
* Get a diff between two dates
*
* @param date1 the oldest date
* @param date2 the newest date
* @param date1 the oldest date
* @param date2 the newest date
* @param timeUnit the unit in which you want the diff
* @return the diff value, in the provided unit
*/

View file

@ -1,8 +1,5 @@
package mage.cards.s;
import java.util.LinkedList;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
@ -14,11 +11,7 @@ import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.constants.*;
import mage.filter.common.FilterCreatureCard;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
@ -30,8 +23,10 @@ import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCreaturePermanent;
import java.util.LinkedList;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public final class SistersOfStoneDeath extends CardImpl {
@ -39,7 +34,7 @@ public final class SistersOfStoneDeath extends CardImpl {
private UUID exileId = UUID.randomUUID();
public SistersOfStoneDeath(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}{B}{G}{G}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}{G}{G}");
this.addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.GORGON);
@ -100,7 +95,9 @@ class SistersOfStoneDeathEffect extends OneShotEffect {
LinkedList<UUID> cards = new LinkedList<>(exile);
for (UUID cardId : cards) {
Card card = game.getCard(cardId);
cardsInExile.add(card);
if (card != null) {
cardsInExile.add(card);
}
}
if (controller.choose(Outcome.PutCreatureInPlay, cardsInExile, target, game)) {
Card chosenCard = game.getCard(target.getFirstTarget());

View file

@ -1,22 +1,12 @@
package mage.cards.s;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.DiscardTargetCost;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.cards.SplitCard;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
@ -27,8 +17,12 @@ import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInHand;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class SphinxOfTheChimes extends CardImpl {
@ -91,7 +85,7 @@ class TargetTwoNonLandCardsWithSameNameInHand extends TargetCardInHand {
Set<UUID> newPossibleTargets = new HashSet<>();
Set<UUID> possibleTargets = new HashSet<>();
Player player = game.getPlayer(sourceControllerId);
if(player == null){
if (player == null) {
return newPossibleTargets;
}
for (Card card : player.getHand().getCards(filter, game)) {
@ -116,9 +110,11 @@ class TargetTwoNonLandCardsWithSameNameInHand extends TargetCardInHand {
for (UUID cardToCheck : cardsToCheck) {
FilterCard nameFilter = new FilterCard();
Card card = game.getCard(cardToCheck);
nameFilter.add(new NamePredicate(card.isSplitCard() ? ((SplitCard) card).getLeftHalfCard().getName() : card.getName()));
if (cardsToCheck.count(nameFilter, game) > 1) {
newPossibleTargets.add(cardToCheck);
if (card != null) {
nameFilter.add(new NamePredicate(card.isSplitCard() ? ((SplitCard) card).getLeftHalfCard().getName() : card.getName()));
if (cardsToCheck.count(nameFilter, game) > 1) {
newPossibleTargets.add(cardToCheck);
}
}
}
}
@ -129,7 +125,7 @@ class TargetTwoNonLandCardsWithSameNameInHand extends TargetCardInHand {
public boolean canChoose(UUID sourceControllerId, Game game) {
Cards cardsToCheck = new CardsImpl();
Player player = game.getPlayer(sourceControllerId);
if(player == null){
if (player == null) {
return false;
}
for (Card card : player.getHand().getCards(filter, game)) {
@ -153,16 +149,12 @@ class TargetTwoNonLandCardsWithSameNameInHand extends TargetCardInHand {
if (card != null) {
if (targets.size() == 1) {
Card card2 = game.getCard(targets.entrySet().iterator().next().getKey());
if (card2 != null && card2.getName().equals(card.getName())) {
return true;
}
return card2 != null && card2.getName().equals(card.getName());
} else {
FilterCard nameFilter = new FilterCard();
nameFilter.add(new NamePredicate(card.isSplitCard() ? ((SplitCard) card).getLeftHalfCard().getName() : card.getName()));
Player player = game.getPlayer(card.getOwnerId());
if (player != null && player.getHand().getCards(nameFilter, game).size() > 1) {
return true;
}
return player != null && player.getHand().getCards(nameFilter, game).size() > 1;
}
}
}

View file

@ -1,7 +1,5 @@
package mage.cards.s;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.BecomesTappedAttachedTriggeredAbility;
import mage.abilities.effects.Effect;
@ -24,8 +22,9 @@ import mage.target.TargetPermanent;
import mage.target.common.TargetLandPermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
*
* @author jeffwadsworth & L_J
*/
public final class SteamVines extends CardImpl {
@ -76,7 +75,6 @@ class SteamVinesEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent steamVines = game.getPermanentOrLKIBattlefield(source.getSourceId());
Card steamVinesCard = game.getCard(source.getSourceId());
if (steamVines != null) {
Permanent enchantedLand = game.getPermanentOrLKIBattlefield(steamVines.getAttachedTo());
Player controller = game.getPlayer(source.getControllerId());
@ -85,15 +83,15 @@ class SteamVinesEffect extends OneShotEffect {
Player landsController = game.getPlayer(enchantedLand.getControllerId());
if (game.getState().getZone(enchantedLand.getId()) == Zone.BATTLEFIELD) { // if 2 or more Steam Vines were on a land
enchantedLand.destroy(source.getId(), game, false);
if(landsController != null) {
if (landsController != null) {
landsController.damage(1, source.getSourceId(), game, false, true);
}
}
if (!game.getBattlefield().getAllActivePermanents(CardType.LAND).isEmpty()) { //lands are available on the battlefield
Target target = new TargetLandPermanent();
target.setNotTarget(true); //not a target, it is chosen
if (steamVinesCard != null
&& landsController != null) {
Card steamVinesCard = game.getCard(source.getSourceId());
if (steamVinesCard != null && landsController != null) {
if (landsController.choose(Outcome.DestroyPermanent, target, source.getId(), game)) {
if (target.getFirstTarget() != null) {
Permanent landChosen = game.getPermanent(target.getFirstTarget());

View file

@ -1,11 +1,11 @@
package mage.cards.s;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.*;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.SplitCard;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SuperType;
@ -21,8 +21,10 @@ import mage.target.common.TargetCardInGraveyard;
import mage.target.common.TargetCardInHand;
import mage.target.common.TargetCardInLibrary;
import java.util.List;
import java.util.UUID;
/**
*
* @author North
*/
public final class SurgicalExtraction extends CardImpl {
@ -71,12 +73,12 @@ class SurgicalExtractionEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Card chosenCard = game.getCard(source.getFirstTarget());
Player controller = game.getPlayer(source.getControllerId());
// 6/1/2011 "Any number of cards" means just that. If you wish, you can choose to
// leave some or all of the cards with the same name as the targeted card,
// including that card, in the zone they're in.
Card chosenCard = game.getCard(source.getFirstTarget());
Player controller = game.getPlayer(source.getControllerId());
if (chosenCard != null && controller != null) {
Player owner = game.getPlayer(chosenCard.getOwnerId());
if (owner != null) {

View file

@ -1,7 +1,5 @@
package mage.cards.t;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
@ -17,14 +15,15 @@ import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class TeferiMageOfZhalfir extends CardImpl {
public TeferiMageOfZhalfir(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{U}{U}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}{U}");
addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.WIZARD);
@ -76,14 +75,14 @@ class TeferiMageOfZhalfirAddFlashEffect extends ContinuousEffectImpl {
// in graveyard
for (UUID cardId : controller.getGraveyard()) {
Card card = game.getCard(cardId);
if (card.isCreature()) {
if (card != null && card.isCreature()) {
game.getState().addOtherAbility(card, FlashAbility.getInstance());
}
}
// on Hand
for (UUID cardId : controller.getHand()) {
Card card = game.getCard(cardId);
if (card.isCreature()) {
if (card != null && card.isCreature()) {
game.getState().addOtherAbility(card, FlashAbility.getInstance());
}
}
@ -103,7 +102,7 @@ class TeferiMageOfZhalfirAddFlashEffect extends ContinuousEffectImpl {
for (UUID commanderId : controller.getCommandersIds()) {
if (game.getState().getZone(commanderId) == Zone.COMMAND) {
Card card = game.getCard(commanderId);
if (card.isCreature()) {
if (card != null && card.isCreature()) {
game.getState().addOtherAbility(card, FlashAbility.getInstance());
}
}

View file

@ -1,7 +1,5 @@
package mage.cards.t;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
@ -18,12 +16,7 @@ import mage.abilities.keyword.EnchantAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
@ -34,8 +27,9 @@ import mage.players.Player;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public final class TravelingPlague extends CardImpl {
@ -130,10 +124,10 @@ class TravelingPlagueEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Card travelingPlague = game.getCard(source.getSourceId());
Permanent enchantedCreature = (Permanent) game.getState().getValue("travelingPlague" + source.getSourceId());
if (enchantedCreature != null) {
Player controllerOfEnchantedCreature = game.getPlayer(enchantedCreature.getControllerId());
Card travelingPlague = game.getCard(source.getSourceId());
if (travelingPlague != null
&& game.getState().getZone(travelingPlague.getId()) == Zone.GRAVEYARD // aura must come from the graveyard
&& controllerOfEnchantedCreature != null) {

View file

@ -1,7 +1,5 @@
package mage.cards.t;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
@ -11,25 +9,21 @@ import mage.abilities.keyword.TrampleAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubLayer;
import mage.constants.Zone;
import mage.constants.*;
import mage.filter.common.FilterLandCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class TrenchGorger extends CardImpl {
public TrenchGorger(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{6}{U}{U}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{U}{U}");
this.subtype.add(SubType.LEVIATHAN);
this.power = new MageInt(6);
@ -77,8 +71,10 @@ class TrenchGorgerEffect extends OneShotEffect {
int count = 0;
for (UUID cardId : target.getTargets()) {
Card card = game.getCard(cardId);
controller.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, Zone.LIBRARY, true);
count++;
if (card != null) {
controller.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, Zone.LIBRARY, true);
count++;
}
}
controller.shuffleLibrary(source, game);
game.addEffect(new SetPowerToughnessSourceEffect(count, count, Duration.EndOfGame, SubLayer.SetPT_7b), source);

View file

@ -1,6 +1,5 @@
package mage.cards.v;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
@ -25,8 +24,9 @@ import mage.players.Player;
import mage.target.TargetPlayer;
import mage.target.common.TargetCardInHand;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public final class VolrathsDungeon extends CardImpl {
@ -65,7 +65,7 @@ class PayLifeActivePlayerCost extends CostImpl {
public PayLifeActivePlayerCost(int amount) {
this.amount = new StaticValue(amount);
this.text = "Pay " + Integer.toString(amount) + " life";
this.text = "Pay " + amount + " life";
}
public PayLifeActivePlayerCost(DynamicValue amount, String text) {
@ -89,9 +89,9 @@ class PayLifeActivePlayerCost extends CostImpl {
int lifeToPayAmount = amount.calculate(game, ability, null);
Player activatingPlayer = game.getPlayer(game.getActivePlayerId());
if (activatingPlayer != null
&& activatingPlayer.chooseUse(Outcome.LoseLife, "Do you wish to pay "+ lifeToPayAmount +" life?", ability, game)) {
&& activatingPlayer.chooseUse(Outcome.LoseLife, "Do you wish to pay " + lifeToPayAmount + " life?", ability, game)) {
Player player = game.getPlayer(game.getActivePlayerId());
if(player != null) {
if (player != null) {
this.paid = player.loseLife(lifeToPayAmount, game, false) == lifeToPayAmount;
}
}
@ -127,7 +127,7 @@ class VolrathsDungeonEffect extends OneShotEffect {
TargetCardInHand target = new TargetCardInHand();
if (targetedPlayer.choose(Outcome.Detriment, targetedPlayer.getHand(), target, game)) {
Card card = game.getCard(target.getFirstTarget());
return targetedPlayer.putCardOnTopXOfLibrary(card, game, source, 0);
return card != null && targetedPlayer.putCardOnTopXOfLibrary(card, game, source, 0);
}
}
return false;

View file

@ -1,7 +1,5 @@
package mage.cards.y;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.LegendarySpellAbility;
import mage.abilities.effects.OneShotEffect;
@ -9,7 +7,10 @@ import mage.abilities.effects.common.ExileSpellEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent;
import mage.filter.common.FilterPermanentCard;
import mage.filter.predicate.Predicates;
@ -20,6 +21,8 @@ import mage.players.Player;
import mage.target.common.TargetCardInGraveyard;
import mage.target.common.TargetCreatureOrPlaneswalker;
import java.util.UUID;
/**
* @author JRHerlehy Created on 4/8/18.
*/
@ -78,7 +81,6 @@ class YawgmothsVileOfferingEffect extends OneShotEffect {
}
Card returnCard = game.getCard(source.getTargets().getFirstTarget());
if (returnCard != null) {
controller.moveCards(returnCard, Zone.BATTLEFIELD, source, game);
}

View file

@ -1,8 +1,5 @@
package mage.abilities;
import java.util.Optional;
import java.util.UUID;
import mage.MageObject;
import mage.MageObjectReference;
import mage.abilities.costs.Cost;
@ -12,17 +9,15 @@ import mage.abilities.costs.mana.VariableManaCost;
import mage.abilities.keyword.FlashAbility;
import mage.cards.Card;
import mage.cards.SplitCard;
import mage.constants.AbilityType;
import mage.constants.AsThoughEffectType;
import mage.constants.SpellAbilityCastMode;
import mage.constants.SpellAbilityType;
import mage.constants.TimingRule;
import mage.constants.Zone;
import mage.constants.*;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.Spell;
import mage.players.Player;
import java.util.Optional;
import java.util.UUID;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -224,12 +219,16 @@ public class SpellAbility extends ActivatedAbilityImpl {
if (event.getType() != GameEvent.EventType.CAST_SPELL) {
return null;
}
Card card = game.getCard(event.getSourceId());
Optional<Ability> ability = card.getAbilities(game).get(event.getTargetId());
if (ability.isPresent() && ability.get() instanceof SpellAbility) {
return (SpellAbility) ability.get();
if (card != null) {
Optional<Ability> ability = card.getAbilities(game).get(event.getTargetId());
if (ability.isPresent() && ability.get() instanceof SpellAbility) {
return (SpellAbility) ability.get();
}
return card.getSpellAbility();
}
return card.getSpellAbility();
return null;
}
public void setId(UUID idToUse) {