mirror of
https://github.com/correl/mage.git
synced 2024-12-27 03:00:13 +00:00
Fixed various Word of Command bugs, implemented mana pool restore methods
This commit is contained in:
parent
9a5b574c0c
commit
cb7c222eb9
6 changed files with 62 additions and 41 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue