* Copy spell - improved support for some cards and abilities (#8074);

This commit is contained in:
Oleg Agafonov 2021-07-31 15:48:57 +04:00
parent 6e0184a38d
commit 530cd627cc
5 changed files with 108 additions and 50 deletions

View file

@ -65,7 +65,6 @@ import mage.util.MessageToClient;
import mage.util.RandomUtil;
import mage.util.functions.CopyApplier;
import mage.watchers.Watcher;
import mage.watchers.Watchers;
import mage.watchers.common.*;
import org.apache.log4j.Logger;
@ -2051,6 +2050,7 @@ public abstract class GameImpl implements Game, Serializable {
// to exist the next time state-based actions are checked.
//
// Copied cards can be stored in GameState.copiedCards or in game state value (until LKI rework)
// Copied cards list contains all parts of split/adventure/mdfc
Set<Card> allCopiedCards = new HashSet<>();
allCopiedCards.addAll(this.getState().getCopiedCards());
Map<String, Object> stateSavedCopiedCards = this.getState().getValues(GameState.COPIED_CARD_KEY);
@ -2060,6 +2060,7 @@ public abstract class GameImpl implements Game, Serializable {
.filter(Objects::nonNull)
.collect(Collectors.toList())
);
Set<Card> copiedCardsToRemove = new HashSet<>();
for (Card copiedCard : allCopiedCards) {
// 1. Zone must be checked from main card only cause mdf parts can have different zones
// (one side on battlefield, another side on outside)
@ -2070,13 +2071,25 @@ public abstract class GameImpl implements Game, Serializable {
Zone zone = state.getZone(copiedCard.getMainCard().getId());
// TODO: remember LKI of copied cards here after LKI rework
switch (zone) {
case BATTLEFIELD:
case OUTSIDE:
case BATTLEFIELD: {
// keep in battlefield
// keep in outside (it's a final zone for all copied cards)
continue;
case STACK:
if (getStack().getStackObject(copiedCard.getId()) != null) {
}
case STACK: {
// copied cards aren't moves and keeps in Stack zone after resolve,
// so it must be moved manually as SBA (see Outside zone change at the end)
MageObject object = getStack().getStackObject(copiedCard.getId());
if (object != null) {
// keep in stack until resolve
continue;
}
case GRAVEYARD:
break;
}
case GRAVEYARD: {
for (Player player : getPlayers().values()) {
if (player.getGraveyard().contains(copiedCard.getId())) {
player.getGraveyard().remove(copiedCard);
@ -2084,7 +2097,9 @@ public abstract class GameImpl implements Game, Serializable {
}
}
break;
case HAND:
}
case HAND: {
for (Player player : getPlayers().values()) {
if (player.getHand().contains(copiedCard.getId())) {
player.getHand().remove(copiedCard);
@ -2092,7 +2107,9 @@ public abstract class GameImpl implements Game, Serializable {
}
}
break;
case LIBRARY:
}
case LIBRARY: {
for (Player player : getPlayers().values()) {
if (player.getLibrary().getCard(copiedCard.getId(), this) != null) {
player.getLibrary().remove(copiedCard.getId(), this);
@ -2100,15 +2117,30 @@ public abstract class GameImpl implements Game, Serializable {
}
}
break;
case EXILED:
}
case EXILED: {
getExile().removeCard(copiedCard, this);
break;
}
case COMMAND:
default: {
break;
}
}
// remove copied card info
this.getState().getCopiedCards().remove(copiedCard);
this.getState().removeValue(GameState.COPIED_CARD_KEY + copiedCard.getId().toString());
// copied card can be removed to Outside
copiedCardsToRemove.add(copiedCard);
}
// real remove
copiedCardsToRemove.forEach(card -> {
card.setZone(Zone.OUTSIDE, this);
this.getState().getCopiedCards().remove(card);
// must keep card in game state as LKI alternative until LKI rework, so don't remove from it
// TODO: change after LKI rework
//this.getState().removeValue(GameState.COPIED_CARD_KEY + copiedCard.getId().toString());
});
List<Permanent> legendary = new ArrayList<>();
List<Permanent> worldEnchantment = new ArrayList<>();

View file

@ -233,7 +233,10 @@ public class Spell extends StackObjectImpl implements Card {
}
}
if (game.getState().getZone(card.getMainCard().getId()) == Zone.STACK) {
if (!isCopy()) {
if (isCopy()) {
// copied spell, only remove from stack
game.getStack().remove(this, game);
} else {
controller.moveCards(card, Zone.GRAVEYARD, ability, game);
}
}
@ -438,7 +441,7 @@ public class Spell extends StackObjectImpl implements Card {
}
}
} else {
// Copied spell, only remove from stack
// copied spell, only remove from stack
game.getStack().remove(this, game);
}
}
@ -847,6 +850,7 @@ public class Spell extends StackObjectImpl implements Card {
@Override
public boolean moveToExile(UUID exileId, String name, Ability source, Game game, List<UUID> appliedEffects) {
if (this.isCopy()) {
// copied spell, only remove from stack
game.getStack().remove(this, game);
return true;
}

View file

@ -4472,7 +4472,7 @@ public abstract class PlayerImpl implements Player, Serializable {
} else if (card instanceof Spell) {
final Spell spell = (Spell) card;
if (spell.isCopy()) {
// Copied spell, only remove from stack
// copied spell, only remove from stack
game.getStack().remove(spell, game);
}
}