From 69e239d2ed4117bb399fd2f8b2fa95d4cfa47652 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 30 Jul 2017 08:54:37 +0200 Subject: [PATCH 1/6] Xmage 1.4.25V0 (update because of Log problem) --- .../src/mage/player/human/HumanPlayer.java | 1 - .../test/cards/single/FracturingGustTest.java | 50 +++++++++++++++++++ .../duel/CommanderReplaceEffectTest.java | 3 +- .../mage/game/permanent/PermanentImpl.java | 5 +- 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index 3c46ffe05f..81ee232f83 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -188,7 +188,6 @@ public class HumanPlayer extends PlayerImpl { synchronized (response) { try { response.wait(); - logger.info("Got response from player: " + response.toString()); } catch (InterruptedException ex) { logger.error("Response error for player " + getName() + " gameId: " + game.getId(), ex); } finally { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/FracturingGustTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/FracturingGustTest.java index 7389b0856a..9ae98477f5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/FracturingGustTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/FracturingGustTest.java @@ -85,4 +85,54 @@ public class FracturingGustTest extends CardTestPlayerBase { assertLife(playerB, 20); } + + @Test + public void testWithIndestructible() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); + // Destroy all artifacts and enchantments. You gain 2 life for each permanent destroyed this way. + addCard(Zone.HAND, playerA, "Fracturing Gust", 1); + + // Flying + // Indestructible (Damage and effects that say "destroy" don't destroy this creature.) + addCard(Zone.BATTLEFIELD, playerB, "Darksteel Gargoyle", 1); // Artifact Creature - Gargoyle + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fracturing Gust"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Fracturing Gust", 1); + assertPermanentCount(playerB, "Darksteel Gargoyle", 1); + + // No life because Darksteel Gargoyle is Indestructible + assertLife(playerA, 20); + assertLife(playerB, 20); + + } + + @Test + public void testWithRestInPeace() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); + // Destroy all artifacts and enchantments. You gain 2 life for each permanent destroyed this way. + addCard(Zone.HAND, playerA, "Fracturing Gust", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Ornithopter", 1); // Artifact Creature 2/2 + + // When Rest in Peace enters the battlefield, exile all cards from all graveyards. + // If a card or token would be put into a graveyard from anywhere, exile it instead. + addCard(Zone.BATTLEFIELD, playerB, "Rest in Peace"); // Artifact + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fracturing Gust"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Fracturing Gust", 1); + assertGraveyardCount(playerB, "Ornithopter", 0); + assertExileCount(playerB, "Ornithopter", 1); + + assertLife(playerA, 24); + assertLife(playerB, 20); + + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/duel/CommanderReplaceEffectTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/duel/CommanderReplaceEffectTest.java index bda7e66293..71c9e14da8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/commander/duel/CommanderReplaceEffectTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/commander/duel/CommanderReplaceEffectTest.java @@ -59,7 +59,8 @@ public class CommanderReplaceEffectTest extends CardTestCommanderDuelBase { addCard(Zone.HAND, playerB, "Phyrexian Rebirth", 1); // Daxos of Meletis can't be blocked by creatures with power 3 or greater. - // Whenever Daxos of Meletis deals combat damage to a player, exile the top card of that player's library. You gain life equal to that card's converted mana cost. Until end of turn, you may cast that card and you may spend mana as though it were mana of any color to cast it. + // Whenever Daxos of Meletis deals combat damage to a player, exile the top card of that player's library. You gain life equal to that card's converted mana cost. + // Until end of turn, you may cast that card and you may spend mana as though it were mana of any color to cast it. castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Daxos of Meletis"); // Destroy all creatures, then put an X/X colorless Horror artifact creature token onto the battlefield, where X is the number of creatures destroyed this way. diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index 2cd47edadc..86ed0b59fd 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -27,6 +27,7 @@ */ package mage.game.permanent; +import java.util.*; import mage.MageObject; import mage.MageObjectReference; import mage.ObjectColor; @@ -55,8 +56,6 @@ import mage.players.Player; import mage.util.GameLog; import mage.util.ThreadLocalStringBuilder; -import java.util.*; - /** * @author BetaSteward_at_googlemail.com */ @@ -972,8 +971,8 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } } game.fireEvent(GameEvent.getEvent(EventType.DESTROYED_PERMANENT, objectId, sourceId, controllerId)); - return true; } + return true; } return false; } From 12f094e85483f4c8ecc46d7aa35925120ed9edc3 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 30 Jul 2017 12:30:47 +0200 Subject: [PATCH 2/6] * Oath of Nissa - Fixed that the revealed and not selected cards were not always put on the bottom of the library. --- Mage.Sets/src/mage/cards/o/OathOfNissa.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/cards/o/OathOfNissa.java b/Mage.Sets/src/mage/cards/o/OathOfNissa.java index 987a3921ac..dc82ce4dd4 100644 --- a/Mage.Sets/src/mage/cards/o/OathOfNissa.java +++ b/Mage.Sets/src/mage/cards/o/OathOfNissa.java @@ -122,8 +122,8 @@ class OathOfNissaEffect extends OneShotEffect { topCards.remove(card); } } - controller.putCardsOnBottomOfLibrary(topCards, game, source, true); } + controller.putCardsOnBottomOfLibrary(topCards, game, source, true); } return true; } From 7b168a9d5e4e9ca94c7fdad71f5aa4c2d0542fb1 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 30 Jul 2017 18:50:36 +0200 Subject: [PATCH 3/6] * Minds Aglow - Fixed that payed mana can be undone if X was set to a too high value. --- .../src/main/java/mage/client/MageFrame.java | 2 +- Mage.Sets/src/mage/cards/m/MindsAglow.java | 22 ++++++++++--------- Mage/src/main/java/mage/game/stack/Spell.java | 14 +++++++----- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index 035ca1bfb8..8fa1cdebb4 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -1281,7 +1281,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { hideTables(); SessionHandler.disconnect(false); if (errorCall) { - UserRequestMessage message = new UserRequestMessage("Connection lost", "The connection to server was lost. Reconnect to " + currentConnection.getHost() + '?'); + UserRequestMessage message = new UserRequestMessage("Connection lost", "The connection to server was lost. Reconnect?"); message.setButton1("No", null); message.setButton2("Yes", PlayerAction.CLIENT_RECONNECT); showUserRequestDialog(message); diff --git a/Mage.Sets/src/mage/cards/m/MindsAglow.java b/Mage.Sets/src/mage/cards/m/MindsAglow.java index 4810ea9247..6b32184ec4 100644 --- a/Mage.Sets/src/mage/cards/m/MindsAglow.java +++ b/Mage.Sets/src/mage/cards/m/MindsAglow.java @@ -47,8 +47,7 @@ import mage.players.Player; public class MindsAglow extends CardImpl { public MindsAglow(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}"); // Join forces - Starting with you, each player may pay any amount of mana. Each player draws X cards, where X is the total amount of mana paid this way. this.getSpellAbility().addEffect(new MindsAglowEffect()); @@ -66,44 +65,44 @@ public class MindsAglow extends CardImpl { } class MindsAglowEffect extends OneShotEffect { - + public MindsAglowEffect() { super(Outcome.Detriment); this.staticText = "Join forces - Starting with you, each player may pay any amount of mana. Each player draws X cards, where X is the total amount of mana paid this way"; } - + public MindsAglowEffect(final MindsAglowEffect effect) { super(effect); } - + @Override public MindsAglowEffect copy() { return new MindsAglowEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { int xSum = 0; xSum += playerPaysXGenericMana(controller, source, game); - for(UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { if (!Objects.equals(playerId, controller.getId())) { Player player = game.getPlayer(playerId); if (player != null) { xSum += playerPaysXGenericMana(player, source, game); - + } } } if (xSum > 0) { - for(UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { player.drawCards(xSum, game); } } - + } // prevent undo controller.resetStoredBookmark(game); @@ -120,6 +119,9 @@ class MindsAglowEffect extends OneShotEffect { if (xValue > 0) { Cost cost = new GenericManaCost(xValue); payed = cost.pay(source, game, source.getSourceId(), player.getId(), false, null); + if (!payed) { + game.undo(player.getId()); + } } else { payed = true; } diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index bfa8c67bf8..288f757d9f 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -69,8 +69,8 @@ import mage.util.SubTypeList; */ public class Spell extends StackObjImpl implements Card { - private final List spellCards = new ArrayList<>(); private final List spellAbilities = new ArrayList<>(); + private final List spellCards = new ArrayList<>(); private final Card card; private final ObjectColor color; @@ -108,7 +108,6 @@ public class Spell extends StackObjImpl implements Card { this.controllerId = controllerId; this.fromZone = fromZone; this.countered = false; - this.doneActivatingManaAbilities = false; } public Spell(final Spell spell) { @@ -129,13 +128,18 @@ public class Spell extends StackObjImpl implements Card { } else { this.card = spell.card.copy(); } - this.controllerId = spell.controllerId; + this.fromZone = spell.fromZone; - this.copiedSpell = spell.copiedSpell; - this.faceDown = spell.faceDown; this.color = spell.color.copy(); this.frameColor = spell.color.copy(); this.frameStyle = spell.frameStyle; + + this.controllerId = spell.controllerId; + this.copiedSpell = spell.copiedSpell; + this.faceDown = spell.faceDown; + this.countered = spell.countered; + this.resolving = spell.resolving; + this.doneActivatingManaAbilities = spell.doneActivatingManaAbilities; } From 33438fff3b471f6cbffa428671a6ba087f61db03 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 30 Jul 2017 19:18:11 +0200 Subject: [PATCH 4/6] * Jeleva, Nephalia's Scourge - Fixed that the card exile did not work, if Jeleva already left battlefield as the ETB triggered ability resolved. --- .../mage/cards/j/JelevaNephaliasScourge.java | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java b/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java index 24f7facf6f..eec959ce32 100644 --- a/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java +++ b/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java @@ -31,6 +31,7 @@ import java.util.HashMap; import java.util.Map; import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -43,6 +44,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SuperType; import mage.constants.WatcherScope; +import mage.constants.Zone; import mage.filter.common.FilterInstantOrSorceryCard; import mage.game.ExileZone; import mage.game.Game; @@ -61,7 +63,7 @@ import mage.watchers.Watcher; public class JelevaNephaliasScourge extends CardImpl { public JelevaNephaliasScourge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}{R}"); addSuperType(SuperType.LEGENDARY); this.subtype.add("Vampire"); this.subtype.add("Wizard"); @@ -107,27 +109,19 @@ class JelevaNephaliasScourgeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Card sourceCard = game.getCard(source.getSourceId()); - if (controller != null && sourceCard != null) { - JelevaNephaliasWatcher watcher = (JelevaNephaliasWatcher) game.getState().getWatchers().get(JelevaNephaliasWatcher.class.getSimpleName(), source.getSourceId()); - if (watcher != null) { - int xValue = watcher.getManaSpentToCastLastTime(sourceCard.getZoneChangeCounter(game) - 1); - if (xValue > 0) { - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - int cardsToExile = Math.min(player.getLibrary().size(), xValue); - for (int i = 0; i < cardsToExile; i++) { - Card card = player.getLibrary().removeFromTop(game); - if (card != null) { - card.moveToExile(CardUtil.getCardExileZoneId(game, source), sourceCard.getIdName(), source.getSourceId(), game); - } - } - } + MageObject sourceObject = source.getSourceObject(game); + JelevaNephaliasWatcher watcher = (JelevaNephaliasWatcher) game.getState().getWatchers().get(JelevaNephaliasWatcher.class.getSimpleName(), source.getSourceId()); + if (controller != null && sourceObject != null && watcher != null) { + int xValue = watcher.getManaSpentToCastLastTime(sourceObject.getZoneChangeCounter(game) - 1); + if (xValue > 0) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + player.moveCards(player.getLibrary().getTopCards(game, xValue), Zone.EXILED, source, game); } } - return true; } + return true; } return false; } From 286d08452e01da4fa1260de331c1d2d48caefa7d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 30 Jul 2017 19:39:28 +0200 Subject: [PATCH 5/6] * Jeleva, Nephalia's Scourge - Fixed that the ETB triggered ability also exiled card if Jeleva was e.g. copied by a Clone card. --- .../mage/cards/j/JelevaNephaliasScourge.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java b/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java index eec959ce32..3db1324d72 100644 --- a/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java +++ b/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java @@ -110,9 +110,9 @@ class JelevaNephaliasScourgeEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); - JelevaNephaliasWatcher watcher = (JelevaNephaliasWatcher) game.getState().getWatchers().get(JelevaNephaliasWatcher.class.getSimpleName(), source.getSourceId()); + JelevaNephaliasWatcher watcher = (JelevaNephaliasWatcher) game.getState().getWatchers().get(JelevaNephaliasWatcher.class.getSimpleName()); if (controller != null && sourceObject != null && watcher != null) { - int xValue = watcher.getManaSpentToCastLastTime(sourceObject.getZoneChangeCounter(game) - 1); + int xValue = watcher.getManaSpentToCastLastTime(sourceObject.getId(), sourceObject.getZoneChangeCounter(game) - 1); if (xValue > 0) { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); @@ -167,10 +167,10 @@ class JelevaNephaliasCastEffect extends OneShotEffect { class JelevaNephaliasWatcher extends Watcher { - private final Map manaSpendToCast = new HashMap<>(); // cast + private final Map manaSpendToCast = new HashMap<>(); // cast public JelevaNephaliasWatcher() { - super(JelevaNephaliasWatcher.class.getSimpleName(), WatcherScope.CARD); + super(JelevaNephaliasWatcher.class.getSimpleName(), WatcherScope.GAME); } public JelevaNephaliasWatcher(final JelevaNephaliasWatcher watcher) { @@ -184,22 +184,22 @@ class JelevaNephaliasWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.SPELL_CAST && event.getSourceId().equals(sourceId)) { + // Watcher saves all casts becaus of possible Clone cards that copy Jeleva + if (event.getType() == GameEvent.EventType.SPELL_CAST) { if (!game.getStack().isEmpty()) { for (StackObject stackObject : game.getStack()) { - if (stackObject instanceof Spell && ((Spell) stackObject).getSourceId().equals(sourceId)) { - Card card = game.getCard(sourceId); - if (!manaSpendToCast.containsValue(card.getZoneChangeCounter(game))) { - manaSpendToCast.put(card.getZoneChangeCounter(game), ((Spell) stackObject).getSpellAbility().getManaCostsToPay().convertedManaCost()); - } + if (stackObject instanceof Spell) { + Spell spell = (Spell) stackObject; + manaSpendToCast.putIfAbsent(spell.getSourceId().toString() + spell.getCard().getZoneChangeCounter(game), + spell.getSpellAbility().getManaCostsToPay().convertedManaCost()); } } } } } - public int getManaSpentToCastLastTime(int zoneChangeCounter) { - return manaSpendToCast.getOrDefault(zoneChangeCounter, 0); + public int getManaSpentToCastLastTime(UUID sourceId, int zoneChangeCounter) { + return manaSpendToCast.getOrDefault(sourceId.toString() + zoneChangeCounter, 0); } @Override From 76390714f57b7a7a4c6d604b7997495c8818c943 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 30 Jul 2017 19:52:56 +0200 Subject: [PATCH 6/6] * Duplicant - Fixed that the target creatures attributes were not copied if the target was not exiled (e.g. Commander going to command zone). --- Mage.Sets/src/mage/cards/d/Duplicant.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Mage.Sets/src/mage/cards/d/Duplicant.java b/Mage.Sets/src/mage/cards/d/Duplicant.java index 60e1118972..096f112bfc 100644 --- a/Mage.Sets/src/mage/cards/d/Duplicant.java +++ b/Mage.Sets/src/mage/cards/d/Duplicant.java @@ -29,6 +29,7 @@ package mage.cards.d; import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -101,13 +102,13 @@ class DuplicantExileTargetEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); - Permanent sourcePermananent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - if (sourcePermananent != null) { - sourcePermananent.imprint(permanent.getId(), game); - sourcePermananent.addInfo("imprint", new StringBuilder("[Imprinted card - ").append(permanent.getName()).append(']').toString(), game); + MageObject sourceObject = source.getSourceObject(game); + if (permanent != null && sourceObject instanceof Permanent) { + if (permanent.moveToExile(null, null, source.getSourceId(), game)) { + ((Permanent) sourceObject).imprint(permanent.getId(), game); + ((Permanent) sourceObject).addInfo("imprint", "[Imprinted card - " + permanent.getName() + ']', game); } - return permanent.moveToExile(null, null, source.getSourceId(), game); + return true; } return false;