Fixed various Word of Command bugs, implemented mana pool restore methods

This commit is contained in:
L_J 2018-06-04 14:30:37 +02:00 committed by GitHub
parent 9a5b574c0c
commit cb7c222eb9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 62 additions and 41 deletions

View file

@ -4,11 +4,8 @@ import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.MageObjectReference; import mage.MageObjectReference;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.RestrictionEffect;
import mage.abilities.effects.common.LoseControlOnOtherPlayersControllerEffect;
import mage.cards.Card; import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
@ -18,8 +15,6 @@ import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.players.ManaPool; 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 // 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 manaPool = targetPlayer.getManaPool();
manaPool.setForcedToPay(true); manaPool.setForcedToPay(true);
manaPool.storeMana();
int bookmark = game.bookmarkState(); int bookmark = game.bookmarkState();
if ((card.isLand() && (!targetPlayer.canPlayLand() || !game.getActivePlayerId().equals(targetPlayer.getId()))) 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) { if (wordOfCommand != null) {
wordOfCommand.setCommandedBy(controller.getId()); // You control the player until Word of Command finishes resolving wordOfCommand.setCommandedBy(controller.getId()); // You control the player until Word of Command finishes resolving
} else { } else {

View file

@ -237,7 +237,8 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
@Override @Override
public void assignPayment(Game game, Ability ability, ManaPool pool, Cost costToPay) { 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 // if auto payment is inactive and no mana type was clicked manually - do nothing
return; return;
} }
@ -324,7 +325,9 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
} }
// stop using mana of the clicked mana type // stop using mana of the clicked mana type
pool.lockManaType(); pool.lockManaType();
handleForcedToPayOnlyForCurrentPayment(game, pool, referenceCosts); if (!wasUnlockedManaType) {
handleForcedToPayOnlyForCurrentPayment(game, pool, referenceCosts);
}
} }
private void handleForcedToPayOnlyForCurrentPayment(Game game, ManaPool pool, ManaCosts referenceCosts) { private void handleForcedToPayOnlyForCurrentPayment(Game game, ManaPool pool, ManaCosts referenceCosts) {
@ -336,6 +339,7 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
if (player != null) { if (player != null) {
game.undo(playerId); game.undo(playerId);
this.clearPaid(); this.clearPaid();
player.getManaPool().restoreMana(pool.getPoolBookmark());
game.bookmarkState(); game.bookmarkState();
} }
} }

View file

@ -394,7 +394,7 @@ public interface Game extends MageItem, Serializable {
void playPriority(UUID activePlayerId, boolean resuming); void playPriority(UUID activePlayerId, boolean resuming);
void resetControlAfterSpellResolve(Spell spell); void resetControlAfterSpellResolve(UUID topId);
boolean endTurn(Ability source); boolean endTurn(Ability source);

View file

@ -1395,13 +1395,8 @@ public abstract class GameImpl implements Game, Serializable {
StackObject top = null; StackObject top = null;
try { try {
top = state.getStack().peek(); top = state.getStack().peek();
Spell topSpell = getSpell(top.getId()); top.resolve(this);
if (topSpell != null) { resetControlAfterSpellResolve(top.getId());
top.resolve(this);
resetControlAfterSpellResolve(topSpell);
} else {
top.resolve(this);
}
} finally { } finally {
if (top != null) { 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 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 @Override
public void resetControlAfterSpellResolve(Spell spell) { public void resetControlAfterSpellResolve(UUID topId) {
// for Word of Command // for Word of Command
if (spell.getCommandedBy() != null) { Spell spell = getSpellOrLKIStack(topId);
UUID commandedBy = spell.getCommandedBy(); if (spell != null) {
UUID spellControllerId = null; if (spell.getCommandedBy() != null) {
if (commandedBy.equals(spell.getControllerId())) { UUID commandedBy = spell.getCommandedBy();
spellControllerId = spell.getSpellAbility().getFirstTarget(); // i.e. resolved spell is Word of Command UUID spellControllerId = null;
} else { if (commandedBy.equals(spell.getControllerId())) {
spellControllerId = spell.getControllerId(); // i.e. resolved spell is the target opponent's spell spellControllerId = spell.getSpellAbility().getFirstTarget(); // i.e. resolved spell is Word of Command
} } else {
if (commandedBy != null && spellControllerId != null) { spellControllerId = spell.getControllerId(); // i.e. resolved spell is the target opponent's spell
Player turnController = getPlayer(commandedBy); }
if (turnController != null) { if (commandedBy != null && spellControllerId != null) {
Player targetPlayer = getPlayer(spellControllerId); Player turnController = getPlayer(commandedBy);
if (targetPlayer != null) { if (turnController != null) {
informPlayers(turnController.getLogName() + " lost control over " + targetPlayer.getLogName()); Player targetPlayer = getPlayer(spellControllerId);
turnController.resetOtherTurnsControlled(); if (targetPlayer != null) {
targetPlayer.setGameUnderYourControl(true); informPlayers(turnController.getLogName() + " lost control over " + targetPlayer.getLogName());
turnController.resetOtherTurnsControlled();
targetPlayer.setGameUnderYourControl(true);
}
} }
} }
} }

View file

@ -36,17 +36,12 @@ public class SpellStack extends ArrayDeque<StackObject> {
StackObject top = null; StackObject top = null;
try { try {
top = this.peek(); top = this.peek();
Spell topSpell = getSpell(top.getId()); top.resolve(game);
if (topSpell != null) { game.resetControlAfterSpellResolve(top.getId());
top.resolve(game);
game.resetControlAfterSpellResolve(topSpell);
} else {
top.resolve(game);
}
} finally { } finally {
if (top != null) { if (top != null) {
if (contains(top)) { 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); this.remove(top, game);
} }
} }

View file

@ -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 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 ManaType unlockedManaType; // type of mana that was selected to pay manually
private boolean forcedToPay; // for Word of Command private boolean forcedToPay; // for Word of Command
private final List<ManaPoolItem> poolBookmark = new ArrayList<>(); // mana pool bookmark for rollback purposes
private final Set<ManaType> doNotEmptyManaTypes = new HashSet<>(); private final Set<ManaType> doNotEmptyManaTypes = new HashSet<>();
@ -56,6 +57,9 @@ public class ManaPool implements Serializable {
this.autoPaymentRestricted = pool.autoPaymentRestricted; this.autoPaymentRestricted = pool.autoPaymentRestricted;
this.unlockedManaType = pool.unlockedManaType; this.unlockedManaType = pool.unlockedManaType;
this.forcedToPay = pool.forcedToPay; this.forcedToPay = pool.forcedToPay;
for (ManaPoolItem item : pool.poolBookmark) {
poolBookmark.add(item.copy());
}
this.doNotEmptyManaTypes.addAll(pool.doNotEmptyManaTypes); this.doNotEmptyManaTypes.addAll(pool.doNotEmptyManaTypes);
} }
@ -503,4 +507,28 @@ public class ManaPool implements Serializable {
public UUID getPlayerId() { public UUID getPlayerId() {
return playerId; return playerId;
} }
public void storeMana() {
poolBookmark.clear();
poolBookmark.addAll(getManaItems());
}
public List<ManaPoolItem> getPoolBookmark() {
List<ManaPoolItem> itemsCopy = new ArrayList<>();
for (ManaPoolItem manaItem : poolBookmark) {
itemsCopy.add(manaItem.copy());
}
return itemsCopy;
}
public void restoreMana(List<ManaPoolItem> manaList) {
manaItems.clear();
if (!manaList.isEmpty()) {
List<ManaPoolItem> itemsCopy = new ArrayList<>();
for (ManaPoolItem manaItem : manaList) {
itemsCopy.add(manaItem.copy());
}
manaItems.addAll(itemsCopy);
}
}
} }