From 2460408da8bfc5e11a138c9b411e6f1809816cb6 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Thu, 26 Dec 2019 07:28:37 +0400 Subject: [PATCH] * Until your next turn effects - fixed that continuous effects of lost/leaved players can be discarded by combat or some cards before next turn starts; --- Mage.Sets/src/mage/cards/a/Aetherspouts.java | 20 ++++--- Mage.Sets/src/mage/cards/e/EyeOfDoom.java | 19 +++---- .../src/mage/cards/i/IllicitAuction.java | 38 +++++++------ Mage.Sets/src/mage/cards/k/Kindle.java | 9 ++-- Mage.Sets/src/mage/cards/t/Tariff.java | 28 +++++----- .../mage/cards/t/TemptWithReflections.java | 11 ++-- .../src/mage/cards/t/ThievesAuction.java | 15 ++---- .../EndOfTurnMultiOpponentsTest.java | 54 +++++++++++++++++++ .../effects/ContinuousEffectImpl.java | 2 +- .../abilities/effects/common/ClashEffect.java | 8 +-- Mage/src/main/java/mage/game/GameImpl.java | 7 ++- .../main/java/mage/game/combat/Combat.java | 2 +- .../main/java/mage/players/PlayerImpl.java | 4 +- .../main/java/mage/players/PlayerList.java | 23 ++++---- 14 files changed, 147 insertions(+), 93 deletions(-) diff --git a/Mage.Sets/src/mage/cards/a/Aetherspouts.java b/Mage.Sets/src/mage/cards/a/Aetherspouts.java index 4c565abaad6..20c3cbd87e6 100644 --- a/Mage.Sets/src/mage/cards/a/Aetherspouts.java +++ b/Mage.Sets/src/mage/cards/a/Aetherspouts.java @@ -1,4 +1,3 @@ - package mage.cards.a; import mage.abilities.Ability; @@ -21,13 +20,12 @@ import java.util.List; import java.util.UUID; /** - * * @author LevelX2 */ public final class Aetherspouts extends CardImpl { public Aetherspouts(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}{U}"); // For each attacking creature, its owner puts it on the top or bottom of their library. @@ -73,14 +71,14 @@ class AetherspoutsEffect extends OneShotEffect { game.getPlayerList(); Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - PlayerList playerList = game.getPlayerList(); + PlayerList playerList = game.getPlayerList().copy(); playerList.setCurrent(game.getActivePlayerId()); Player player = game.getPlayer(game.getActivePlayerId()); Player activePlayer = player; do { List permanentsToTop = new ArrayList<>(); List permanentsToBottom = new ArrayList<>(); - for (Permanent permanent:game.getState().getBattlefield().getActivePermanents(new FilterAttackingCreature(), player.getId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getState().getBattlefield().getActivePermanents(new FilterAttackingCreature(), player.getId(), source.getSourceId(), game)) { if (permanent.isOwnedBy(player.getId())) { if (player.chooseUse(outcome, "Put " + permanent.getLogName() + " to the top? (else it goes to bottom)", source, game)) { permanentsToTop.add(permanent); @@ -94,7 +92,7 @@ class AetherspoutsEffect extends OneShotEffect { // cards to top Cards cards = new CardsImpl(); List toLibrary = new ArrayList<>(); - for (Permanent permanent: permanentsToTop) { + for (Permanent permanent : permanentsToTop) { if (permanent instanceof PermanentToken) { toLibrary.add(permanent); } else { @@ -128,13 +126,13 @@ class AetherspoutsEffect extends OneShotEffect { } } // move all permanents to lib at the same time - for(Permanent permanent: toLibrary) { + for (Permanent permanent : toLibrary) { player.moveCardToLibraryWithInfo(permanent, source.getSourceId(), game, Zone.BATTLEFIELD, true, false); } // cards to bottom cards.clear(); toLibrary.clear(); - for (Permanent permanent: permanentsToBottom) { + for (Permanent permanent : permanentsToBottom) { if (permanent instanceof PermanentToken) { toLibrary.add(permanent); } else { @@ -161,15 +159,15 @@ class AetherspoutsEffect extends OneShotEffect { if (cards.size() == 1) { Card card = cards.get(cards.iterator().next(), game); Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) { + if (permanent != null) { toLibrary.add(permanent); } } // move all permanents to lib at the same time - for(Permanent permanent: toLibrary) { + for (Permanent permanent : toLibrary) { player.moveCardToLibraryWithInfo(permanent, source.getSourceId(), game, Zone.BATTLEFIELD, false, false); } - player = playerList.getNext(game); + player = playerList.getNext(game, false); } while (player != null && !player.getId().equals(game.getActivePlayerId()) && activePlayer.canRespond()); return true; } diff --git a/Mage.Sets/src/mage/cards/e/EyeOfDoom.java b/Mage.Sets/src/mage/cards/e/EyeOfDoom.java index da09bdeea46..2ccd1e35591 100644 --- a/Mage.Sets/src/mage/cards/e/EyeOfDoom.java +++ b/Mage.Sets/src/mage/cards/e/EyeOfDoom.java @@ -1,9 +1,5 @@ - package mage.cards.e; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -27,21 +23,26 @@ import mage.players.PlayerList; import mage.target.Target; import mage.target.common.TargetNonlandPermanent; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class EyeOfDoom extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("permanent with a doom counter on it"); + static { filter.add(new CounterPredicate(CounterType.DOOM)); } + public EyeOfDoom(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // When Eye of Doom enters the battlefield, each player chooses a nonland permanent and puts a doom counter on it. - this.addAbility(new EntersBattlefieldTriggeredAbility(new EyeOfDoomEffect(),false)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new EyeOfDoomEffect(), false)); // {2}, {tap}, Sacrifice Eye of Doom: Destroy each permanent with a doom counter on it. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyAllEffect(filter), new GenericManaCost(2)); @@ -93,10 +94,10 @@ class EyeOfDoomEffect extends OneShotEffect { game.informPlayers(player.getLogName() + " chooses " + permanent.getName()); } } - player = playerList.getNext(game); + player = playerList.getNext(game, false); } while (!player.getId().equals(game.getActivePlayerId())); - for (Permanent permanent: permanents) { + for (Permanent permanent : permanents) { permanent.addCounters(CounterType.DOOM.createInstance(), source, game); } diff --git a/Mage.Sets/src/mage/cards/i/IllicitAuction.java b/Mage.Sets/src/mage/cards/i/IllicitAuction.java index 08a4a981ebd..3791eac67b9 100644 --- a/Mage.Sets/src/mage/cards/i/IllicitAuction.java +++ b/Mage.Sets/src/mage/cards/i/IllicitAuction.java @@ -1,10 +1,6 @@ package mage.cards.i; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.keyword.DoubleStrikeAbility; @@ -21,8 +17,12 @@ import mage.players.Player; import mage.players.PlayerList; import mage.target.common.TargetCreaturePermanent; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + /** - * * @author Quercitron */ public final class IllicitAuction extends CardImpl { @@ -66,18 +66,17 @@ class IllicitAuctionEffect extends GainControlTargetEffect { public void init(Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); Permanent targetCreature = game.getPermanent(source.getFirstTarget()); - if (controller != null - && targetCreature != null) { - PlayerList playerList = game.getPlayerList().copy(); - playerList.setCurrent(game.getActivePlayerId()); - - Player winner = game.getPlayer(game.getActivePlayerId()); + if (controller != null && targetCreature != null) { + PlayerList playerList = game.getState().getPlayersInRange(controller.getId(), game); + Player winner = game.getPlayer(controller.getId()); int highBid = 0; game.informPlayers(winner.getLogName() + " has bet 0 lifes"); - Player currentPlayer = playerList.getNextInRange(controller, game); - while (!Objects.equals(currentPlayer, winner)) { + + Player currentPlayer = playerList.getNext(game, false); + while (currentPlayer != null && !Objects.equals(currentPlayer, winner)) { String text = winner.getLogName() + " has bet " + highBid + " life" + (highBid > 1 ? "s" : "") + ". Top the bid?"; - if (currentPlayer.chooseUse(Outcome.GainControl, text, source, game)) { + if (currentPlayer.canRespond() + && currentPlayer.chooseUse(Outcome.GainControl, text, source, game)) { int newBid = 0; if (!currentPlayer.isHuman()) {//AI will evaluate the creature and bid CreatureEvaluator eval = new CreatureEvaluator(); @@ -85,7 +84,9 @@ class IllicitAuctionEffect extends GainControlTargetEffect { int creatureValue = eval.evaluate(targetCreature, game); newBid = Math.max(creatureValue % 2, computerLife - 100); } else { - newBid = currentPlayer.getAmount(highBid + 1, Integer.MAX_VALUE, "Choose bid", game); + if (currentPlayer.canRespond()) { + newBid = currentPlayer.getAmount(highBid + 1, Integer.MAX_VALUE, "Choose bid", game); + } } if (newBid > highBid) { highBid = newBid; @@ -93,7 +94,12 @@ class IllicitAuctionEffect extends GainControlTargetEffect { game.informPlayers(currentPlayer.getLogName() + " bet " + newBid + " life" + (newBid > 1 ? "s" : "")); } } - currentPlayer = playerList.getNextInRange(controller, game); + currentPlayer = playerList.getNext(game, false); + + // stops loop on all players quite + if (game.getState().getPlayersInRange(controller.getId(), game).isEmpty()) { + break; + } } game.informPlayers(winner.getLogName() + " won the auction with a bid of " + highBid + " life" + (highBid > 1 ? "s" : "")); diff --git a/Mage.Sets/src/mage/cards/k/Kindle.java b/Mage.Sets/src/mage/cards/k/Kindle.java index 24a88be94e9..ac8d7a38cae 100644 --- a/Mage.Sets/src/mage/cards/k/Kindle.java +++ b/Mage.Sets/src/mage/cards/k/Kindle.java @@ -1,7 +1,5 @@ - package mage.cards.k; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; @@ -16,8 +14,9 @@ import mage.players.Player; import mage.players.PlayerList; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Kindle extends CardImpl { @@ -29,7 +28,7 @@ public final class Kindle extends CardImpl { } public Kindle(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); // Kindle deals X damage to any target, where X is 2 plus the number of cards named Kindle in all graveyards. @@ -64,7 +63,7 @@ class KindleCardsInAllGraveyardsCount implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { int amount = 0; - PlayerList playerList = game.getPlayerList(); + PlayerList playerList = game.getPlayerList().copy(); for (UUID playerUUID : playerList) { Player player = game.getPlayer(playerUUID); if (player != null) { diff --git a/Mage.Sets/src/mage/cards/t/Tariff.java b/Mage.Sets/src/mage/cards/t/Tariff.java index 318e83aba40..88ba621659b 100644 --- a/Mage.Sets/src/mage/cards/t/Tariff.java +++ b/Mage.Sets/src/mage/cards/t/Tariff.java @@ -1,9 +1,5 @@ - package mage.cards.t; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCosts; @@ -24,14 +20,17 @@ import mage.players.Player; import mage.players.PlayerList; import mage.target.TargetCard; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author Quercitron */ public final class Tariff extends CardImpl { public Tariff(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{W}"); // Each player sacrifices the creature they control with the highest converted mana cost unless they pay that creature's mana cost. If two or more creatures a player controls are tied for highest cost, that player chooses one. @@ -49,12 +48,12 @@ public final class Tariff extends CardImpl { } class TariffEffect extends OneShotEffect { - + public TariffEffect() { super(Outcome.DestroyPermanent); this.staticText = "Each player sacrifices the creature they control with the highest converted mana cost unless they pay that creature's mana cost. If two or more creatures a player controls are tied for highest cost, that player chooses one."; } - + public TariffEffect(final TariffEffect effect) { super(effect); } @@ -63,21 +62,20 @@ class TariffEffect extends OneShotEffect { public TariffEffect copy() { return new TariffEffect(this); } - + @Override public boolean apply(Game game, Ability source) { PlayerList playerList = game.getPlayerList().copy(); playerList.setCurrent(game.getActivePlayerId()); Player player = game.getPlayer(game.getActivePlayerId()); - do { processPlayer(game, source, player); - player = playerList.getNext(game); + player = playerList.getNext(game, false); } while (!player.getId().equals(game.getActivePlayerId())); - + return true; } - + private void processPlayer(Game game, Ability source, Player player) { MageObject sourceObject = game.getObject(source.getSourceId()); @@ -100,7 +98,7 @@ class TariffEffect extends OneShotEffect { creatureToPayFor.sacrifice(source.getSourceId(), game); } } - + private List getPermanentsWithTheHighestCMC(Game game, UUID playerId, FilterPermanent filter) { List permanents = game.getBattlefield().getAllActivePermanents(filter, playerId, game); int highestCMC = -1; @@ -135,5 +133,5 @@ class TariffEffect extends OneShotEffect { } return permanent; } - + } diff --git a/Mage.Sets/src/mage/cards/t/TemptWithReflections.java b/Mage.Sets/src/mage/cards/t/TemptWithReflections.java index 7c644e6bd03..8df6b4f317d 100644 --- a/Mage.Sets/src/mage/cards/t/TemptWithReflections.java +++ b/Mage.Sets/src/mage/cards/t/TemptWithReflections.java @@ -1,9 +1,5 @@ - package mage.cards.t; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -18,8 +14,11 @@ import mage.players.Player; import mage.players.PlayerList; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class TemptWithReflections extends CardImpl { @@ -81,7 +80,7 @@ class TemptWithReflectionsEffect extends OneShotEffect { } game.informPlayers((player.getLogName() + decision + permanent.getName())); } - player = playerList.getNext(game); + player = playerList.getNext(game, false); } while (!player.getId().equals(game.getActivePlayerId())); for (UUID playerId : playersSaidYes) { diff --git a/Mage.Sets/src/mage/cards/t/ThievesAuction.java b/Mage.Sets/src/mage/cards/t/ThievesAuction.java index b9b27cf7438..ed260a99d58 100644 --- a/Mage.Sets/src/mage/cards/t/ThievesAuction.java +++ b/Mage.Sets/src/mage/cards/t/ThievesAuction.java @@ -1,14 +1,8 @@ - package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -24,14 +18,15 @@ import mage.target.TargetCard; import mage.target.common.TargetCardInExile; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author emerald000 */ public final class ThievesAuction extends CardImpl { public ThievesAuction(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{R}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}{R}{R}"); // Exile all nontoken permanents. Starting with you, each player chooses one of the exiled cards and puts it onto the battlefield tapped under their control. Repeat this process until all cards exiled this way have been chosen. this.getSpellAbility().addEffect(new ThievesAuctionEffect()); @@ -98,7 +93,7 @@ class ThievesAuctionEffect extends OneShotEffect { } } // Repeat this process until all cards exiled this way have been chosen. - player = playerList.getNext(game); + player = playerList.getNext(game, false); } return true; } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/EndOfTurnMultiOpponentsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/EndOfTurnMultiOpponentsTest.java index b25fd55e46e..4a981b00069 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/EndOfTurnMultiOpponentsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/EndOfTurnMultiOpponentsTest.java @@ -153,4 +153,58 @@ public class EndOfTurnMultiOpponentsTest extends CardTestMultiPlayerBaseWithRang assertAllCommandsUsed(); } + // leaved players + // 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. + // They neither expire immediately nor last indefinitely. + @Test + public void test_UntilYourNextTurnMulti_Leaved() { + // Player order: A -> D -> C -> B + addCustomCardWithAbility("boost1", playerA, new SimpleStaticAbility(Zone.ALL, new BoostAllEffect(1, 1, Duration.UntilYourNextTurn))); + + EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 1, playerA, true, PhaseStep.END_TURN); + EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 2, playerD, true, PhaseStep.END_TURN); + EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 3, playerC, true, PhaseStep.END_TURN); + EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 4, playerB, true, PhaseStep.END_TURN); + EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 5, playerD, true, null); + + addCard(Zone.BATTLEFIELD, playerA, cardBear2, 1); + addCard(Zone.BATTLEFIELD, playerB, cardBear2, 1); + addCard(Zone.BATTLEFIELD, playerC, cardBear2, 1); + addCard(Zone.BATTLEFIELD, playerD, cardBear2, 1); + // + // When Eye of Doom enters the battlefield, each player chooses a nonland permanent and puts a doom counter on it. + addCard(Zone.HAND, playerC, "Eye of Doom", 1); + addCard(Zone.BATTLEFIELD, playerC, "Forest", 4); + + checkPlayerInGame("A must plays in 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, playerA, true); + attack(1, playerA, cardBear2); + + checkPlayerInGame("A must plays in 2", 2, PhaseStep.PRECOMBAT_MAIN, playerD, playerA, true); + attack(2, playerD, cardBear2); + + checkPlayerInGame("A must plays in 3 before", 3, PhaseStep.PRECOMBAT_MAIN, playerC, playerA, true); + attack(3, playerC, cardBear2); + concede(3, PhaseStep.PRECOMBAT_MAIN, playerA); + checkPlayerInGame("A must leaved in 3 after", 3, PhaseStep.POSTCOMBAT_MAIN, playerC, playerA, false); + + // test PlayerList.getNext processing + // play Eye of Doom, ask all players to put doom counter + castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerC, "Eye of Doom"); + addTarget(playerC, cardBear2); + addTarget(playerB, cardBear2); + //addTarget(playerA, cardBear2); // leaved + addTarget(playerD, cardBear2); + + checkPlayerInGame("A must leaved in 4", 4, PhaseStep.POSTCOMBAT_MAIN, playerB, playerA, false); + attack(4, playerB, cardBear2); + checkPlayerInGame("A must leaved in 5", 5, PhaseStep.POSTCOMBAT_MAIN, playerD, playerA, false); + attack(5, playerD, cardBear2); + + setStopAt(5, PhaseStep.CLEANUP); + setStrictChooseMode(true); + execute(); + assertAllCommandsUsed(); + } + } diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java index e414bfb3c17..4355daf9b4e 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java @@ -217,7 +217,7 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu boolean canDelete = false; Player player = game.getPlayer(startingControllerId); - // discard on start of turn for leave player + // discard on start of turn for leaved player // 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. // They neither expire immediately nor last indefinitely. diff --git a/Mage/src/main/java/mage/abilities/effects/common/ClashEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ClashEffect.java index 5575a214741..182b6e583f3 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ClashEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ClashEffect.java @@ -1,7 +1,5 @@ - package mage.abilities.effects.common; -import java.io.ObjectStreamException; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.MageSingleton; @@ -20,6 +18,8 @@ import mage.players.PlayerList; import mage.target.Target; import mage.target.common.TargetOpponent; +import java.io.ObjectStreamException; + /** * 1. The controller of the spell or ability chooses an opponent. (This doesn't * target the opponent.) 2. Each player involved in the clash reveals the top @@ -36,7 +36,7 @@ import mage.target.common.TargetOpponent; * 7. The clash spell or ability finishes resolving. That usually involves a * bonus gained by the controller of the clash spell or ability if they won * the clash. 8. Abilities that triggered during the clash are put on the stack. - * + *

* There are no draws or losses in a clash. Either you win it or you don't. Each * spell or ability with clash says what happens if you (the controller of that * spell or ability) win the clash. Typically, if you don't win the clash, @@ -148,7 +148,7 @@ public class ClashEffect extends OneShotEffect implements MageSingleton { if (cardOpponent != null && current.getId().equals(opponent.getId())) { topOpponent = current.chooseUse(Outcome.Detriment, "Put " + cardOpponent.getLogName() + " back on top of your library? (otherwise it goes to bottom)", source, game); } - nextPlayer = playerList.getNext(game); + nextPlayer = playerList.getNext(game, false); } while (nextPlayer != null && !nextPlayer.getId().equals(game.getActivePlayerId())); // put the cards back to library if (cardController != null) { diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 96aca2cb527..2da492db7d3 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -766,7 +766,7 @@ public abstract class GameImpl implements Game, Serializable { state.getTurn().resumePlay(this, wasPaused); if (!isPaused() && !checkIfGameIsOver()) { endOfTurn(); - player = playerList.getNext(this); + player = playerList.getNext(this, true); state.setTurnNum(state.getTurnNum() + 1); } } @@ -791,7 +791,7 @@ public abstract class GameImpl implements Game, Serializable { if (!playExtraTurns()) { break; } - playerByOrder = playerList.getNext(this); + playerByOrder = playerList.getNext(this, true); state.setPlayerByOrderId(playerByOrder.getId()); } } @@ -2494,7 +2494,6 @@ public abstract class GameImpl implements Game, Serializable { perm.removeFromCombat(this, true); } toOutside.add(perm); -// it.remove(); } else if (perm.isControlledBy(player.getId())) { // and any effects which give that player control of any objects or players end Effects: @@ -2591,7 +2590,7 @@ public abstract class GameImpl implements Game, Serializable { if (!isActivePlayer(playerId)) { setMonarchId(null, getActivePlayerId()); } else { - Player nextPlayer = getPlayerList().getNext(this); + Player nextPlayer = getPlayerList().getNext(this, true); if (nextPlayer != null) { setMonarchId(null, nextPlayer.getId()); } diff --git a/Mage/src/main/java/mage/game/combat/Combat.java b/Mage/src/main/java/mage/game/combat/Combat.java index acf6d191f33..91874cdd0dc 100644 --- a/Mage/src/main/java/mage/game/combat/Combat.java +++ b/Mage/src/main/java/mage/game/combat/Combat.java @@ -1236,7 +1236,7 @@ public class Combat implements Serializable, Copyable { case LEFT: players = game.getState().getPlayerList(attackingPlayerId); while (attackingPlayer.isInGame()) { - Player opponent = players.getNext(game); + Player opponent = players.getNext(game, false); if (attackingPlayer.hasOpponent(opponent.getId(), game)) { attackablePlayers.add(opponent.getId()); break; diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 38c9f1fdf5a..d641650af6e 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -487,10 +487,10 @@ public abstract class PlayerImpl implements Player, Serializable { inRange.add(playerId); PlayerList players = game.getState().getPlayerList(playerId); for (int i = 0; i < range.getRange(); i++) { - Player player = players.getNext(game); + Player player = players.getNext(game, false); if (player != null) { while (player.hasLeft()) { - player = players.getNext(game); + player = players.getNext(game, false); } inRange.add(player.getId()); } diff --git a/Mage/src/main/java/mage/players/PlayerList.java b/Mage/src/main/java/mage/players/PlayerList.java index 2c6f7633cd5..f25b5a9a16d 100644 --- a/Mage/src/main/java/mage/players/PlayerList.java +++ b/Mage/src/main/java/mage/players/PlayerList.java @@ -1,12 +1,11 @@ - package mage.players; -import java.util.UUID; import mage.game.Game; import mage.util.CircularList; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class PlayerList extends CircularList { @@ -23,7 +22,7 @@ public class PlayerList extends CircularList { } public Player getNextInRange(Player basePlayer, Game game) { - UUID currentPlayerBefore = get(); + UUID currentPlayerBefore = this.get(); UUID nextPlayerId = super.getNext(); do { if (basePlayer.getInRange().contains(nextPlayerId)) { @@ -34,7 +33,10 @@ public class PlayerList extends CircularList { return null; } - public Player getNext(Game game) { + /** + * checkNextTurnReached - use it turns/priority code only to mark leaved player as "reached next turn end" (need for some continous effects) + */ + public Player getNext(Game game, boolean checkNextTurnReached) { UUID start = this.get(); if (start == null) { return null; @@ -42,11 +44,14 @@ public class PlayerList extends CircularList { Player player; while (true) { player = game.getPlayer(super.getNext()); - if (!player.hasLeft() && !player.hasLost()) { + if (player.isInGame()) { break; } - if (!player.hasReachedNextTurnAfterLeaving()) { - player.setReachedNextTurnAfterLeaving(true); + + if (checkNextTurnReached) { + if (!player.hasReachedNextTurnAfterLeaving()) { + player.setReachedNextTurnAfterLeaving(true); + } } if (player.getId().equals(start)) { return null; @@ -60,7 +65,7 @@ public class PlayerList extends CircularList { UUID start = this.get(); while (true) { player = game.getPlayer(super.getPrevious()); - if (!player.hasLeft() && !player.hasLost()) { + if (player.isInGame()) { break; } if (player.getId().equals(start)) {