Fix DFC copy having both faces

This commit is contained in:
Bug Hunter
2022-02-16 12:04:44 +00:00
committed by Hans Mackowiak
parent 39c49b2315
commit cbf1bdd3a5
19 changed files with 46 additions and 73 deletions

View File

@@ -756,9 +756,9 @@ public class AiController {
} }
// state needs to be switched here so API checks evaluate the right face // state needs to be switched here so API checks evaluate the right face
CardStateName currentState = sa.getCardState() != null && sa.getHostCard().getCurrentStateName() != sa.getCardState().getStateName() && !sa.getHostCard().isInPlay() ? sa.getHostCard().getCurrentStateName() : null; CardStateName currentState = sa.getCardState() != null && sa.getHostCard().getCurrentStateName() != sa.getCardStateName() && !sa.getHostCard().isInPlay() ? sa.getHostCard().getCurrentStateName() : null;
if (currentState != null) { if (currentState != null) {
sa.getHostCard().setState(sa.getCardState().getStateName(), false); sa.getHostCard().setState(sa.getCardStateName(), false);
} }
AiPlayDecision canPlay = canPlaySa(sa); // this is the "heaviest" check, which also sets up targets, defines X, etc. AiPlayDecision canPlay = canPlaySa(sa); // this is the "heaviest" check, which also sets up targets, defines X, etc.

View File

@@ -299,7 +299,7 @@ public class ControlGainAi extends SpellAbilityAi {
final Game game = ai.getGame(); final Game game = ai.getGame();
// Special card logic that is processed elsewhere // Special card logic that is processed elsewhere
if (sa.getParam("AILogic").equals("DonateTargetPerm")) { if (("DonateTargetPerm").equals(sa.getParam("AILogic"))) {
// Donate step 2 - target a donatable permanent. // Donate step 2 - target a donatable permanent.
return SpecialCardAi.Donate.considerDonatingPermanent(ai, sa); return SpecialCardAi.Donate.considerDonatingPermanent(ai, sa);
} }

View File

@@ -186,7 +186,7 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
artIndex = Math.max(artIndex0, IPaperCard.DEFAULT_ART_INDEX); artIndex = Math.max(artIndex0, IPaperCard.DEFAULT_ART_INDEX);
foil = foil0; foil = foil0;
rarity = rarity0; rarity = rarity0;
artist = (artist0 != null ? TextUtil.normalizeText(artist0) : IPaperCard.NO_ARTIST_NAME); artist = artist0 != null ? TextUtil.normalizeText(artist0) : IPaperCard.NO_ARTIST_NAME;
collectorNumber = (collectorNumber0 != null) && (collectorNumber0.length() > 0) ? collectorNumber0 : IPaperCard.NO_COLLECTOR_NUMBER; collectorNumber = (collectorNumber0 != null) && (collectorNumber0.length() > 0) ? collectorNumber0 : IPaperCard.NO_COLLECTOR_NUMBER;
// If the user changes the language this will make cards sort by the old language until they restart the game. // If the user changes the language this will make cards sort by the old language until they restart the game.
// This is a good tradeoff // This is a good tradeoff

View File

@@ -1601,15 +1601,11 @@ public class AbilityUtils {
if (sa.hasParam("ForgetOtherTargets")) { if (sa.hasParam("ForgetOtherTargets")) {
host.clearRemembered(); host.clearRemembered();
} }
for (final GameObject o : sa.getTargets()) { host.addRemembered(sa.getTargets());
host.addRemembered(o);
}
} }
if (sa.hasParam("ImprintTargets") && sa.usesTargeting()) { if (sa.hasParam("ImprintTargets") && sa.usesTargeting()) {
for (final Card c : sa.getTargets().getTargetCards()) { host.addImprintedCards(sa.getTargets().getTargetCards());
host.addImprintedCard(c);
}
} }
if (sa.hasParam("RememberCostMana")) { if (sa.hasParam("RememberCostMana")) {

View File

@@ -142,9 +142,7 @@ public class ChooseSourceEffect extends SpellAbilityEffect {
} }
host.setChosenCards(chosen); host.setChosenCards(chosen);
if (sa.hasParam("RememberChosen")) { if (sa.hasParam("RememberChosen")) {
for (final Card rem : chosen) { host.addRemembered(chosen);
host.addRemembered(rem);
}
} }
} }
} }

View File

@@ -168,9 +168,7 @@ public class DigEffect extends SpellAbilityEffect {
if (!toReveal.isEmpty()) { if (!toReveal.isEmpty()) {
game.getAction().reveal(toReveal, cont); game.getAction().reveal(toReveal, cont);
if (sa.hasParam("RememberRevealed")) { if (sa.hasParam("RememberRevealed")) {
for (final Card one : toReveal) { host.addRemembered(toReveal);
host.addRemembered(one);
}
} }
} }
} }
@@ -329,7 +327,7 @@ public class DigEffect extends SpellAbilityEffect {
} }
List<Card> chosen = new ArrayList<>(); List<Card> chosen = new ArrayList<>();
int max = anyNumber ? valid.size() : Math.min(valid.size(),destZone1ChangeNum); int max = anyNumber ? valid.size() : Math.min(valid.size(), destZone1ChangeNum);
int min = (anyNumber || optional) ? 0 : max; int min = (anyNumber || optional) ? 0 : max;
if (max > 0) { // if max is 0 don't make a choice if (max > 0) { // if max is 0 don't make a choice
chosen = chooser.getController().chooseEntitiesForEffect(valid, min, max, delayedReveal, sa, prompt, p, null); chosen = chooser.getController().chooseEntitiesForEffect(valid, min, max, delayedReveal, sa, prompt, p, null);

View File

@@ -29,10 +29,7 @@ public class DigUntilEffect extends SpellAbilityEffect {
protected String getStackDescription(SpellAbility sa) { protected String getStackDescription(SpellAbility sa) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
String desc = "Card"; String desc = sa.getParamOrDefault("ValidDescription", "Card");
if (sa.hasParam("ValidDescription")) {
desc = sa.getParam("ValidDescription");
}
int untilAmount = 1; int untilAmount = 1;
if (sa.hasParam("Amount")) { if (sa.hasParam("Amount")) {
@@ -57,7 +54,6 @@ public class DigUntilEffect extends SpellAbilityEffect {
final ZoneType found = ZoneType.smartValueOf(sa.getParam("FoundDestination")); final ZoneType found = ZoneType.smartValueOf(sa.getParam("FoundDestination"));
final ZoneType revealed = ZoneType.smartValueOf(sa.getParam("RevealedDestination")); final ZoneType revealed = ZoneType.smartValueOf(sa.getParam("RevealedDestination"));
if (found != null) { if (found != null) {
sb.append(untilAmount > 1 ? "those cards" : "that card"); sb.append(untilAmount > 1 ? "those cards" : "that card");
sb.append(" "); sb.append(" ");

View File

@@ -198,9 +198,7 @@ public class EffectEffect extends SpellAbilityEffect {
// Set Remembered // Set Remembered
if (rememberList != null) { if (rememberList != null) {
for (final Object o : rememberList) { eff.addRemembered(rememberList);
eff.addRemembered(o);
}
if (sa.hasParam("ForgetOnMoved")) { if (sa.hasParam("ForgetOnMoved")) {
addForgetOnMovedTrigger(eff, sa.getParam("ForgetOnMoved")); addForgetOnMovedTrigger(eff, sa.getParam("ForgetOnMoved"));
if (!"Stack".equals(sa.getParam("ForgetOnMoved"))) { if (!"Stack".equals(sa.getParam("ForgetOnMoved"))) {
@@ -219,9 +217,7 @@ public class EffectEffect extends SpellAbilityEffect {
// Set Imprinted // Set Imprinted
if (effectImprinted != null) { if (effectImprinted != null) {
for (final Card c : AbilityUtils.getDefinedCards(hostCard, effectImprinted, sa)) { eff.addImprintedCards(AbilityUtils.getDefinedCards(hostCard, effectImprinted, sa));
eff.addImprintedCard(c);
}
} }
// Note counters on defined // Note counters on defined

View File

@@ -79,9 +79,7 @@ public class FlipOntoBattlefieldEffect extends SpellAbilityEffect {
} }
// Remember whatever was hit // Remember whatever was hit
for (Card c : hit) { host.addRemembered(hit);
host.addRemembered(c);
}
} }
@Override @Override

View File

@@ -92,9 +92,7 @@ public class MultiplePilesEffect extends SpellAbilityEffect {
if (randomChosen) { if (randomChosen) {
for (Entry<Player, List<CardCollectionView>> ev : record.entrySet()) { for (Entry<Player, List<CardCollectionView>> ev : record.entrySet()) {
CardCollectionView chosen = Aggregates.random(ev.getValue()); CardCollectionView chosen = Aggregates.random(ev.getValue());
for (Card c : chosen) { source.addRemembered(chosen);
source.addRemembered(c);
}
} }
SpellAbility sub = sa.getAdditionalAbility("ChosenPile"); SpellAbility sub = sa.getAdditionalAbility("ChosenPile");

View File

@@ -193,13 +193,9 @@ public class SubgameEffect extends SpellAbilityEffect {
if (sa.hasParam("RememberPlayers")) { if (sa.hasParam("RememberPlayers")) {
final String param = sa.getParam("RememberPlayers"); final String param = sa.getParam("RememberPlayers");
if (param.equals("Win")) { if (param.equals("Win")) {
for (Player p : winPlayers) { hostCard.addRemembered(winPlayers);
hostCard.addRemembered(p);
}
} else if (param.equals("NotWin")) { } else if (param.equals("NotWin")) {
for (Player p : notWinPlayers) { hostCard.addRemembered(notWinPlayers);
hostCard.addRemembered(p);
}
} }
} }

View File

@@ -117,9 +117,7 @@ public class VoteEffect extends SpellAbilityEffect {
if (sa.hasParam("Tied") && mostVotes.size() > 1) { if (sa.hasParam("Tied") && mostVotes.size() > 1) {
subAbs.add(sa.getParam("Tied")); subAbs.add(sa.getParam("Tied"));
} else if (sa.hasParam("VoteSubAbility")) { } else if (sa.hasParam("VoteSubAbility")) {
for (final Object o : mostVotes) { host.addRemembered(mostVotes);
host.addRemembered(o);
}
subAbs.add(sa.getParam("VoteSubAbility")); subAbs.add(sa.getParam("VoteSubAbility"));
} else { } else {
for (Object type : mostVotes) { for (Object type : mostVotes) {

View File

@@ -784,13 +784,13 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
return false; return false;
} }
CardStateName destState = transformCard.backside ? CardStateName.Original : CardStateName.Transformed;
// below only when in play // below only when in play
if (!isInPlay()) { if (!isInPlay()) {
return true; return true;
} }
CardStateName destState = transformCard.backside ? CardStateName.Original : CardStateName.Transformed;
// use Original State for the transform check // use Original State for the transform check
if (!transformCard.getOriginalState(destState).getType().isPermanent()) { if (!transformCard.getOriginalState(destState).getType().isPermanent()) {
return false; return false;
@@ -887,7 +887,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
public final boolean hasAlternateState() { public final boolean hasAlternateState() {
// Note: Since FaceDown state is created lazily (whereas previously // Note: Since FaceDown state is created lazily (whereas previously
// it was always created), adjust threshold based on its existence. // it was always created), adjust threshold based on its existence.
int threshold = (states.containsKey(CardStateName.FaceDown) ? 2 : 1); int threshold = states.containsKey(CardStateName.FaceDown) ? 2 : 1;
int numStates = states.keySet().size(); int numStates = states.keySet().size();
@@ -6451,6 +6451,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
return c.getCardForUi(); return c.getCardForUi();
} }
//allow special cards to override this function to return another card for the sake of UI logic
public Card getCardForUi() {
return this;
}
public IPaperCard getPaperCard() { public IPaperCard getPaperCard() {
IPaperCard cp = paperCard; IPaperCard cp = paperCard;
if (cp != null) { if (cp != null) {
@@ -6486,11 +6491,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
staticCommandList.add(objects); staticCommandList.add(objects);
} }
//allow special cards to override this function to return another card for the sake of UI logic
public Card getCardForUi() {
return this;
}
public String getOracleText() { public String getOracleText() {
CardRules rules = cardRules; CardRules rules = cardRules;
if (copiedPermanent != null) { //return oracle text of copied permanent if applicable if (copiedPermanent != null) { //return oracle text of copied permanent if applicable

View File

@@ -96,12 +96,8 @@ public class CardFactory {
out.setAttachedCards(in.getAttachedCards()); out.setAttachedCards(in.getAttachedCards());
out.setEntityAttachedTo(in.getEntityAttachedTo()); out.setEntityAttachedTo(in.getEntityAttachedTo());
for (final Object o : in.getRemembered()) { out.addRemembered(in.getRemembered());
out.addRemembered(o); out.addImprintedCards(in.getImprintedCards());
}
for (final Card o : in.getImprintedCards()) {
out.addImprintedCard(o);
}
out.setCommander(in.isRealCommander()); out.setCommander(in.isRealCommander());
//out.setFaceDown(in.isFaceDown()); //out.setFaceDown(in.isFaceDown());
@@ -125,11 +121,9 @@ public class CardFactory {
private final static Card copySpellHost(final SpellAbility sourceSA, final SpellAbility targetSA, Player controller) { private final static Card copySpellHost(final SpellAbility sourceSA, final SpellAbility targetSA, Player controller) {
final Card source = sourceSA.getHostCard(); final Card source = sourceSA.getHostCard();
final Card original = targetSA.getHostCard(); final Card original = targetSA.getHostCard();
final Card c = copyCard(original, true); final Game game = source.getGame();
final Card c = new Card(game.nextCardId(), original.getPaperCard(), game);
// clear remember/imprint for copied spells copyCopiableCharacteristics(original, c);
c.clearRemembered();
c.clearImprintedCards();
if (sourceSA.hasParam("NonLegendary")) { if (sourceSA.hasParam("NonLegendary")) {
c.removeType(CardType.Supertype.Legendary); c.removeType(CardType.Supertype.Legendary);
@@ -524,8 +518,6 @@ public class CardFactory {
public static void copyState(final Card from, final CardStateName fromState, final Card to, public static void copyState(final Card from, final CardStateName fromState, final Card to,
final CardStateName toState, boolean updateView) { final CardStateName toState, boolean updateView) {
// copy characteristics not associated with a state // copy characteristics not associated with a state
to.setBasePowerString(from.getBasePowerString());
to.setBaseToughnessString(from.getBaseToughnessString());
to.setText(from.getSpellText()); to.setText(from.getSpellText());
// get CardCharacteristics for desired state // get CardCharacteristics for desired state
@@ -753,7 +745,7 @@ public class CardFactory {
if (sa.hasParam("GainThisAbility") && (sa instanceof SpellAbility)) { if (sa.hasParam("GainThisAbility") && (sa instanceof SpellAbility)) {
SpellAbility root = ((SpellAbility) sa).getRootAbility(); SpellAbility root = ((SpellAbility) sa).getRootAbility();
if (root.isTrigger() && root.getTrigger() != null) { if (root.isTrigger()) {
state.addTrigger(root.getTrigger().copy(out, false)); state.addTrigger(root.getTrigger().copy(out, false));
} else if (root.isReplacementAbility()) { } else if (root.isReplacementAbility()) {
state.addReplacementEffect(root.getReplacementEffect().copy(out, false)); state.addReplacementEffect(root.getReplacementEffect().copy(out, false));

View File

@@ -173,8 +173,7 @@ public abstract class CostPartWithList extends CostPart {
} }
// copy table because the original get cleaned after the cost is done // copy table because the original get cleaned after the cost is done
final CardZoneTable copyTable = new CardZoneTable(); final CardZoneTable copyTable = new CardZoneTable(table);
copyTable.putAll(table);
copyTable.triggerChangesZoneAll(payer.getGame(), ability); copyTable.triggerChangesZoneAll(payer.getGame(), ability);
} }

View File

@@ -195,8 +195,7 @@ public class CostPutCounter extends CostPartWithList {
return; return;
} }
GameEntityCounterTable tempTable = new GameEntityCounterTable(); GameEntityCounterTable tempTable = new GameEntityCounterTable(counterTable);
tempTable.putAll(counterTable);
tempTable.replaceCounterEffect(ability.getHostCard().getGame(), ability, effect); tempTable.replaceCounterEffect(ability.getHostCard().getGame(), ability, effect);
} }

View File

@@ -19,6 +19,8 @@ package forge.game.spellability;
import java.util.Map; import java.util.Map;
import forge.card.CardStateName;
import forge.game.IHasSVars;
import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityFactory;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
@@ -103,6 +105,14 @@ public final class AbilitySub extends SpellAbility implements java.io.Serializab
effect.resolve(this); effect.resolve(this);
} }
@Override
protected IHasSVars getSVarFallback() {
if (getCardState() != null && getCardStateName().equals(CardStateName.RightSplit)) {
return getCardState();
}
return super.getSVarFallback();
}
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public final Object clone() { public final Object clone() {

View File

@@ -174,11 +174,11 @@ public abstract class Spell extends SpellAbility implements java.io.Serializable
} }
source.turnFaceDownNoUpdate(); source.turnFaceDownNoUpdate();
lkicheck = true; lkicheck = true;
} else if (getCardState() != null && source.getCurrentStateName() != getCardStateName()) { } else if (getCardState() != null && source.getCurrentStateName() != getCardStateName() && getHostCard().getState(getCardStateName()) != null) {
if (!source.isLKI()) { if (!source.isLKI()) {
source = CardUtil.getLKICopy(source); source = CardUtil.getLKICopy(source);
} }
CardStateName stateName = getCardState().getStateName(); CardStateName stateName = getCardStateName();
if (!source.hasState(stateName)) { if (!source.hasState(stateName)) {
source.addAlternateState(stateName, false); source.addAlternateState(stateName, false);
source.getState(stateName).copyFrom(getHostCard().getState(stateName), true); source.getState(stateName).copyFrom(getHostCard().getState(stateName), true);

View File

@@ -1104,8 +1104,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
clone.counterTable = new GameEntityCounterTable(counterTable); clone.counterTable = new GameEntityCounterTable(counterTable);
} }
if (changeZoneTable != null) { if (changeZoneTable != null) {
clone.changeZoneTable = new CardZoneTable(); clone.changeZoneTable = new CardZoneTable(changeZoneTable);
clone.changeZoneTable.putAll(changeZoneTable);
} }
clone.payingMana = Lists.newArrayList(payingMana); clone.payingMana = Lists.newArrayList(payingMana);