diff --git a/Mage.Sets/src/mage/cards/w/WordOfCommand.java b/Mage.Sets/src/mage/cards/w/WordOfCommand.java index 19da321434..54c3a66c79 100644 --- a/Mage.Sets/src/mage/cards/w/WordOfCommand.java +++ b/Mage.Sets/src/mage/cards/w/WordOfCommand.java @@ -4,11 +4,8 @@ import java.util.UUID; import mage.MageObject; import mage.MageObjectReference; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RestrictionEffect; -import mage.abilities.effects.common.LoseControlOnOtherPlayersControllerEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -18,8 +15,6 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.players.ManaPool; @@ -101,6 +96,7 @@ class WordOfCommandEffect extends OneShotEffect { // and only if mana they produce is spent to activate other mana abilities of lands he or she controls and/or play that card ManaPool manaPool = targetPlayer.getManaPool(); manaPool.setForcedToPay(true); + manaPool.storeMana(); int bookmark = game.bookmarkState(); if ((card.isLand() && (!targetPlayer.canPlayLand() || !game.getActivePlayerId().equals(targetPlayer.getId()))) @@ -127,7 +123,7 @@ class WordOfCommandEffect extends OneShotEffect { } } - Spell wordOfCommand = game.getSpell(sourceObject.getId()); + Spell wordOfCommand = game.getSpell(source.getSourceId()); if (wordOfCommand != null) { wordOfCommand.setCommandedBy(controller.getId()); // You control the player until Word of Command finishes resolving } else { diff --git a/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java b/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java index 90a8b7e4ec..73739a4348 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java @@ -237,7 +237,8 @@ public class ManaCostsImpl extends ArrayList implements M @Override public void assignPayment(Game game, Ability ability, ManaPool pool, Cost costToPay) { - if (!pool.isAutoPayment() && pool.getUnlockedManaType() == null) { + boolean wasUnlockedManaType = (pool.getUnlockedManaType() != null); + if (!pool.isAutoPayment() && !wasUnlockedManaType) { // if auto payment is inactive and no mana type was clicked manually - do nothing return; } @@ -324,7 +325,9 @@ public class ManaCostsImpl extends ArrayList implements M } // stop using mana of the clicked mana type pool.lockManaType(); - handleForcedToPayOnlyForCurrentPayment(game, pool, referenceCosts); + if (!wasUnlockedManaType) { + handleForcedToPayOnlyForCurrentPayment(game, pool, referenceCosts); + } } private void handleForcedToPayOnlyForCurrentPayment(Game game, ManaPool pool, ManaCosts referenceCosts) { @@ -336,6 +339,7 @@ public class ManaCostsImpl extends ArrayList implements M if (player != null) { game.undo(playerId); this.clearPaid(); + player.getManaPool().restoreMana(pool.getPoolBookmark()); game.bookmarkState(); } } diff --git a/Mage/src/main/java/mage/game/Game.java b/Mage/src/main/java/mage/game/Game.java index 21418c8a0c..2f7af72d29 100644 --- a/Mage/src/main/java/mage/game/Game.java +++ b/Mage/src/main/java/mage/game/Game.java @@ -394,7 +394,7 @@ public interface Game extends MageItem, Serializable { void playPriority(UUID activePlayerId, boolean resuming); - void resetControlAfterSpellResolve(Spell spell); + void resetControlAfterSpellResolve(UUID topId); boolean endTurn(Ability source); diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 350ff0047a..55c1872ab1 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1395,13 +1395,8 @@ public abstract class GameImpl implements Game, Serializable { StackObject top = null; try { top = state.getStack().peek(); - Spell topSpell = getSpell(top.getId()); - if (topSpell != null) { - top.resolve(this); - resetControlAfterSpellResolve(topSpell); - } else { - top.resolve(this); - } + top.resolve(this); + resetControlAfterSpellResolve(top.getId()); } finally { if (top != null) { state.getStack().remove(top, this); // seems partly redundant because move card from stack to grave is already done and the stack removed @@ -1417,24 +1412,27 @@ public abstract class GameImpl implements Game, Serializable { } @Override - public void resetControlAfterSpellResolve(Spell spell) { + public void resetControlAfterSpellResolve(UUID topId) { // for Word of Command - if (spell.getCommandedBy() != null) { - UUID commandedBy = spell.getCommandedBy(); - UUID spellControllerId = null; - if (commandedBy.equals(spell.getControllerId())) { - spellControllerId = spell.getSpellAbility().getFirstTarget(); // i.e. resolved spell is Word of Command - } else { - spellControllerId = spell.getControllerId(); // i.e. resolved spell is the target opponent's spell - } - if (commandedBy != null && spellControllerId != null) { - Player turnController = getPlayer(commandedBy); - if (turnController != null) { - Player targetPlayer = getPlayer(spellControllerId); - if (targetPlayer != null) { - informPlayers(turnController.getLogName() + " lost control over " + targetPlayer.getLogName()); - turnController.resetOtherTurnsControlled(); - targetPlayer.setGameUnderYourControl(true); + Spell spell = getSpellOrLKIStack(topId); + if (spell != null) { + if (spell.getCommandedBy() != null) { + UUID commandedBy = spell.getCommandedBy(); + UUID spellControllerId = null; + if (commandedBy.equals(spell.getControllerId())) { + spellControllerId = spell.getSpellAbility().getFirstTarget(); // i.e. resolved spell is Word of Command + } else { + spellControllerId = spell.getControllerId(); // i.e. resolved spell is the target opponent's spell + } + if (commandedBy != null && spellControllerId != null) { + Player turnController = getPlayer(commandedBy); + if (turnController != null) { + Player targetPlayer = getPlayer(spellControllerId); + if (targetPlayer != null) { + informPlayers(turnController.getLogName() + " lost control over " + targetPlayer.getLogName()); + turnController.resetOtherTurnsControlled(); + targetPlayer.setGameUnderYourControl(true); + } } } } diff --git a/Mage/src/main/java/mage/game/stack/SpellStack.java b/Mage/src/main/java/mage/game/stack/SpellStack.java index ecf91441b4..060be88c1f 100644 --- a/Mage/src/main/java/mage/game/stack/SpellStack.java +++ b/Mage/src/main/java/mage/game/stack/SpellStack.java @@ -36,17 +36,12 @@ public class SpellStack extends ArrayDeque { StackObject top = null; try { top = this.peek(); - Spell topSpell = getSpell(top.getId()); - if (topSpell != null) { - top.resolve(game); - game.resetControlAfterSpellResolve(topSpell); - } else { - top.resolve(game); - } + top.resolve(game); + game.resetControlAfterSpellResolve(top.getId()); } finally { if (top != null) { if (contains(top)) { - logger.warn("StackObject was still on the stack after resoving" + top.getName()); + logger.warn("StackObject was still on the stack after resolving" + top.getName()); this.remove(top, game); } } diff --git a/Mage/src/main/java/mage/players/ManaPool.java b/Mage/src/main/java/mage/players/ManaPool.java index f927460970..67dbe5fea9 100644 --- a/Mage/src/main/java/mage/players/ManaPool.java +++ b/Mage/src/main/java/mage/players/ManaPool.java @@ -36,6 +36,7 @@ public class ManaPool implements Serializable { private boolean autoPaymentRestricted; // auto payment from mana pool: true - if auto Payment is on, it will only pay if one kind of mana is in the pool private ManaType unlockedManaType; // type of mana that was selected to pay manually private boolean forcedToPay; // for Word of Command + private final List poolBookmark = new ArrayList<>(); // mana pool bookmark for rollback purposes private final Set doNotEmptyManaTypes = new HashSet<>(); @@ -56,6 +57,9 @@ public class ManaPool implements Serializable { this.autoPaymentRestricted = pool.autoPaymentRestricted; this.unlockedManaType = pool.unlockedManaType; this.forcedToPay = pool.forcedToPay; + for (ManaPoolItem item : pool.poolBookmark) { + poolBookmark.add(item.copy()); + } this.doNotEmptyManaTypes.addAll(pool.doNotEmptyManaTypes); } @@ -503,4 +507,28 @@ public class ManaPool implements Serializable { public UUID getPlayerId() { return playerId; } + + public void storeMana() { + poolBookmark.clear(); + poolBookmark.addAll(getManaItems()); + } + + public List getPoolBookmark() { + List itemsCopy = new ArrayList<>(); + for (ManaPoolItem manaItem : poolBookmark) { + itemsCopy.add(manaItem.copy()); + } + return itemsCopy; + } + + public void restoreMana(List manaList) { + manaItems.clear(); + if (!manaList.isEmpty()) { + List itemsCopy = new ArrayList<>(); + for (ManaPoolItem manaItem : manaList) { + itemsCopy.add(manaItem.copy()); + } + manaItems.addAll(itemsCopy); + } + } }