Modal double-faced cards - fixed game error on usage with some replacement effects (example: Diluvian Primordial, closes #12176) (#12184)

This commit is contained in:
Susucre 2024-04-25 21:40:57 +02:00 committed by GitHub
parent 1ae48593a8
commit 36d6547bf8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 339 additions and 38 deletions

View file

@ -1,6 +1,5 @@
package mage.abilities.effects.common;
import mage.ApprovingObject;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.ContinuousEffect;
@ -115,8 +114,7 @@ public class MayCastTargetCardEffect extends OneShotEffect {
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
boolean noMana = manaAdjustment == CastManaAdjustment.WITHOUT_PAYING_MANA_COST;
controller.cast(controller.chooseAbilityForCast(card, game, noMana),
game, noMana, new ApprovingObject(source, game));
CardUtil.castSingle(controller, source, game, card, noMana, null);
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
} else {
// TODO: support (and add tests!) for the non-NONE manaAdjustment

View file

@ -2,6 +2,7 @@ package mage.abilities.effects.common.replacement;
import mage.abilities.Ability;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.Card;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
@ -50,9 +51,21 @@ public class ThatSpellGraveyardExileReplacementEffect extends ReplacementEffectI
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
return zEvent.getToZone() == Zone.GRAVEYARD
&& zEvent.getTargetId().equals(((FixedTarget) getTargetPointer()).getTarget())
&& ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1
== game.getState().getZoneChangeCounter(zEvent.getTargetId());
if (zEvent.getToZone() != Zone.GRAVEYARD) {
return false;
}
Card cardMoving = game.getCard(zEvent.getTargetId());
Card cardTarget = game.getCard(((FixedTarget) getTargetPointer()).getTarget());
if (cardMoving == null || cardTarget == null) {
return false;
}
// for MDFC.
Card mainCardMoving = cardMoving.getMainCard();
Card mainCardTarget = cardTarget.getMainCard();
return mainCardMoving != null
&& mainCardTarget != null
&& mainCardMoving.getId().equals(mainCardTarget.getId())
&& ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1
== game.getState().getZoneChangeCounter(mainCardMoving.getId());
}
}

View file

@ -56,7 +56,8 @@ public abstract class AdventureCard extends CardImpl {
@Override
public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List<UUID> appliedEffects) {
if (super.moveToZone(toZone, source, game, flag, appliedEffects)) {
game.getState().setZone(getSpellCard().getId(), toZone);
Zone currentZone = game.getState().getZone(getId());
game.getState().setZone(getSpellCard().getId(), currentZone);
return true;
}
return false;

View file

@ -116,7 +116,8 @@ public abstract class ModalDoubleFacedCard extends CardImpl implements CardWithH
@Override
public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List<UUID> appliedEffects) {
if (super.moveToZone(toZone, source, game, flag, appliedEffects)) {
setSideZones(toZone, game);
Zone currentZone = game.getState().getZone(getId());
setSideZones(currentZone, game);
return true;
}
return false;
@ -131,7 +132,8 @@ public abstract class ModalDoubleFacedCard extends CardImpl implements CardWithH
@Override
public boolean moveToExile(UUID exileId, String name, Ability source, Game game, List<UUID> appliedEffects) {
if (super.moveToExile(exileId, name, source, game, appliedEffects)) {
setSideZones(Zone.EXILED, game);
Zone currentZone = game.getState().getZone(getId());
setSideZones(currentZone, game);
return true;
}
return false;
@ -233,10 +235,12 @@ public abstract class ModalDoubleFacedCard extends CardImpl implements CardWithH
case MODAL_RIGHT:
return this.rightHalfCard.cast(game, fromZone, ability, controllerId);
default:
if (this.leftHalfCard.getSpellAbility() != null)
if (this.leftHalfCard.getSpellAbility() != null) {
this.leftHalfCard.getSpellAbility().setControllerId(controllerId);
if (this.rightHalfCard.getSpellAbility() != null)
}
if (this.rightHalfCard.getSpellAbility() != null) {
this.rightHalfCard.getSpellAbility().setControllerId(controllerId);
}
return super.cast(game, fromZone, ability, controllerId);
}
}

View file

@ -77,8 +77,9 @@ public abstract class SplitCard extends CardImpl implements CardWithHalves {
@Override
public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List<UUID> appliedEffects) {
if (super.moveToZone(toZone, source, game, flag, appliedEffects)) {
game.getState().setZone(getLeftHalfCard().getId(), toZone);
game.getState().setZone(getRightHalfCard().getId(), toZone);
Zone currentZone = game.getState().getZone(getId());
game.getState().setZone(getLeftHalfCard().getId(), currentZone);
game.getState().setZone(getRightHalfCard().getId(), currentZone);
return true;
}
return false;

View file

@ -1494,6 +1494,10 @@ public final class CardUtil {
}
public static void castSingle(Player player, Ability source, Game game, Card card, ManaCostsImpl<ManaCost> manaCost) {
castSingle(player, source, game, card, false, manaCost);
}
public static void castSingle(Player player, Ability source, Game game, Card card, boolean noMana, ManaCostsImpl<ManaCost> manaCost) {
// handle split-cards
if (card instanceof SplitCard) {
SplitCardHalf leftHalfCard = ((SplitCard) card).getLeftHalfCard();
@ -1560,8 +1564,8 @@ public final class CardUtil {
}
// cast it
player.cast(player.chooseAbilityForCast(card.getMainCard(), game, false),
game, false, new ApprovingObject(source, game));
player.cast(player.chooseAbilityForCast(card.getMainCard(), game, noMana),
game, noMana, new ApprovingObject(source, game));
// turn off effect after cast on every possible card-face
if (card instanceof SplitCard) {