diff --git a/Mage.Sets/src/mage/cards/b/BarbarianBully.java b/Mage.Sets/src/mage/cards/b/BarbarianBully.java index f08f840f347..0657151e523 100644 --- a/Mage.Sets/src/mage/cards/b/BarbarianBully.java +++ b/Mage.Sets/src/mage/cards/b/BarbarianBully.java @@ -66,7 +66,7 @@ class BarbarianBullyEffect extends OneShotEffect { return false; } boolean costPaid = false; - for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player == null) { continue; diff --git a/Mage/src/main/java/mage/game/Game.java b/Mage/src/main/java/mage/game/Game.java index 2c2d713c7ae..f276fb45aaa 100644 --- a/Mage/src/main/java/mage/game/Game.java +++ b/Mage/src/main/java/mage/game/Game.java @@ -159,20 +159,23 @@ public interface Game extends MageItem, Serializable, Copyable { Player getPlayerOrPlaneswalkerController(UUID playerId); /** - * Static players list from start of the game. Use it to find player by ID. + * Static players list from start of the game. Use it to find player by ID or in game engine. */ Players getPlayers(); /** * Static players list from start of the game. Use it to interate by starting turn order. - * WARNING, it's ignore range and leaved players, so use it game engine only + * WARNING, it's ignore range and leaved players, so use it by game engine only */ + // TODO: check usage of getPlayerList in cards and replace by game.getState().getPlayersInRange PlayerList getPlayerList(); /** * Returns opponents list in range for the given playerId. Use it to interate by starting turn order. - * Warning, it will return dead players until end of turn. + * + * Warning, it will return leaved players until end of turn. For dialogs and one shot effects use excludeLeavedPlayers */ + // TODO: check usage of getOpponents in cards and replace with correct call of excludeLeavedPlayers default Set getOpponents(UUID playerId) { return getOpponents(playerId, false); } @@ -181,9 +184,9 @@ public interface Game extends MageItem, Serializable, Copyable { * Returns opponents list in range for the given playerId. Use it to interate by starting turn order. * Warning, it will return dead players until end of turn. * - * @param excludeDeadPlayers exclude dead player immediately without waiting range update on next turn + * @param excludeLeavedPlayers exclude dead player immediately without waiting range update on next turn */ - default Set getOpponents(UUID playerId, boolean excludeDeadPlayers) { + default Set getOpponents(UUID playerId, boolean excludeLeavedPlayers) { Player player = getPlayer(playerId); if (player == null) { return new LinkedHashSet<>(); @@ -192,7 +195,7 @@ public interface Game extends MageItem, Serializable, Copyable { return this.getPlayerList().stream() .filter(opponentId -> !opponentId.equals(playerId)) .filter(player::hasPlayerInRange) - .filter(opponentId -> !excludeDeadPlayers || !getPlayer(opponentId).hasLost()) + .filter(opponentId -> !excludeLeavedPlayers || getPlayer(opponentId).isInGame()) .collect(Collectors.toCollection(LinkedHashSet::new)); } diff --git a/Mage/src/main/java/mage/game/GameCommanderImpl.java b/Mage/src/main/java/mage/game/GameCommanderImpl.java index 86f0ae07caa..78a5c5f986e 100644 --- a/Mage/src/main/java/mage/game/GameCommanderImpl.java +++ b/Mage/src/main/java/mage/game/GameCommanderImpl.java @@ -247,6 +247,10 @@ public abstract class GameCommanderImpl extends GameImpl { @Override protected boolean checkStateBasedActions() { for (Player player : getPlayers().values()) { + if (!player.isInGame()) { + continue; + } + for (UUID commanderId : this.getCommandersIds(player, CommanderCardType.COMMANDER_OR_OATHBREAKER, false)) { CommanderInfoWatcher damageWatcher = getState().getWatcher(CommanderInfoWatcher.class, commanderId); if (damageWatcher == null) { @@ -255,7 +259,7 @@ public abstract class GameCommanderImpl extends GameImpl { for (Map.Entry entrySet : damageWatcher.getDamageToPlayer().entrySet()) { if (entrySet.getValue() > 20) { Player opponent = getPlayer(entrySet.getKey()); - if (opponent != null && !opponent.hasLost() && player.isInGame()) { + if (opponent != null && !opponent.hasLost()) { opponent.lost(this); } } diff --git a/Mage/src/main/java/mage/game/GameState.java b/Mage/src/main/java/mage/game/GameState.java index ae70b465bac..3f8ef44ff42 100644 --- a/Mage/src/main/java/mage/game/GameState.java +++ b/Mage/src/main/java/mage/game/GameState.java @@ -719,6 +719,8 @@ public class GameState implements Serializable, Copyable { /** * Returns a list of all players of the game ignoring range or if a player * has lost or left the game. + * + * Warning, it's ignore range, must be used by game engine only. */ public PlayerList getPlayerList() { return playerList; @@ -728,13 +730,12 @@ public class GameState implements Serializable, Copyable { * Returns a list of all active players of the game, setting the playerId to * the current player of the list. * - * @param playerId - * @return playerList + * Warning, it's ignore range, must be used by game engine only. */ public PlayerList getPlayerList(UUID playerId) { PlayerList newPlayerList = new PlayerList(); for (Player player : players.values()) { - if (!player.hasLeft() && !player.hasLost()) { + if (player.isInGame()) { newPlayerList.add(player.getId()); } } @@ -742,26 +743,29 @@ public class GameState implements Serializable, Copyable { return newPlayerList; } + // TODO: check usage of getPlayersInRange in cards and replace with correct call of excludeLeavedPlayers + public PlayerList getPlayersInRange(UUID playerId, Game game) { + return getPlayersInRange(playerId, game, false); + } + /** * Returns a list of all active players of the game in range of playerId, * also setting the playerId to the first/current player of the list. Also * returning the other players in turn order. *

- * Not safe for continuous effects, see rule 800.4k (effects must work until - * end of turn even after player leaves) Use Player.InRange() to find active - * players list at the start of the turn + * Continuous effects, triggers and other must include leaved players, see rule 800.4k (effects must work until + * end of turn even after player leaves). But one short effects and dialogs must use actual players list. * - * @param playerId - * @param game - * @return playerList + * @param excludeLeavedPlayers - true for dialogs and one short effects, false for triggers and continuous effects */ - public PlayerList getPlayersInRange(UUID playerId, Game game) { + public PlayerList getPlayersInRange(UUID playerId, Game game, boolean excludeLeavedPlayers) { PlayerList newPlayerList = new PlayerList(); Player currentPlayer = game.getPlayer(playerId); if (currentPlayer != null) { // must fill PlayerList by table added order (same as main game) for (Player player : players.values()) { - if (player.isInGame() && currentPlayer.hasPlayerInRange(player.getId())) { + if ((!excludeLeavedPlayers || player.isInGame()) + && currentPlayer.hasPlayerInRange(player.getId())) { newPlayerList.add(player.getId()); } } diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index 5ea3418c940..f41c02f3123 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -277,6 +277,7 @@ public interface Player extends MageItem, Copyable { void idleTimeout(Game game); + // TODO: research usage of !hasLeft() && !hasLost() replace it by isInGame() if possible boolean hasLeft(); /**