diff --git a/Mage.Common/src/mage/view/PlayerView.java b/Mage.Common/src/mage/view/PlayerView.java index 49b5b3d8e5..ee63045b38 100644 --- a/Mage.Common/src/mage/view/PlayerView.java +++ b/Mage.Common/src/mage/view/PlayerView.java @@ -92,7 +92,8 @@ public class PlayerView implements Serializable { this.experience = player.getCounters().getCount(CounterType.EXPERIENCE); this.wins = player.getMatchPlayer().getWins(); this.winsNeeded = player.getMatchPlayer().getWinsNeeded(); - this.deckHashCode = player.getMatchPlayer().getDeck().getDeckHashCode(); + // If match ended immediately before, deck can be set to null so check is necessarry here + this.deckHashCode = player.getMatchPlayer().getDeck() != null ? player.getMatchPlayer().getDeck().getDeckHashCode() : 0; this.libraryCount = player.getLibrary().size(); this.handCount = player.getHand().size(); this.manaPool = new ManaPoolView(player.getManaPool()); diff --git a/Mage.Server/src/main/java/mage/server/MageServerImpl.java b/Mage.Server/src/main/java/mage/server/MageServerImpl.java index 6489473a79..d0a62c9940 100644 --- a/Mage.Server/src/main/java/mage/server/MageServerImpl.java +++ b/Mage.Server/src/main/java/mage/server/MageServerImpl.java @@ -141,7 +141,7 @@ public class MageServerImpl implements MageServer { String authToken = generateAuthToken(); activeAuthTokens.put(email, authToken); String subject = "XMage Password Reset Auth Token"; - String text = "Use this auth token to reset your password: " + authToken + "\n" + String text = "Use this auth token to reset " + authorizedUser.name + "'s password: " + authToken + "\n" + "It's valid until the next server restart."; boolean success; if (!ConfigSettings.getInstance().getMailUser().isEmpty()) { @@ -500,11 +500,11 @@ public class MageServerImpl implements MageServer { try { callExecutor.execute( new Runnable() { - @Override - public void run() { - ChatManager.getInstance().broadcast(chatId, userName, StringEscapeUtils.escapeHtml4(message), MessageColor.BLUE); - } - } + @Override + public void run() { + ChatManager.getInstance().broadcast(chatId, userName, StringEscapeUtils.escapeHtml4(message), MessageColor.BLUE); + } + } ); } catch (Exception ex) { handleException(ex); @@ -1139,19 +1139,19 @@ public class MageServerImpl implements MageServer { try { callExecutor.execute( new Runnable() { - @Override - public void run() { - if (SessionManager.getInstance().isValidSession(sessionId)) { - try { - action.execute(); - } catch (MageException me) { - throw new RuntimeException(me); - } - } else { - LogServiceImpl.instance.log(LogKeys.KEY_NOT_VALID_SESSION_INTERNAL, actionName, sessionId); - } + @Override + public void run() { + if (SessionManager.getInstance().isValidSession(sessionId)) { + try { + action.execute(); + } catch (MageException me) { + throw new RuntimeException(me); } + } else { + LogServiceImpl.instance.log(LogKeys.KEY_NOT_VALID_SESSION_INTERNAL, actionName, sessionId); } + } + } ); } catch (Exception ex) { handleException(ex); diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index 64edc644b1..0af0a5c829 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -132,19 +132,19 @@ public class TableController { private void init() { match.addTableEventListener( new Listener() { - @Override - public void event(TableEvent event) { - try { - switch (event.getEventType()) { - case SIDEBOARD: - sideboard(event.getPlayerId(), event.getDeck()); - break; - } - } catch (MageException ex) { - logger.fatal("Table event listener error", ex); - } + @Override + public void event(TableEvent event) { + try { + switch (event.getEventType()) { + case SIDEBOARD: + sideboard(event.getPlayerId(), event.getDeck()); + break; } + } catch (MageException ex) { + logger.fatal("Table event listener error", ex); } + } + } ); } @@ -333,17 +333,15 @@ public class TableController { if (player == null || player.hasQuit()) { return true; // so the construct panel closes after submit } - } else { - if (table.getMatch() != null) { - MatchPlayer mPlayer = table.getMatch().getPlayer(playerId); - if (mPlayer == null || mPlayer.hasQuit()) { - return true; // so the construct panel closes after submit - } - if (table.isTournamentSubTable()) { - TournamentPlayer tournamentPlayer = table.getTournament().getPlayer(mPlayer.getPlayer().getId()); - if (tournamentPlayer != null) { - tournamentPlayer.setStateInfo(""); // reset sideboarding state - } + } else if (table.getMatch() != null) { + MatchPlayer mPlayer = table.getMatch().getPlayer(playerId); + if (mPlayer == null || mPlayer.hasQuit()) { + return true; // so the construct panel closes after submit + } + if (table.isTournamentSubTable()) { + TournamentPlayer tournamentPlayer = table.getTournament().getPlayer(mPlayer.getPlayer().getId()); + if (tournamentPlayer != null) { + tournamentPlayer.setStateInfo(""); // reset sideboarding state } } } @@ -390,12 +388,10 @@ public class TableController { } else { logger.fatal("Tournament == null table: " + table.getId() + " userId: " + userId); } + } else if (TableState.SIDEBOARDING.equals(table.getState())) { + match.updateDeck(playerId, deck); } else { - if (TableState.SIDEBOARDING.equals(table.getState())) { - match.updateDeck(playerId, deck); - } else { - // deck was meanwhile submitted so the autoupdate can be ignored - } + // deck was meanwhile submitted so the autoupdate can be ignored } } @@ -591,7 +587,9 @@ public class TableController { // log about game started logger.info("GAME started " + match.getGame().getId() + " [" + match.getName() + "] " + creator + " - " + opponent.toString()); logger.debug("- matchId: " + match.getId() + " [" + match.getName() + "]"); - logger.debug("- chatId: " + GameManager.getInstance().getChatId(match.getGame().getId())); + if (match.getGame() != null) { + logger.debug("- chatId: " + GameManager.getInstance().getChatId(match.getGame().getId())); + } LogServiceImpl.instance.log(LogKeys.KEY_GAME_STARTED, String.valueOf(userPlayerMap.size()), creator, opponent.toString()); } catch (Exception ex) { logger.fatal("Error starting game table: " + table.getId(), ex); @@ -791,11 +789,11 @@ public class TableController { if (seconds > 0) { futureTimeout = timeoutExecutor.schedule( new Runnable() { - @Override - public void run() { - autoSideboard(); - } - }, + @Override + public void run() { + autoSideboard(); + } + }, seconds, TimeUnit.SECONDS ); } @@ -896,13 +894,11 @@ public class TableController { logger.debug("- Match table with no match:"); logger.debug("-- matchId:" + match.getId() + " [" + match.getName() + "]"); // return false; - } else { - if (match.isDoneSideboarding() && match.getGame() == null) { - // no sideboarding and not active game -> match seems to hang (maybe the Draw bug) - logger.debug("- Match with no active game and not in sideboard state:"); - logger.debug("-- matchId:" + match.getId() + " [" + match.getName() + "]"); - // return false; - } + } else if (match.isDoneSideboarding() && match.getGame() == null) { + // no sideboarding and not active game -> match seems to hang (maybe the Draw bug) + logger.debug("- Match with no active game and not in sideboard state:"); + logger.debug("-- matchId:" + match.getId() + " [" + match.getName() + "]"); + // return false; } } // check for active players @@ -964,7 +960,7 @@ public class TableController { // tournament is not ready, can't start return false; } - if (!table.allSeatsAreOccupied()) { + if (!table.allSeatsAreOccupied()) { logger.debug("Not alle Seats are occupied: stop start tableId:" + table.getId()); return false; } diff --git a/Mage.Server/src/main/java/mage/server/game/GameWorker.java b/Mage.Server/src/main/java/mage/server/game/GameWorker.java index e36dce24b2..934a6bccf3 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameWorker.java +++ b/Mage.Server/src/main/java/mage/server/game/GameWorker.java @@ -40,7 +40,7 @@ import org.apache.log4j.Logger; */ public class GameWorker implements Callable { - private static final Logger logger = Logger.getLogger(GameWorker.class); + private static final Logger LOGGER = Logger.getLogger(GameWorker.class); private final GameCallback gameController; private final Game game; @@ -55,18 +55,26 @@ public class GameWorker implements Callable { @Override public Object call() { try { - logger.debug("GAME WORKER started gameId " + game.getId()); + LOGGER.debug("GAME WORKER started gameId " + game.getId()); Thread.currentThread().setName("GAME " + game.getId()); game.start(choosingPlayerId); game.fireUpdatePlayersEvent(); gameController.gameResult(game.getWinner()); game.cleanUp(); } catch (MageException ex) { - logger.fatal("GameWorker mage error [" + game.getId() + "]" + ex, ex); + LOGGER.fatal("GameWorker mage error [" + game.getId() + "] " + ex, ex); } catch (Exception e) { - logger.fatal("GameWorker general exception [" + game.getId() + "]" + e.getMessage(), e); + LOGGER.fatal("GameWorker general exception [" + game.getId() + "] " + e.getMessage(), e); + if (e instanceof NullPointerException) { + if (e.getStackTrace() == null) { + LOGGER.info("Stack trace is null"); + } else { + LOGGER.info("Null-Pointer-Exception: Stack trace"); + LOGGER.info(e.getStackTrace()); + } + } } catch (Error err) { - logger.fatal("GameWorker general error [" + game.getId() + "]" + err, err); + LOGGER.fatal("GameWorker general error [" + game.getId() + "] " + err, err); } return null; } diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/AllyEncampment.java b/Mage.Sets/src/mage/sets/battleforzendikar/AllyEncampment.java index c1dbe52d37..9e209644e4 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/AllyEncampment.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/AllyEncampment.java @@ -52,10 +52,10 @@ import mage.target.common.TargetControlledCreaturePermanent; */ public class AllyEncampment extends CardImpl { - private static final FilterSpell filter = new FilterSpell("an Ally spell"); + private static final FilterSpell FILTER = new FilterSpell("an Ally spell"); static { - filter.add(new SubtypePredicate("Ally")); + FILTER.add(new SubtypePredicate("Ally")); } public AllyEncampment(UUID ownerId) { @@ -66,7 +66,7 @@ public class AllyEncampment extends CardImpl { this.addAbility(new ColorlessManaAbility()); // {T} Add one mana of any color to your mana pool. Spend this mana only to cast an Ally spell. - this.addAbility(new ConditionalAnyColorManaAbility(new TapSourceCost(), 1, new ConditionalSpellManaBuilder(filter), true)); + this.addAbility(new ConditionalAnyColorManaAbility(new TapSourceCost(), 1, new ConditionalSpellManaBuilder(FILTER), true)); // {1}, {T}, Sacrifice Ally Encampment: Return target Ally you control to its owner's hand. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new GenericManaCost(1)); diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/VoiceOfResurgence.java b/Mage.Sets/src/mage/sets/dragonsmaze/VoiceOfResurgence.java index 6e76865f93..a10dbc38f5 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/VoiceOfResurgence.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/VoiceOfResurgence.java @@ -31,7 +31,6 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; @@ -40,8 +39,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; import mage.constants.Zone; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; @@ -125,13 +123,6 @@ class VoiceOfResurgenceTriggeredAbility extends TriggeredAbilityImpl { class VoiceOfResurgenceToken extends Token { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("creatures you control"); - private static final DynamicValue creaturesControlled = new PermanentsOnBattlefieldCount(filter); - - static { - filter.add(new CardTypePredicate(CardType.CREATURE)); - } - public VoiceOfResurgenceToken() { super("Elemental", "X/X green and white Elemental creature with with \"This creature's power and toughness are each equal to the number of creatures you control."); setOriginalExpansionSetCode("DGM"); @@ -140,9 +131,10 @@ class VoiceOfResurgenceToken extends Token { color.setWhite(true); subtype.add("Elemental"); - power = new MageInt(0); + power = new MageInt(0); toughness = new MageInt(0); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SetPowerToughnessSourceEffect(creaturesControlled, Duration.EndOfGame))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SetPowerToughnessSourceEffect( + new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()), Duration.EndOfGame))); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/VoiceOfResurgenceTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/VoiceOfResurgenceTest.java new file mode 100644 index 0000000000..0fcd6d4d74 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/VoiceOfResurgenceTest.java @@ -0,0 +1,80 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.triggers.dies; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class VoiceOfResurgenceTest extends CardTestPlayerBase { + + /** + * Voice of Resurgence creates it's token under owner's control upon death + * even when it is controlled by an opponent when it dies. Happened with + * Treachery. + * + */ + @Test + public void testDiesTriggeredAbility() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); + // Enchant creature + // When Treachery enters the battlefield, untap up to five lands. + // You control enchanted creature. + addCard(Zone.HAND, playerA, "Treachery"); // {3}{U}{U} + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); + // Whenever an opponent casts a spell during your turn or when Voice of Resurgence dies, + // put a green and white Elemental creature token onto the battlefield with "This creature's power and toughness are each equal to the number of creatures you control." + addCard(Zone.BATTLEFIELD, playerB, "Voice of Resurgence", 1); // 2/2 + addCard(Zone.HAND, playerB, "Lightning Bolt"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treachery", "Voice of Resurgence"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", "Voice of Resurgence"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + + assertGraveyardCount(playerA, "Treachery", 1); + assertGraveyardCount(playerB, "Voice of Resurgence", 1); + + assertPermanentCount(playerA, "Elemental", 1); + assertPowerToughness(playerA, "Elemental", 2, 2); + assertTappedCount("Island", true, 0); + } + +} diff --git a/Mage/src/main/java/mage/abilities/common/BeginningOfUntapTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/BeginningOfUntapTriggeredAbility.java index 233935e988..8bb9d6ae87 100644 --- a/Mage/src/main/java/mage/abilities/common/BeginningOfUntapTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/BeginningOfUntapTriggeredAbility.java @@ -18,7 +18,7 @@ import mage.target.targetpointer.FixedTarget; * @author Jeff */ public class BeginningOfUntapTriggeredAbility extends TriggeredAbilityImpl { - + private TargetController targetController; public BeginningOfUntapTriggeredAbility(Effect effect, TargetController targetController, boolean isOptional) { @@ -51,7 +51,7 @@ public class BeginningOfUntapTriggeredAbility extends TriggeredAbilityImpl { case YOU: boolean yours = event.getPlayerId().equals(this.controllerId); if (yours) { - if (getTargets().size() == 0) { + if (getTargets().isEmpty()) { for (Effect effect : this.getEffects()) { effect.setTargetPointer(new FixedTarget(event.getPlayerId())); } @@ -61,14 +61,14 @@ public class BeginningOfUntapTriggeredAbility extends TriggeredAbilityImpl { case NOT_YOU: Player controller = game.getPlayer(this.getControllerId()); if (controller != null && controller.getInRange().contains(event.getPlayerId()) && !event.getPlayerId().equals(this.getControllerId())) { - if (getTargets().size() == 0) { + if (getTargets().isEmpty()) { for (Effect effect : this.getEffects()) { effect.setTargetPointer(new FixedTarget(event.getPlayerId())); } } return true; } - break; + break; case OPPONENT: if (game.getPlayer(this.controllerId).hasOpponent(event.getPlayerId(), game)) { if (getTargets().size() == 0) { @@ -78,7 +78,7 @@ public class BeginningOfUntapTriggeredAbility extends TriggeredAbilityImpl { } return true; } - break; + break; case ANY: controller = game.getPlayer(this.getControllerId()); if (controller != null && controller.getInRange().contains(event.getPlayerId())) { @@ -117,5 +117,5 @@ public class BeginningOfUntapTriggeredAbility extends TriggeredAbilityImpl { } return ""; } - + } diff --git a/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardEachPlayerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardEachPlayerEffect.java index e801fa4d07..912186fe39 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardEachPlayerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardEachPlayerEffect.java @@ -64,10 +64,10 @@ public class DiscardEachPlayerEffect extends OneShotEffect { HashMap cardsToDiscard = new HashMap<>(); if (controller != null) { // choose cards to discard - for (UUID playerId : controller.getInRange()) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - switch(targetController) { + switch (targetController) { case NOT_YOU: if (playerId.equals(source.getControllerId())) { continue; @@ -127,7 +127,7 @@ public class DiscardEachPlayerEffect extends OneShotEffect { } StringBuilder sb = new StringBuilder(); sb.append("each "); - switch(targetController) { + switch (targetController) { case NOT_YOU: sb.append("other player"); break; diff --git a/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardHandAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardHandAllEffect.java index 0e28b171c6..fca8199637 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardHandAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardHandAllEffect.java @@ -57,8 +57,7 @@ public class DiscardHandAllEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player sourcePlayer = game.getPlayer(source.getControllerId()); - for (UUID playerId : sourcePlayer.getInRange()) { + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { Set cards = player.getHand().getCards(game); @@ -66,7 +65,7 @@ public class DiscardHandAllEffect extends OneShotEffect { player.discard(card, source, game); } } - } + } return true; } } diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 38e76d28be..6af9ce25fd 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -138,24 +138,24 @@ public abstract class GameImpl implements Game, Serializable { private static final int ROLLBACK_TURNS_MAX = 4; - private static final Logger logger = Logger.getLogger(GameImpl.class); + private static final Logger LOGGER = Logger.getLogger(GameImpl.class); - private static final FilterPermanent filterAura = new FilterPermanent(); - private static final FilterPermanent filterEquipment = new FilterPermanent(); - private static final FilterPermanent filterFortification = new FilterPermanent(); - private static final FilterPermanent filterLegendary = new FilterPermanent(); + private static final FilterPermanent FILTER_AURA = new FilterPermanent(); + private static final FilterPermanent FILTER_EQUIPMENT = new FilterPermanent(); + private static final FilterPermanent FILTER_FORTIFICATION = new FilterPermanent(); + private static final FilterPermanent FILTER_LEGENDARY = new FilterPermanent(); static { - filterAura.add(new CardTypePredicate(CardType.ENCHANTMENT)); - filterAura.add(new SubtypePredicate("Aura")); + FILTER_AURA.add(new CardTypePredicate(CardType.ENCHANTMENT)); + FILTER_AURA.add(new SubtypePredicate("Aura")); - filterEquipment.add(new CardTypePredicate(CardType.ARTIFACT)); - filterEquipment.add(new SubtypePredicate("Equipment")); + FILTER_EQUIPMENT.add(new CardTypePredicate(CardType.ARTIFACT)); + FILTER_EQUIPMENT.add(new SubtypePredicate("Equipment")); - filterFortification.add(new CardTypePredicate(CardType.ARTIFACT)); - filterFortification.add(new SubtypePredicate("Fortification")); + FILTER_FORTIFICATION.add(new CardTypePredicate(CardType.ARTIFACT)); + FILTER_FORTIFICATION.add(new SubtypePredicate("Fortification")); - filterLegendary.add(new SupertypePredicate("Legendary")); + FILTER_LEGENDARY.add(new SupertypePredicate("Legendary")); } private static Random rnd = new Random(); @@ -230,7 +230,7 @@ public abstract class GameImpl implements Game, Serializable { public GameImpl(final GameImpl game) { long t1 = 0; - if (logger.isDebugEnabled()) { + if (LOGGER.isDebugEnabled()) { t1 = System.currentTimeMillis(); } this.id = game.id; @@ -248,7 +248,7 @@ public abstract class GameImpl implements Game, Serializable { this.lkiExtended.putAll(game.lkiExtended); this.shortLivingLKI.putAll(game.shortLivingLKI); this.permanentsEntering.putAll(game.permanentsEntering); - if (logger.isDebugEnabled()) { + if (LOGGER.isDebugEnabled()) { copyCount++; copyTime += (System.currentTimeMillis() - t1); } @@ -577,7 +577,7 @@ public abstract class GameImpl implements Game, Serializable { boolean result = checkIfGameIsOver(); return result; } else { - logger.debug("Game over for player Id: " + playerId + " gameId " + getId()); + LOGGER.debug("Game over for player Id: " + playerId + " gameId " + getId()); leave(playerId); return true; } @@ -599,15 +599,15 @@ public abstract class GameImpl implements Game, Serializable { } if (remainingPlayers <= 1 || numLosers >= state.getPlayers().size() - 1) { end(); - if (remainingPlayers == 0 && logger.isDebugEnabled()) { - logger.debug("DRAW for gameId: " + getId()); + if (remainingPlayers == 0 && LOGGER.isDebugEnabled()) { + LOGGER.debug("DRAW for gameId: " + getId()); for (Player player : state.getPlayers().values()) { - logger.debug("-- " + player.getName() + " left: " + (player.hasLeft() ? "Y" : "N") + " lost: " + (player.hasLost() ? "Y" : "N")); + LOGGER.debug("-- " + player.getName() + " left: " + (player.hasLeft() ? "Y" : "N") + " lost: " + (player.hasLost() ? "Y" : "N")); } } for (Player player : state.getPlayers().values()) { if (!player.hasLeft() && !player.hasLost()) { - logger.debug(new StringBuilder("Player ").append(player.getName()).append(" has won gameId: ").append(this.getId())); + LOGGER.debug(new StringBuilder("Player ").append(player.getName()).append(" has won gameId: ").append(this.getId())); player.won(this); } } @@ -643,8 +643,8 @@ public abstract class GameImpl implements Game, Serializable { public int bookmarkState() { if (!simulation) { saveState(true); - if (logger.isTraceEnabled()) { - logger.trace("Bookmarking state: " + gameStates.getSize()); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Bookmarking state: " + gameStates.getSize()); } savedStates.push(gameStates.getSize() - 1); return savedStates.size(); @@ -772,7 +772,7 @@ public abstract class GameImpl implements Game, Serializable { sb.append("]"); count++; } - logger.info(sb.toString()); + LOGGER.info(sb.toString()); } } @@ -926,7 +926,7 @@ public abstract class GameImpl implements Game, Serializable { } Player startingPlayer = state.getPlayer(startingPlayerId); if (startingPlayer == null) { - logger.debug("Starting player not found. playerId:" + startingPlayerId); + LOGGER.debug("Starting player not found. playerId:" + startingPlayerId); return; } StringBuilder message = new StringBuilder(choosingPlayer.getLogName()).append(" chooses that "); @@ -1052,12 +1052,12 @@ public abstract class GameImpl implements Game, Serializable { UUID winnerIdFound = null; for (Player player : state.getPlayers().values()) { if (player.hasWon()) { - logger.debug(player.getName() + " has won gameId: " + getId()); + LOGGER.debug(player.getName() + " has won gameId: " + getId()); winnerIdFound = player.getId(); break; } if (!player.hasLost() && !player.hasLeft()) { - logger.debug(player.getName() + " has not lost so he won gameId: " + this.getId()); + LOGGER.debug(player.getName() + " has not lost so he won gameId: " + this.getId()); player.won(this); winnerIdFound = player.getId(); break; @@ -1089,7 +1089,7 @@ public abstract class GameImpl implements Game, Serializable { return player.getId(); } } - logger.debug("Game was not possible to pick a choosing player. GameId:" + getId()); + LOGGER.debug("Game was not possible to pick a choosing player. GameId:" + getId()); return null; } @@ -1106,7 +1106,7 @@ public abstract class GameImpl implements Game, Serializable { @Override public void end() { if (!state.isGameOver()) { - logger.debug("END of gameId: " + this.getId()); + LOGGER.debug("END of gameId: " + this.getId()); endTime = new Date(); state.endGame(); for (Player player : state.getPlayers().values()) { @@ -1175,7 +1175,7 @@ public abstract class GameImpl implements Game, Serializable { if (player != null) { player.timerTimeout(this); } else { - logger.error(new StringBuilder("timerTimeout - player not found - playerId: ").append(playerId)); + LOGGER.error(new StringBuilder("timerTimeout - player not found - playerId: ").append(playerId)); } } @@ -1185,7 +1185,7 @@ public abstract class GameImpl implements Game, Serializable { if (player != null) { player.idleTimeout(this); } else { - logger.error(new StringBuilder("idleTimeout - player not found - playerId: ").append(playerId)); + LOGGER.error(new StringBuilder("idleTimeout - player not found - playerId: ").append(playerId)); } } @@ -1193,7 +1193,7 @@ public abstract class GameImpl implements Game, Serializable { public synchronized void concede(UUID playerId) { Player player = state.getPlayer(playerId); if (player != null) { - logger.debug("Player " + player.getName() + " concedes game " + this.getId()); + LOGGER.debug("Player " + player.getName() + " concedes game " + this.getId()); fireInformEvent(player.getLogName() + " has conceded."); player.concede(this); } @@ -1306,7 +1306,11 @@ public abstract class GameImpl implements Game, Serializable { } } } catch (Exception ex) { - logger.fatal("Game exception gameId: " + getId(), ex); + LOGGER.fatal("Game exception gameId: " + getId(), ex); + if ((ex instanceof NullPointerException) + && errorContinueCounter == 1 && ex.getStackTrace() != null) { + LOGGER.fatal(ex.getStackTrace()); + } this.fireErrorEvent("Game exception occurred: ", ex); restoreState(bookmark, ""); bookmark = 0; @@ -1325,7 +1329,7 @@ public abstract class GameImpl implements Game, Serializable { } } } catch (Exception ex) { - logger.fatal("Game exception ", ex); + LOGGER.fatal("Game exception ", ex); this.fireErrorEvent("Game exception occurred: ", ex); this.end(); } finally { @@ -1709,7 +1713,7 @@ public abstract class GameImpl implements Game, Serializable { if (perm.getSupertype().contains("World")) { worldEnchantment.add(perm); } - if (filterAura.match(perm, this)) { + if (FILTER_AURA.match(perm, this)) { //20091005 - 704.5n, 702.14c if (perm.getAttachedTo() == null) { Card card = this.getCard(perm.getId()); @@ -1732,7 +1736,7 @@ public abstract class GameImpl implements Game, Serializable { } if (spellAbility.getTargets().isEmpty()) { Permanent enchanted = this.getPermanent(perm.getAttachedTo()); - logger.error("Aura without target: " + perm.getName() + " attached to " + (enchanted == null ? " null" : enchanted.getName())); + LOGGER.error("Aura without target: " + perm.getName() + " attached to " + (enchanted == null ? " null" : enchanted.getName())); } else { Target target = spellAbility.getTargets().get(0); if (target instanceof TargetPermanent) { @@ -1744,10 +1748,8 @@ public abstract class GameImpl implements Game, Serializable { UUID wasAttachedTo = perm.getAttachedTo(); perm.attachTo(null, this); fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, wasAttachedTo, perm.getId(), perm.getControllerId())); - } else { - if (movePermanentToGraveyardWithInfo(perm)) { - somethingHappened = true; - } + } else if (movePermanentToGraveyardWithInfo(perm)) { + somethingHappened = true; } } else { Filter auraFilter = spellAbility.getTargets().get(0).getFilter(); @@ -1758,19 +1760,15 @@ public abstract class GameImpl implements Game, Serializable { somethingHappened = true; } } - } else { - if (!auraFilter.match(attachedTo, this) || attachedTo.cantBeEnchantedBy(perm, this)) { - // handle bestow unattachment - Card card = this.getCard(perm.getId()); - if (card != null && card.getCardType().contains(CardType.CREATURE)) { - UUID wasAttachedTo = perm.getAttachedTo(); - perm.attachTo(null, this); - fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, wasAttachedTo, perm.getId(), perm.getControllerId())); - } else { - if (movePermanentToGraveyardWithInfo(perm)) { - somethingHappened = true; - } - } + } else if (!auraFilter.match(attachedTo, this) || attachedTo.cantBeEnchantedBy(perm, this)) { + // handle bestow unattachment + Card card = this.getCard(perm.getId()); + if (card != null && card.getCardType().contains(CardType.CREATURE)) { + UUID wasAttachedTo = perm.getAttachedTo(); + perm.attachTo(null, this); + fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, wasAttachedTo, perm.getId(), perm.getControllerId())); + } else if (movePermanentToGraveyardWithInfo(perm)) { + somethingHappened = true; } } } @@ -1792,10 +1790,10 @@ public abstract class GameImpl implements Game, Serializable { } } } - if (this.getState().isLegendaryRuleActive() && filterLegendary.match(perm, this)) { + if (this.getState().isLegendaryRuleActive() && FILTER_LEGENDARY.match(perm, this)) { legendary.add(perm); } - if (filterEquipment.match(perm, this)) { + if (FILTER_EQUIPMENT.match(perm, this)) { //20091005 - 704.5p, 702.14d if (perm.getAttachedTo() != null) { Permanent creature = getPermanent(perm.getAttachedTo()); @@ -1810,7 +1808,7 @@ public abstract class GameImpl implements Game, Serializable { } } } - if (filterFortification.match(perm, this)) { + if (FILTER_FORTIFICATION.match(perm, this)) { if (perm.getAttachedTo() != null) { Permanent land = getPermanent(perm.getAttachedTo()); if (land == null || !land.getAttachments().contains(perm.getId())) { @@ -2093,7 +2091,7 @@ public abstract class GameImpl implements Game, Serializable { @Override public void debugMessage(String message) { - logger.warn(message); + LOGGER.warn(message); } @Override @@ -2117,7 +2115,7 @@ public abstract class GameImpl implements Game, Serializable { if (simulation) { return; } - logger.trace("fireUpdatePlayersEvent"); + LOGGER.trace("fireUpdatePlayersEvent"); tableEventSource.fireTableEvent(EventType.UPDATE, null, this); getState().clearLookedAt(); getState().clearRevealed(); @@ -2128,7 +2126,7 @@ public abstract class GameImpl implements Game, Serializable { if (simulation) { return; } - logger.trace("fireGameEndIfo"); + LOGGER.trace("fireGameEndIfo"); tableEventSource.fireTableEvent(EventType.END_GAME_INFO, null, this); } @@ -2214,10 +2212,10 @@ public abstract class GameImpl implements Game, Serializable { Player player = getPlayer(playerId); if (player == null || player.hasLeft()) { - logger.debug("Player already left " + (player != null ? player.getName() : playerId)); + LOGGER.debug("Player already left " + (player != null ? player.getName() : playerId)); return; } - logger.debug("Start leave game: " + player.getName()); + LOGGER.debug("Start leave game: " + player.getName()); player.leave(); if (checkIfGameIsOver()) { // no need to remove objects if only one player is left so the game is over @@ -2532,9 +2530,9 @@ public abstract class GameImpl implements Game, Serializable { try { Integer amount = Integer.parseInt(s[1]); player.setLife(amount, this); - logger.info("Setting player's life: "); + LOGGER.info("Setting player's life: "); } catch (NumberFormatException e) { - logger.fatal("error setting life", e); + LOGGER.fatal("error setting life", e); } }