Fix NullPointerException when a random discard effect is applied to a player with empty hand.

This commit is contained in:
LoneFox 2015-06-11 14:23:55 +03:00
parent 81108be346
commit 3d59c57b0e

View file

@ -216,14 +216,14 @@ public abstract class PlayerImpl implements Player, Serializable {
protected boolean topCardRevealed = false;
// 800.4i When a player leaves the game, any continuous effects with durations that last until that player's next turn
// or until a specific point in that turn will last until that turn would have begun.
// or until a specific point in that turn will last until that turn would have begun.
// They neither expire immediately nor last indefinitely.
protected boolean reachedNextTurnAfterLeaving = false;
// indicates that the spell with the set sourceId can be cast with an alternate mana costs (can also be no mana costs)
protected UUID castSourceIdWithAlternateMana;
protected ManaCosts castSourceIdManaCosts;
// indicates that the player is in mana payment phase
protected boolean payManaMode = false;
@ -369,7 +369,7 @@ public abstract class PlayerImpl implements Player, Serializable {
this.canPaySacrificeCost = player.canPaySacrificeCost();
this.loseByZeroOrLessLife = player.canLoseByZeroOrLessLife();
this.canPlayCardsFromGraveyard = player.canPlayCardsFromGraveyard();
this.alternativeSourceCosts.addAll(player.getAlternativeSourceCosts());
this.alternativeSourceCosts.addAll(player.getAlternativeSourceCosts());
this.topCardRevealed = player.isTopCardRevealed();
this.playersUnderYourControl.clear();
@ -444,7 +444,7 @@ public abstract class PlayerImpl implements Player, Serializable {
this.payManaMode = false;
this.setLife(game.getLife(), game);
this.setReachedNextTurnAfterLeaving(false);
this.castSourceIdWithAlternateMana = null;
this.castSourceIdManaCosts = null;
}
@ -575,7 +575,7 @@ public abstract class PlayerImpl implements Player, Serializable {
/**
* returns true if the player has the control itself - false if the player is controlled by another player
* @return
* @return
*/
@Override
public boolean isGameUnderControl() {
@ -704,8 +704,10 @@ public abstract class PlayerImpl implements Player, Serializable {
if (random) {
for (int i = 0; i < amount; i++) {
Card card = this.getHand().getRandom(game);
discardedCards.add(card);
discard(card, source, game);
if(card != null) {
discardedCards.add(card);
discard(card, source, game);
}
}
} else {
TargetDiscard target = new TargetDiscard(amount, amount, new FilterCard(CardUtil.numberToText(amount, "a") + " card" + (amount > 1 ? "s" : "")), playerId);
@ -802,7 +804,7 @@ public abstract class PlayerImpl implements Player, Serializable {
attachedToPlayer.removeAttachment(permanent, game);
}
}
}
if (permanent.getPairedCard() != null) {
Permanent pairedCard = game.getPermanent(permanent.getPairedCard());
@ -876,7 +878,7 @@ public abstract class PlayerImpl implements Player, Serializable {
while (isInGame() && cards.size() > 1) {
this.choose(Outcome.Neutral, cards, target, game);
UUID targetObjectId = target.getFirstTarget();
cards.remove(targetObjectId);
cards.remove(targetObjectId);
moveObjectToLibrary(targetObjectId, source.getSourceId(), game, true, false);
target.clearChosen();
}
@ -917,7 +919,7 @@ public abstract class PlayerImpl implements Player, Serializable {
return castSourceIdManaCosts;
}
@Override
public boolean isInPayManaMode() {
return payManaMode;
@ -947,7 +949,7 @@ public abstract class PlayerImpl implements Player, Serializable {
spellAbility.getManaCosts().add(alternateCosts.copy());
spellAbility.getManaCostsToPay().clear();
spellAbility.getManaCostsToPay().add(alternateCosts.copy());
}
}
}
setCastSourceIdWithAlternateMana(null, null);
if (spell.activate(game, noMana)) {
@ -1528,7 +1530,7 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public String getLogName() {
return GameLog.getColoredPlayerName(name);
return GameLog.getColoredPlayerName(name);
}
@Override
@ -1669,11 +1671,11 @@ public abstract class PlayerImpl implements Player, Serializable {
sourceControllerId = ((Spell) source).getControllerId();
} else if (source instanceof Card) {
sourceAbilities = ((Card) source).getAbilities(game);
sourceControllerId = ((Card) source).getOwnerId();
sourceControllerId = ((Card) source).getOwnerId();
} else if (source instanceof CommandObject){
sourceControllerId = ((CommandObject) source).getControllerId();
sourceAbilities = ((CommandObject) source).getAbilities();
}
}
} else {
sourceAbilities = ((Permanent) source).getAbilities(game);
sourceControllerId = ((Permanent) source).getControllerId();
@ -2426,7 +2428,7 @@ public abstract class PlayerImpl implements Player, Serializable {
if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NON_HAND_ZONE, this.getId(), game)) {
for (Ability ability : card.getAbilities()) {
if (ability.getZone().match(Zone.HAND)) {
ability.setControllerId(this.getId()); // controller must be set for case owner != caster
ability.setControllerId(this.getId()); // controller must be set for case owner != caster
if (ability instanceof ActivatedAbility) {
if (((ActivatedAbility) ability).canActivate(playerId, game)) {
playable.add(ability);
@ -2537,7 +2539,7 @@ public abstract class PlayerImpl implements Player, Serializable {
* @return
*/
private boolean shouldSkipGettingPlayable(Game game) {
if (game.getStep() == null) { // happens at the start of the game
if (game.getStep() == null) { // happens at the start of the game
return true;
}
for (Entry<PhaseStep, Step.StepPart> phaseStep : silentPhaseSteps.entrySet()) {
@ -2841,16 +2843,16 @@ public abstract class PlayerImpl implements Player, Serializable {
cardList.addAll(cards.getCards(game));
return moveCards(cardList, fromZone, toZone, source, game);
}
@Override
public boolean moveCards(Card card, Zone fromZone, Zone toZone, Ability source, Game game) {
ArrayList<Card> cardList = new ArrayList<>();
if (card != null) {
cardList.add(card);
}
return moveCards(cardList, fromZone, toZone, source, game);
return moveCards(cardList, fromZone, toZone, source, game);
}
@Override
public boolean moveCards(List<Card> cards, Zone fromZone, Zone toZone, Ability source, Game game) {
if (cards.isEmpty()) {
@ -2858,13 +2860,13 @@ public abstract class PlayerImpl implements Player, Serializable {
}
game.fireEvent(new ZoneChangeGroupEvent(cards, source == null ? null : source.getSourceId(), this.getId(), fromZone, toZone));
switch(toZone) {
case EXILED:
case EXILED:
boolean result = false;
for(Card card: cards) {
result |= moveCardToExileWithInfo(card, null, "", source == null ? null : source.getSourceId(), game, fromZone, true);
}
return result;
case GRAVEYARD:
return result;
case GRAVEYARD:
return moveCardsToGraveyardWithInfo(cards, source, game, fromZone);
case HAND:
result = false;
@ -2874,9 +2876,9 @@ public abstract class PlayerImpl implements Player, Serializable {
return result;
default:
throw new UnsupportedOperationException("to Zone not supported yet");
}
}
}
@Override
public boolean moveCardToHandWithInfo(Card card, UUID sourceId, Game game, Zone fromZone) {
return this.moveCardToHandWithInfo(card, sourceId, game, fromZone, true);
@ -2898,7 +2900,7 @@ public abstract class PlayerImpl implements Player, Serializable {
default:
sb.append(fromZone != null ? new StringBuilder(" from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" ") : "");
break;
}
}
sb.append(card.getOwnerId().equals(this.getId()) ? "into his or her hand" : "into its owner's hand");
game.informPlayers(sb.toString());
}
@ -2906,10 +2908,10 @@ public abstract class PlayerImpl implements Player, Serializable {
}
return result;
}
@Override
public boolean moveCardsToGraveyardWithInfo(List<Card> allCards, Ability source, Game game, Zone fromZone) {
boolean result = true;
boolean result = true;
UUID sourceId = source == null ? null : source.getSourceId();
while (!allCards.isEmpty()) {
// identify cards from one owner
@ -2943,10 +2945,10 @@ public abstract class PlayerImpl implements Player, Serializable {
target.setRequired(true);
while (choosingPlayer.isInGame() && cards.size() > 1) {
choosingPlayer.chooseTarget(Outcome.Neutral, cards, target, source, game);
UUID targetObjectId = target.getFirstTarget();
UUID targetObjectId = target.getFirstTarget();
Card card = cards.get(targetObjectId, game);
cards.remove(targetObjectId);
if (card != null) {
cards.remove(targetObjectId);
if (card != null) {
result &= choosingPlayer.moveCardToGraveyardWithInfo(card, sourceId, game, fromZone);
}
target.clearChosen();
@ -2959,11 +2961,11 @@ public abstract class PlayerImpl implements Player, Serializable {
result &= choosingPlayer.moveCardToGraveyardWithInfo(card, sourceId, game, fromZone);
}
}
}
}
}
return result;
}
@Override
public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId, Game game, Zone fromZone) {
boolean result = false;
@ -3045,7 +3047,7 @@ public abstract class PlayerImpl implements Player, Serializable {
public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped) {
return this.putOntoBattlefieldWithInfo(card, game, fromZone, sourceId, tapped, false);
}
@Override
public boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped, boolean facedown) {
boolean result = false;