Temporary clones: restore Remembered/Imprinted

This commit is contained in:
Bug Hunter
2021-04-20 04:00:41 +00:00
committed by Michael Kamensky
parent 98600e9a19
commit b7a475cc0a
10 changed files with 71 additions and 23 deletions

View File

@@ -1029,7 +1029,7 @@ public class PlayerControllerAi extends PlayerController {
*/
if (sa.isMayChooseNewTargets() && !sa.setupTargets()) {
if (sa.isSpell()) {
sa.getHostCard().ceaseToExist(false);
player.getGame().getAction().ceaseToExist(sa.getHostCard(), false);
}
continue;
}

View File

@@ -785,12 +785,12 @@ public class Game {
// unattach all "Enchant Player"
c.removeAttachedTo(p);
if (c.getOwner().equals(p)) {
for(Card cc : cards) {
for (Card cc : cards) {
cc.removeImprintedCard(c);
cc.removeEncodedCard(c);
cc.removeRemembered(c);
}
c.ceaseToExist(false);
getAction().ceaseToExist(c, false);
// CR 603.2f owner of trigger source lost game
triggerHandler.clearDelayedTrigger(c);
} else {

View File

@@ -919,6 +919,38 @@ public class GameAction {
}
}
public void ceaseToExist(Card c, boolean skipTrig) {
final String origin = c.getZone().getZoneType().name();
c.getZone().remove(c);
c.setZone(null);
// CR 603.6c other players LTB triggers should work
if (!skipTrig) {
game.addChangeZoneLKIInfo(c);
Card lki = null;
CardCollectionView lastBattlefield = game.getLastStateBattlefield();
int idx = lastBattlefield.indexOf(c);
if (idx != -1) {
lki = lastBattlefield.get(idx);
}
if (lki == null) {
lki = CardUtil.getLKICopy(c);
}
if (game.getCombat() != null) {
game.getCombat().removeFromCombat(c);
game.getCombat().saveLKI(lki);
}
game.getTriggerHandler().registerActiveLTBTrigger(lki);
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(c);
runParams.put(AbilityKey.CardLKI, lki);
runParams.put(AbilityKey.Origin, origin);
game.getTriggerHandler().runTrigger(TriggerType.ChangesZone, runParams, false);
game.getTriggerHandler().runWaitingTriggers();
}
}
// Temporarily disable (if mode = true) actively checking static abilities.
private void setHoldCheckingStaticAbilities(boolean mode) {
holdCheckingStaticAbilities = mode;

View File

@@ -3,6 +3,8 @@ package forge.game.ability.effects;
import java.util.Arrays;
import java.util.List;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.GameCommand;
@@ -13,12 +15,14 @@ import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardFactory;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.event.GameEventCardStatsChanged;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.CardTranslation;
import forge.util.Localizer;
import forge.util.collect.FCollection;
public class CloneEffect extends SpellAbilityEffect {
// TODO update this method
@@ -139,10 +143,6 @@ public class CloneEffect extends SpellAbilityEffect {
tgtCard.updateStateForView();
//Clear Remembered and Imprint lists
tgtCard.clearRemembered();
tgtCard.clearImprintedCards();
// check if clone is now an Aura that needs to be attached
if (tgtCard.isAura() && !tgtCard.isInZone(ZoneType.Battlefield)) {
AttachEffect.attachAuraOnIndirectEnterBattlefield(tgtCard);
@@ -150,12 +150,23 @@ public class CloneEffect extends SpellAbilityEffect {
if (sa.hasParam("Duration")) {
final Card cloneCard = tgtCard;
// if clone is temporary, target needs old values back after
final Iterable<Card> clonedImprinted = new CardCollection(tgtCard.getImprintedCards());
final Iterable<Object> clonedRemembered = new FCollection<>(tgtCard.getRemembered());
final GameCommand unclone = new GameCommand() {
private static final long serialVersionUID = -78375985476256279L;
@Override
public void run() {
if (cloneCard.removeCloneState(ts)) {
// remove values gained while being cloned
cloneCard.clearImprintedCards();
cloneCard.clearRemembered();
// restore original Remembered and Imprinted, ignore cards from players who lost
cloneCard.addImprintedCards(Iterables.filter(clonedImprinted, Predicates.not(CardPredicates.inZone(ZoneType.None))));
cloneCard.addRemembered(Iterables.filter(clonedRemembered, Player.class));
cloneCard.addRemembered(Iterables.filter(Iterables.filter(clonedRemembered, Card.class), CardPredicates.ownerLives()));
cloneCard.updateStateForView();
game.fireEvent(new GameEventCardStatsChanged(cloneCard));
}
@@ -176,9 +187,15 @@ public class CloneEffect extends SpellAbilityEffect {
sa.getHostCard().addFacedownCommand(unclone);
}
}
//Clear Remembered and Imprint lists
tgtCard.clearRemembered();
tgtCard.clearImprintedCards();
if (sa.hasParam("RememberCloneOrigin")) {
tgtCard.addRemembered(cardToCopy);
}
game.fireEvent(new GameEventCardStatsChanged(tgtCard));
} // cloneResolve

View File

@@ -6762,17 +6762,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
}
}
public void ceaseToExist(boolean skipTrig) {
// CR 603.6c other players LTB triggers should work
if (skipTrig) {
getZone().remove(this);
setZone(getOwner().getZone(ZoneType.None));
}
else {
game.getAction().moveTo(ZoneType.None, this, null);
}
}
public void forceTurnFaceUp() {
getGame().getTriggerHandler().suppressMode(TriggerType.TurnFaceUp);
turnFaceUp(false, false, null);

View File

@@ -68,6 +68,15 @@ public final class CardPredicates {
};
}
public static final Predicate<Card> ownerLives() {
return new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return !c.getOwner().hasLost();
}
};
}
public static final Predicate<Card> isType(final String cardType) {
return new Predicate<Card>() {
@Override

View File

@@ -2357,7 +2357,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
public void rollback() {
for (Card c : rollbackEffects) {
c.ceaseToExist(true);
c.getGame().getAction().ceaseToExist(c, true);
}
rollbackEffects.clear();
}

View File

@@ -319,7 +319,9 @@ public class TriggerHandler {
checkStatics |= type.equals("Battlefield");
} else {
final ZoneType zone = (ZoneType) runParams.get(AbilityKey.Destination);
checkStatics |= zone.equals(ZoneType.Battlefield);
if (zone != null) {
checkStatics |= zone.equals(ZoneType.Battlefield);
}
}
}

View File

@@ -586,7 +586,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
}
if (source.isCopiedSpell() && source.isInZone(ZoneType.Stack)) {
source.ceaseToExist(true);
game.getAction().ceaseToExist(source, true);
return;
}

View File

@@ -2840,8 +2840,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
if (c == null) {
continue;
}
c.getZone().remove(c);
c.ceaseToExist(true);
c.getGame().getAction().ceaseToExist(c, true);
StringBuilder sb = new StringBuilder();
sb.append(p).append(" removes ").append(c).append(" from game due to Dev Cheats.");