mirror of
https://github.com/correl/mage.git
synced 2024-12-25 19:25:41 +00:00
Fix NullPointerException when a random discard effect is applied to a player with empty hand.
This commit is contained in:
parent
81108be346
commit
3d59c57b0e
1 changed files with 35 additions and 33 deletions
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue