[TDM] Implement omen mechanic (#13501)

* Abstract AdventureCard to SingleFaceSplitCard

* Fix AdventureCardSpellImpl

* Finish converting adventure card and adventure spell

* Update Brightcap Badger

change finalize call to adventure card

* Update Darksteel Monolith

being cast from hand condition referencing AdventureCardSpell

* Update Tlincalli Hunter

exiled creature condition referencing AdventureCardSpell

* Update Twice Upon a Time

finalizeAdventure called from Adventure card

* Finish abstracting Adventure

missed some more references to adventure cards

* Implement Omen cards

* Implement Dirgur Island Dragon

* Missed some adventureSpellName references

* OmenCardSpell had wrong comma symbol

* Add tests for Omen Cards

* Rename two part card components

change from SingleFaceSplitCard to CardWithSpellOption

* Update comments and variable name
This commit is contained in:
Jmlundeen 2025-04-08 07:54:18 -05:00 committed by GitHub
parent e3937e31c1
commit 0df5f17603
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 637 additions and 264 deletions

View file

@ -123,6 +123,7 @@ public class ModernCardRenderer extends CardRenderer {
public static final Color ERROR_COLOR = new Color(255, 0, 255); public static final Color ERROR_COLOR = new Color(255, 0, 255);
static String SUB_TYPE_ADVENTURE = "Adventure"; static String SUB_TYPE_ADVENTURE = "Adventure";
static String SUB_TYPE_OMEN = "Omen";
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Layout metrics for modern border cards // Layout metrics for modern border cards
@ -168,8 +169,8 @@ public class ModernCardRenderer extends CardRenderer {
// Processed mana cost string // Processed mana cost string
protected String manaCostString; protected String manaCostString;
// Is an adventure // Is an adventure or omen
protected boolean isAdventure = false; protected boolean isCardWithSpellOption = false;
public ModernCardRenderer(CardView card) { public ModernCardRenderer(CardView card) {
// Pass off to parent // Pass off to parent
@ -179,12 +180,13 @@ public class ModernCardRenderer extends CardRenderer {
manaCostString = ManaSymbols.getClearManaCost(cardView.getManaCostStr()); manaCostString = ManaSymbols.getClearManaCost(cardView.getManaCostStr());
if (cardView.isSplitCard()) { if (cardView.isSplitCard()) {
isAdventure = cardView.getRightSplitTypeLine().contains(SUB_TYPE_ADVENTURE); isCardWithSpellOption = cardView.getRightSplitTypeLine().contains(SUB_TYPE_ADVENTURE)
|| cardView.getRightSplitTypeLine().contains(SUB_TYPE_OMEN);
} }
} }
protected boolean isAdventure() { protected boolean isCardWithSpellOption() {
return isAdventure; return isCardWithSpellOption;
} }
@Override @Override
@ -660,7 +662,7 @@ public class ModernCardRenderer extends CardRenderer {
drawRulesText(g, textboxKeywords, textboxRules, drawRulesText(g, textboxKeywords, textboxRules,
contentWidth / 2 + totalContentInset + 4, totalContentInset + boxHeight + 2, contentWidth / 2 + totalContentInset + 4, totalContentInset + boxHeight + 2,
contentWidth / 2 - 8, typeLineY - totalContentInset - boxHeight - 6, false); contentWidth / 2 - 8, typeLineY - totalContentInset - boxHeight - 6, false);
} else if (isAdventure) { } else if (isCardWithSpellOption) {
drawRulesText(g, textboxKeywords, textboxRules, drawRulesText(g, textboxKeywords, textboxRules,
contentWidth / 2 + totalContentInset + 4, typeLineY + boxHeight + 2, contentWidth / 2 + totalContentInset + 4, typeLineY + boxHeight + 2,
contentWidth / 2 - 8, cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3, false); contentWidth / 2 - 8, cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3, false);

View file

@ -56,7 +56,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
private boolean isAftermath = false; private boolean isAftermath = false;
private static String trimAdventure(String rule) { private static String trimAdventure(String rule) {
if (rule.startsWith("Adventure")) { if (rule.startsWith("Adventure") || rule.startsWith("Omen")) {
return rule.substring(rule.lastIndexOf("—") + 8); return rule.substring(rule.lastIndexOf("—") + 8);
} }
return rule; return rule;
@ -71,7 +71,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
rightHalf.color = new ObjectColor(cardView.getRightSplitCostsStr()); rightHalf.color = new ObjectColor(cardView.getRightSplitCostsStr());
leftHalf.color = new ObjectColor(cardView.getLeftSplitCostsStr()); leftHalf.color = new ObjectColor(cardView.getLeftSplitCostsStr());
if (isAdventure()) { if (isCardWithSpellOption()) {
List<String> trimmedRules = new ArrayList<>(); List<String> trimmedRules = new ArrayList<>();
for (String rule : view.getRightSplitRules()) { for (String rule : view.getRightSplitRules()) {
trimmedRules.add(trimAdventure(rule)); trimmedRules.add(trimAdventure(rule));
@ -95,7 +95,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
// they "rotate" in opposite directions making consquence and normal split cards // they "rotate" in opposite directions making consquence and normal split cards
// have the "right" vs "left" as the top half. // have the "right" vs "left" as the top half.
// Adventures are treated differently and not rotated at all. // Adventures are treated differently and not rotated at all.
if (isAdventure()) { if (isCardWithSpellOption()) {
manaCostString = leftHalf.manaCostString; manaCostString = leftHalf.manaCostString;
textboxKeywords = leftHalf.keywords; textboxKeywords = leftHalf.keywords;
textboxRules = leftHalf.rules; textboxRules = leftHalf.rules;
@ -159,7 +159,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
protected void drawBackground(Graphics2D g) { protected void drawBackground(Graphics2D g) {
if (cardView.isFaceDown()) { if (cardView.isFaceDown()) {
drawCardBackTexture(g); drawCardBackTexture(g);
} if (isAdventure()) { } if (isCardWithSpellOption()) {
super.drawBackground(g); super.drawBackground(g);
} else { } else {
{ // Left half background (top of the card) { // Left half background (top of the card)
@ -204,7 +204,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
@Override @Override
protected void drawArt(Graphics2D g) { protected void drawArt(Graphics2D g) {
if (isAdventure) { if (isCardWithSpellOption) {
super.drawArt(g); super.drawArt(g);
} else if (artImage != null) { } else if (artImage != null) {
if (isAftermath()) { if (isAftermath()) {
@ -318,7 +318,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
@Override @Override
protected void drawFrame(Graphics2D g, CardPanelAttributes attribs, BufferedImage image, boolean lessOpaqueRulesTextBox) { protected void drawFrame(Graphics2D g, CardPanelAttributes attribs, BufferedImage image, boolean lessOpaqueRulesTextBox) {
if (isAdventure()) { if (isCardWithSpellOption()) {
super.drawFrame(g, attribs, image, lessOpaqueRulesTextBox); super.drawFrame(g, attribs, image, lessOpaqueRulesTextBox);
CardPanelAttributes adventureAttribs = new CardPanelAttributes( CardPanelAttributes adventureAttribs = new CardPanelAttributes(

View file

@ -432,21 +432,21 @@ public class CardView extends SimpleCardView {
fullCardName = mainCard.getLeftHalfCard().getName() + MockCard.MODAL_DOUBLE_FACES_NAME_SEPARATOR + mainCard.getRightHalfCard().getName(); fullCardName = mainCard.getLeftHalfCard().getName() + MockCard.MODAL_DOUBLE_FACES_NAME_SEPARATOR + mainCard.getRightHalfCard().getName();
this.manaCostLeftStr = mainCard.getLeftHalfCard().getManaCostSymbols(); this.manaCostLeftStr = mainCard.getLeftHalfCard().getManaCostSymbols();
this.manaCostRightStr = mainCard.getRightHalfCard().getManaCostSymbols(); this.manaCostRightStr = mainCard.getRightHalfCard().getManaCostSymbols();
} else if (card instanceof AdventureCard) { } else if (card instanceof CardWithSpellOption) {
this.isSplitCard = true; this.isSplitCard = true;
AdventureCard adventureCard = ((AdventureCard) card); CardWithSpellOption mainCard = ((CardWithSpellOption) card);
leftSplitName = adventureCard.getName(); leftSplitName = mainCard.getName();
leftSplitCostsStr = String.join("", adventureCard.getManaCostSymbols()); leftSplitCostsStr = String.join("", mainCard.getManaCostSymbols());
leftSplitRules = adventureCard.getSharedRules(game); leftSplitRules = mainCard.getSharedRules(game);
leftSplitTypeLine = getCardTypeLine(game, adventureCard); leftSplitTypeLine = getCardTypeLine(game, mainCard);
AdventureCardSpell adventureCardSpell = adventureCard.getSpellCard(); SpellOptionCard splitCardSpell = mainCard.getSpellCard();
rightSplitName = adventureCardSpell.getName(); rightSplitName = splitCardSpell.getName();
rightSplitCostsStr = String.join("", adventureCardSpell.getManaCostSymbols()); rightSplitCostsStr = String.join("", splitCardSpell.getManaCostSymbols());
rightSplitRules = adventureCardSpell.getRules(game); rightSplitRules = splitCardSpell.getRules(game);
rightSplitTypeLine = getCardTypeLine(game, adventureCardSpell); rightSplitTypeLine = getCardTypeLine(game, splitCardSpell);
fullCardName = adventureCard.getName() + MockCard.ADVENTURE_NAME_SEPARATOR + adventureCardSpell.getName(); fullCardName = mainCard.getName() + MockCard.CARD_WITH_SPELL_OPTION_NAME_SEPARATOR + splitCardSpell.getName();
this.manaCostLeftStr = adventureCard.getManaCostSymbols(); this.manaCostLeftStr = mainCard.getManaCostSymbols();
this.manaCostRightStr = adventureCardSpell.getManaCostSymbols(); this.manaCostRightStr = splitCardSpell.getManaCostSymbols();
} else if (card instanceof MockCard) { } else if (card instanceof MockCard) {
// deck editor cards // deck editor cards
fullCardName = ((MockCard) card).getFullName(true); fullCardName = ((MockCard) card).getFullName(true);

View file

@ -52,7 +52,7 @@ public final class BrightcapBadger extends AdventureCard {
// Fungus Frolic // Fungus Frolic
// Create two 1/1 green Saproling creature tokens. // Create two 1/1 green Saproling creature tokens.
this.getSpellCard().getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), 2)); this.getSpellCard().getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), 2));
this.getSpellCard().finalizeAdventure(); this.finalizeAdventure();
} }
private BrightcapBadger(final BrightcapBadger card) { private BrightcapBadger(final BrightcapBadger card) {

View file

@ -54,7 +54,7 @@ enum IsBeingCastFromHandCondition implements Condition {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
MageObject object = game.getObject(source); MageObject object = game.getObject(source);
if (object instanceof SplitCardHalf || object instanceof AdventureCardSpell || object instanceof ModalDoubleFacedCardHalf) { if (object instanceof SplitCardHalf || object instanceof SpellOptionCard || object instanceof ModalDoubleFacedCardHalf) {
UUID mainCardId = ((Card) object).getMainCard().getId(); UUID mainCardId = ((Card) object).getMainCard().getId();
object = game.getObject(mainCardId); object = game.getObject(mainCardId);
} }

View file

@ -0,0 +1,52 @@
package mage.cards.d;
import mage.MageInt;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.TapTargetEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.WardAbility;
import mage.cards.CardSetInfo;
import mage.cards.OmenCard;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author Jmlundeen
*/
public final class DirgurIslandDragon extends OmenCard {
public DirgurIslandDragon(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.INSTANT}, "{5}{U}", "Skimming Strike", "{1}{U}");
this.subtype.add(SubType.DRAGON);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
// Flying
this.addAbility(FlyingAbility.getInstance());
// Ward {2}
this.addAbility(new WardAbility(new ManaCostsImpl<>("{2}")));
// Skimming Strike
// Tap up to one target creature. Draw a card.
this.getSpellCard().getSpellAbility().addEffect(new TapTargetEffect());
this.getSpellCard().getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1));
this.getSpellCard().getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1));
this.finalizeOmen();
}
private DirgurIslandDragon(final DirgurIslandDragon card) {
super(card);
}
@Override
public DirgurIslandDragon copy() {
return new DirgurIslandDragon(this);
}
}

View file

@ -65,7 +65,7 @@ enum ExiledCreatureSpellCondition implements Condition {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
MageObject object = game.getObject(source); MageObject object = game.getObject(source);
if (object instanceof SplitCardHalf || object instanceof AdventureCardSpell || object instanceof ModalDoubleFacedCardHalf) { if (object instanceof SplitCardHalf || object instanceof SpellOptionCard || object instanceof ModalDoubleFacedCardHalf) {
UUID mainCardId = ((Card) object).getMainCard().getId(); UUID mainCardId = ((Card) object).getMainCard().getId();
object = game.getObject(mainCardId); object = game.getObject(mainCardId);
} }

View file

@ -47,7 +47,7 @@ public final class TwiceUponATime extends AdventureCard {
// Unlikely Meeting // Unlikely Meeting
// Search your library for a Doctor card, reveal it, put it into your hand, then shuffle. // Search your library for a Doctor card, reveal it, put it into your hand, then shuffle.
this.getSpellCard().getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter2), true)); this.getSpellCard().getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter2), true));
this.getSpellCard().finalizeAdventure(); this.finalizeAdventure();
} }
private TwiceUponATime(final TwiceUponATime card) { private TwiceUponATime(final TwiceUponATime card) {

View file

@ -67,6 +67,7 @@ public final class TarkirDragonstorm extends ExpansionSet {
cards.add(new SetCardInfo("Delta Bloodflies", 77, Rarity.COMMON, mage.cards.d.DeltaBloodflies.class)); cards.add(new SetCardInfo("Delta Bloodflies", 77, Rarity.COMMON, mage.cards.d.DeltaBloodflies.class));
cards.add(new SetCardInfo("Descendant of Storms", 8, Rarity.UNCOMMON, mage.cards.d.DescendantOfStorms.class)); cards.add(new SetCardInfo("Descendant of Storms", 8, Rarity.UNCOMMON, mage.cards.d.DescendantOfStorms.class));
cards.add(new SetCardInfo("Devoted Duelist", 104, Rarity.COMMON, mage.cards.d.DevotedDuelist.class)); cards.add(new SetCardInfo("Devoted Duelist", 104, Rarity.COMMON, mage.cards.d.DevotedDuelist.class));
cards.add(new SetCardInfo("Dirgur Island Dragon", 40, Rarity.COMMON, mage.cards.d.DirgurIslandDragon.class));
cards.add(new SetCardInfo("Dismal Backwater", 254, Rarity.COMMON, mage.cards.d.DismalBackwater.class)); cards.add(new SetCardInfo("Dismal Backwater", 254, Rarity.COMMON, mage.cards.d.DismalBackwater.class));
cards.add(new SetCardInfo("Dispelling Exhale", 41, Rarity.COMMON, mage.cards.d.DispellingExhale.class)); cards.add(new SetCardInfo("Dispelling Exhale", 41, Rarity.COMMON, mage.cards.d.DispellingExhale.class));
cards.add(new SetCardInfo("Dracogenesis", 105, Rarity.MYTHIC, mage.cards.d.Dracogenesis.class)); cards.add(new SetCardInfo("Dracogenesis", 105, Rarity.MYTHIC, mage.cards.d.Dracogenesis.class));

View file

@ -0,0 +1,77 @@
package org.mage.test.cards.cost.omen;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class OmenCardsTest extends CardTestPlayerBase {
@Test
public void testDirgurIslandDragonShuffle() {
setStrictChooseMode(true);
skipInitShuffling();
removeAllCardsFromLibrary(playerA);
addCard(Zone.HAND, playerA, "Dirgur Island Dragon");
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
addCard(Zone.BATTLEFIELD, playerB, "Bear Cub");
addCard(Zone.LIBRARY, playerA, "Mountain");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Skimming Strike", "Bear Cub");
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLibraryCount(playerA, "Dirgur Island Dragon", 1);
assertTapped("Bear Cub", true);
assertHandCount(playerA, 1);
}
@Test
public void testDirgurIslandDragonShuffleAndPlay() {
setStrictChooseMode(true);
skipInitShuffling();
removeAllCardsFromLibrary(playerA);
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
addCard(Zone.BATTLEFIELD, playerB, "Bear Cub");
addCard(Zone.LIBRARY, playerA, "Mountain");
addCard(Zone.HAND, playerA, "Dirgur Island Dragon");
castSpell(2, PhaseStep.BEGIN_COMBAT, playerA, "Skimming Strike", "Bear Cub");
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Dirgur Island Dragon");
setStopAt(3, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, "Dirgur Island Dragon", 1);
}
@Test
public void testCounteredInGraveyard() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
addCard(Zone.BATTLEFIELD, playerB,"Island", 4);
addCard(Zone.BATTLEFIELD, playerB,"Bear Cub");
addCard(Zone.HAND, playerA, "Dirgur Island Dragon");
addCard(Zone.HAND, playerB, "Counterspell");
castSpell(2, PhaseStep.BEGIN_COMBAT, playerA, "Skimming Strike", "Bear Cub");
castSpell(2, PhaseStep.BEGIN_COMBAT, playerB, "Counterspell", "Skimming Strike", "Skimming Strike", StackClause.WHILE_ON_STACK);
attack(2, playerB, "Bear Cub");
setStopAt(2, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerA, "Dirgur Island Dragon", 1);
assertLife(playerA, 20 - 2);
}
@Test
public void testGraveyardCast() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
addCard(Zone.BATTLEFIELD, playerA, "Kess, Dissident Mage");
addCard(Zone.GRAVEYARD, playerA, "Dirgur Island Dragon");
addCard(Zone.BATTLEFIELD, playerB, "Bear Cub");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Skimming Strike", "Bear Cub");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertLibraryCount(playerA, "Dirgur Island Dragon", 1);
}
}

View file

@ -6,8 +6,8 @@ import mage.MageObject;
import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.costs.mana.VariableManaCost;
import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.FlashAbility;
import mage.cards.AdventureCardSpell;
import mage.cards.Card; import mage.cards.Card;
import mage.cards.SpellOptionCard;
import mage.cards.SplitCard; import mage.cards.SplitCard;
import mage.constants.*; import mage.constants.*;
import mage.game.Game; import mage.game.Game;
@ -99,7 +99,7 @@ public class SpellAbility extends ActivatedAbilityImpl {
// forced to cast (can be part id or main id) // forced to cast (can be part id or main id)
Set<UUID> idsToCheck = new HashSet<>(); Set<UUID> idsToCheck = new HashSet<>();
idsToCheck.add(object.getId()); idsToCheck.add(object.getId());
if (object instanceof Card && !(object instanceof AdventureCardSpell)) { if (object instanceof Card && !(object instanceof SpellOptionCard)) {
idsToCheck.add(((Card) object).getMainCard().getId()); idsToCheck.add(((Card) object).getMainCard().getId());
} }
for (UUID idToCheck : idsToCheck) { for (UUID idToCheck : idsToCheck) {

View file

@ -4,7 +4,7 @@ package mage.abilities.condition.common;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.condition.Condition; import mage.abilities.condition.Condition;
import mage.cards.AdventureCardSpell; import mage.cards.SpellOptionCard;
import mage.cards.Card; import mage.cards.Card;
import mage.cards.ModalDoubleFacedCardHalf; import mage.cards.ModalDoubleFacedCardHalf;
import mage.cards.SplitCardHalf; import mage.cards.SplitCardHalf;
@ -20,7 +20,7 @@ public enum IsBeingCastFromHandCondition implements Condition {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
MageObject object = game.getObject(source); MageObject object = game.getObject(source);
if (object instanceof SplitCardHalf || object instanceof AdventureCardSpell || object instanceof ModalDoubleFacedCardHalf) { if (object instanceof SplitCardHalf || object instanceof SpellOptionCard || object instanceof ModalDoubleFacedCardHalf) {
UUID mainCardId = ((Card) object).getMainCard().getId(); UUID mainCardId = ((Card) object).getMainCard().getId();
object = game.getObject(mainCardId); object = game.getObject(mainCardId);
} }

View file

@ -549,9 +549,9 @@ public class ContinuousEffects implements Serializable {
// rules: // rules:
// 708.4. In every zone except the stack, the characteristics of a split card are those of its two halves combined. // 708.4. In every zone except the stack, the characteristics of a split card are those of its two halves combined.
idToCheck = ((SplitCardHalf) objectToCheck).getMainCard().getId(); idToCheck = ((SplitCardHalf) objectToCheck).getMainCard().getId();
} else if (!type.needPlayCardAbility() && objectToCheck instanceof AdventureCardSpell) { } else if (!type.needPlayCardAbility() && objectToCheck instanceof CardWithSpellOption) {
// adventure spell uses alternative characteristics for spell/stack, all other cases must use main card // adventure/omen spell uses alternative characteristics for spell/stack, all other cases must use main card
idToCheck = ((AdventureCardSpell) objectToCheck).getMainCard().getId(); idToCheck = ((CardWithSpellOption) objectToCheck).getMainCard().getId();
} else if (!type.needPlayCardAbility() && objectToCheck instanceof ModalDoubleFacedCardHalf) { } else if (!type.needPlayCardAbility() && objectToCheck instanceof ModalDoubleFacedCardHalf) {
// each mdf side uses own characteristics to check for playing, all other cases must use main card // each mdf side uses own characteristics to check for playing, all other cases must use main card
// rules: // rules:

View file

@ -5,7 +5,7 @@ import mage.abilities.MageSingleton;
import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.AdventureCardSpell; import mage.cards.AdventureSpellCard;
import mage.cards.Card; import mage.cards.Card;
import mage.constants.AsThoughEffectType; import mage.constants.AsThoughEffectType;
import mage.constants.Duration; import mage.constants.Duration;
@ -51,10 +51,10 @@ public class ExileAdventureSpellEffect extends OneShotEffect implements MageSing
Spell spell = game.getStack().getSpell(source.getId()); Spell spell = game.getStack().getSpell(source.getId());
if (spell != null) { if (spell != null) {
Card spellCard = spell.getCard(); Card spellCard = spell.getCard();
if (spellCard instanceof AdventureCardSpell) { if (spellCard instanceof AdventureSpellCard) {
UUID exileId = adventureExileId(controller.getId(), game); UUID exileId = adventureExileId(controller.getId(), game);
game.getExile().createZone(exileId, "On an Adventure from " + controller.getName()); game.getExile().createZone(exileId, "On an Adventure from " + controller.getName());
AdventureCardSpell adventureSpellCard = (AdventureCardSpell) spellCard; AdventureSpellCard adventureSpellCard = (AdventureSpellCard) spellCard;
Card parentCard = adventureSpellCard.getParentCard(); Card parentCard = adventureSpellCard.getParentCard();
if (controller.moveCardsToExile(parentCard, source, game, true, exileId, "On an Adventure from " + controller.getName())) { if (controller.moveCardsToExile(parentCard, source, game, true, exileId, "On an Adventure from " + controller.getName())) {
ContinuousEffect effect = new AdventureCastFromExileEffect(); ContinuousEffect effect = new AdventureCastFromExileEffect();

View file

@ -257,7 +257,7 @@ public class ForetellAbility extends SpecialAction {
game.getState().addOtherAbility(rightHalfCard, ability); game.getState().addOtherAbility(rightHalfCard, ability);
} }
} }
} else if (card instanceof AdventureCard) { } else if (card instanceof CardWithSpellOption) {
if (foretellCost != null) { if (foretellCost != null) {
Card creatureCard = card.getMainCard(); Card creatureCard = card.getMainCard();
ForetellCostAbility ability = new ForetellCostAbility(foretellCost); ForetellCostAbility ability = new ForetellCostAbility(foretellCost);
@ -268,7 +268,7 @@ public class ForetellAbility extends SpecialAction {
game.getState().addOtherAbility(creatureCard, ability); game.getState().addOtherAbility(creatureCard, ability);
} }
if (foretellSplitCost != null) { if (foretellSplitCost != null) {
Card spellCard = ((AdventureCard) card).getSpellCard(); Card spellCard = ((CardWithSpellOption) card).getSpellCard();
ForetellCostAbility ability = new ForetellCostAbility(foretellSplitCost); ForetellCostAbility ability = new ForetellCostAbility(foretellSplitCost);
ability.setSourceId(spellCard.getId()); ability.setSourceId(spellCard.getId());
ability.setControllerId(source.getControllerId()); ability.setControllerId(source.getControllerId());
@ -360,11 +360,11 @@ public class ForetellAbility extends SpecialAction {
} else if (((ModalDoubleFacedCard) card).getRightHalfCard().getName().equals(abilityName)) { } else if (((ModalDoubleFacedCard) card).getRightHalfCard().getName().equals(abilityName)) {
return ((ModalDoubleFacedCard) card).getRightHalfCard().getSpellAbility().canActivate(playerId, game); return ((ModalDoubleFacedCard) card).getRightHalfCard().getSpellAbility().canActivate(playerId, game);
} }
} else if (card instanceof AdventureCard) { } else if (card instanceof CardWithSpellOption) {
if (card.getMainCard().getName().equals(abilityName)) { if (card.getMainCard().getName().equals(abilityName)) {
return card.getMainCard().getSpellAbility().canActivate(playerId, game); return card.getMainCard().getSpellAbility().canActivate(playerId, game);
} else if (((AdventureCard) card).getSpellCard().getName().equals(abilityName)) { } else if (((CardWithSpellOption) card).getSpellCard().getName().equals(abilityName)) {
return ((AdventureCard) card).getSpellCard().getSpellAbility().canActivate(playerId, game); return ((CardWithSpellOption) card).getSpellCard().getSpellAbility().canActivate(playerId, game);
} }
} }
return card.getSpellAbility().canActivate(playerId, game); return card.getSpellAbility().canActivate(playerId, game);
@ -391,11 +391,11 @@ public class ForetellAbility extends SpecialAction {
} else if (((ModalDoubleFacedCard) card).getRightHalfCard().getName().equals(abilityName)) { } else if (((ModalDoubleFacedCard) card).getRightHalfCard().getName().equals(abilityName)) {
spellAbilityCopy = ((ModalDoubleFacedCard) card).getRightHalfCard().getSpellAbility().copy(); spellAbilityCopy = ((ModalDoubleFacedCard) card).getRightHalfCard().getSpellAbility().copy();
} }
} else if (card instanceof AdventureCard) { } else if (card instanceof CardWithSpellOption) {
if (card.getMainCard().getName().equals(abilityName)) { if (card.getMainCard().getName().equals(abilityName)) {
spellAbilityCopy = card.getMainCard().getSpellAbility().copy(); spellAbilityCopy = card.getMainCard().getSpellAbility().copy();
} else if (((AdventureCard) card).getSpellCard().getName().equals(abilityName)) { } else if (((CardWithSpellOption) card).getSpellCard().getName().equals(abilityName)) {
spellAbilityCopy = ((AdventureCard) card).getSpellCard().getSpellAbility().copy(); spellAbilityCopy = ((CardWithSpellOption) card).getSpellCard().getSpellAbility().copy();
} }
} else { } else {
spellAbilityCopy = card.getSpellAbility().copy(); spellAbilityCopy = card.getSpellAbility().copy();

View file

@ -268,11 +268,11 @@ class PlotSpellAbility extends SpellAbility {
} else if (((CardWithHalves) mainCard).getRightHalfCard().getName().equals(faceCardName)) { } else if (((CardWithHalves) mainCard).getRightHalfCard().getName().equals(faceCardName)) {
return ((CardWithHalves) mainCard).getRightHalfCard().getSpellAbility().canActivate(playerId, game); return ((CardWithHalves) mainCard).getRightHalfCard().getSpellAbility().canActivate(playerId, game);
} }
} else if (card instanceof AdventureCard) { } else if (card instanceof CardWithSpellOption) {
if (card.getMainCard().getName().equals(faceCardName)) { if (card.getMainCard().getName().equals(faceCardName)) {
return card.getMainCard().getSpellAbility().canActivate(playerId, game); return card.getMainCard().getSpellAbility().canActivate(playerId, game);
} else if (((AdventureCard) card).getSpellCard().getName().equals(faceCardName)) { } else if (((CardWithSpellOption) card).getSpellCard().getName().equals(faceCardName)) {
return ((AdventureCard) card).getSpellCard().getSpellAbility().canActivate(playerId, game); return ((CardWithSpellOption) card).getSpellCard().getSpellAbility().canActivate(playerId, game);
} }
} }
return card.getSpellAbility().canActivate(playerId, game); return card.getSpellAbility().canActivate(playerId, game);
@ -294,11 +294,11 @@ class PlotSpellAbility extends SpellAbility {
} else if (((CardWithHalves) card).getRightHalfCard().getName().equals(faceCardName)) { } else if (((CardWithHalves) card).getRightHalfCard().getName().equals(faceCardName)) {
spellAbilityCopy = ((CardWithHalves) card).getRightHalfCard().getSpellAbility().copy(); spellAbilityCopy = ((CardWithHalves) card).getRightHalfCard().getSpellAbility().copy();
} }
} else if (card instanceof AdventureCard) { } else if (card instanceof CardWithSpellOption) {
if (card.getMainCard().getName().equals(faceCardName)) { if (card.getMainCard().getName().equals(faceCardName)) {
spellAbilityCopy = card.getMainCard().getSpellAbility().copy(); spellAbilityCopy = card.getMainCard().getSpellAbility().copy();
} else if (((AdventureCard) card).getSpellCard().getName().equals(faceCardName)) { } else if (((CardWithSpellOption) card).getSpellCard().getName().equals(faceCardName)) {
spellAbilityCopy = ((AdventureCard) card).getSpellCard().getSpellAbility().copy(); spellAbilityCopy = ((CardWithSpellOption) card).getSpellCard().getSpellAbility().copy();
} }
} else { } else {
spellAbilityCopy = card.getSpellAbility().copy(); spellAbilityCopy = card.getSpellAbility().copy();

View file

@ -1,98 +1,29 @@
package mage.cards; package mage.cards;
import mage.abilities.Abilities;
import mage.abilities.AbilitiesImpl;
import mage.abilities.Ability;
import mage.abilities.SpellAbility; import mage.abilities.SpellAbility;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SpellAbilityType; import mage.constants.SpellAbilityType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.events.ZoneChangeEvent;
import mage.util.CardUtil;
import java.util.List;
import java.util.UUID; import java.util.UUID;
/** /**
* @author phulin * @author phulin
*/ */
public abstract class AdventureCard extends CardImpl { public abstract class AdventureCard extends CardWithSpellOption {
/* The adventure spell card, i.e. Swift End. */
protected AdventureCardSpell spellCard;
public AdventureCard(UUID ownerId, CardSetInfo setInfo, CardType[] types, CardType[] typesSpell, String costs, String adventureName, String costsSpell) { public AdventureCard(UUID ownerId, CardSetInfo setInfo, CardType[] types, CardType[] typesSpell, String costs, String adventureName, String costsSpell) {
super(ownerId, setInfo, types, costs); super(ownerId, setInfo, types, costs);
this.spellCard = new AdventureCardSpellImpl(ownerId, setInfo, adventureName, typesSpell, costsSpell, this); this.spellCard = new AdventureSpellCard(ownerId, setInfo, adventureName, typesSpell, costsSpell, this);
}
public AdventureCard(AdventureCard card) {
super(card);
} }
public void finalizeAdventure() { public void finalizeAdventure() {
spellCard.finalizeAdventure(); spellCard.finalizeSpell();
}
protected AdventureCard(final AdventureCard card) {
super(card);
this.spellCard = card.getSpellCard().copy();
this.spellCard.setParentCard(this);
}
public AdventureCardSpell getSpellCard() {
return spellCard;
}
public void setParts(AdventureCardSpell cardSpell) {
// for card copy only - set new parts
this.spellCard = cardSpell;
cardSpell.setParentCard(this);
}
@Override
public void assignNewId() {
super.assignNewId();
spellCard.assignNewId();
}
@Override
public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List<UUID> appliedEffects) {
if (super.moveToZone(toZone, source, game, flag, appliedEffects)) {
Zone currentZone = game.getState().getZone(getId());
game.getState().setZone(getSpellCard().getId(), currentZone);
return true;
}
return false;
}
@Override
public void setZone(Zone zone, Game game) {
super.setZone(zone, game);
game.setZone(getSpellCard().getId(), zone);
}
@Override
public boolean moveToExile(UUID exileId, String name, Ability source, Game game, List<UUID> appliedEffects) {
if (super.moveToExile(exileId, name, source, game, appliedEffects)) {
Zone currentZone = game.getState().getZone(getId());
game.getState().setZone(getSpellCard().getId(), currentZone);
return true;
}
return false;
}
@Override
public boolean removeFromZone(Game game, Zone fromZone, Ability source) {
// zone contains only one main card
return super.removeFromZone(game, fromZone, source);
}
@Override
public void updateZoneChangeCounter(Game game, ZoneChangeEvent event) {
if (isCopy()) { // same as meld cards
super.updateZoneChangeCounter(game, event);
return;
}
super.updateZoneChangeCounter(game, event);
getSpellCard().updateZoneChangeCounter(game, event);
} }
@Override @Override
@ -103,45 +34,4 @@ public abstract class AdventureCard extends CardImpl {
this.getSpellCard().getSpellAbility().setControllerId(controllerId); this.getSpellCard().getSpellAbility().setControllerId(controllerId);
return super.cast(game, fromZone, ability, controllerId); return super.cast(game, fromZone, ability, controllerId);
} }
@Override
public Abilities<Ability> getAbilities() {
Abilities<Ability> allAbilities = new AbilitiesImpl<>();
allAbilities.addAll(spellCard.getAbilities());
allAbilities.addAll(super.getAbilities());
return allAbilities;
}
@Override
public Abilities<Ability> getInitAbilities() {
// must init only parent related abilities, spell card must be init separately
return super.getAbilities();
}
@Override
public Abilities<Ability> getAbilities(Game game) {
Abilities<Ability> allAbilities = new AbilitiesImpl<>();
allAbilities.addAll(spellCard.getAbilities(game));
allAbilities.addAll(super.getAbilities(game));
return allAbilities;
}
public Abilities<Ability> getSharedAbilities(Game game) {
// abilities without spellcard
return super.getAbilities(game);
}
public List<String> getSharedRules(Game game) {
// rules without spellcard
Abilities<Ability> sourceAbilities = this.getSharedAbilities(game);
return CardUtil.getCardRulesWithAdditionalInfo(game, this, sourceAbilities, sourceAbilities);
}
@Override
public void setOwnerId(UUID ownerId) {
super.setOwnerId(ownerId);
abilities.setControllerId(ownerId);
spellCard.getAbilities().setControllerId(ownerId);
spellCard.setOwnerId(ownerId);
}
} }

View file

@ -1,12 +0,0 @@
package mage.cards;
/**
* @author phulin
*/
public interface AdventureCardSpell extends SubCard<AdventureCard> {
@Override
AdventureCardSpell copy();
void finalizeAdventure();
}

View file

@ -19,11 +19,11 @@ import java.util.stream.Collectors;
/** /**
* @author phulin * @author phulin
*/ */
public class AdventureCardSpellImpl extends CardImpl implements AdventureCardSpell { public class AdventureSpellCard extends CardImpl implements SpellOptionCard {
private AdventureCard adventureCardParent; private AdventureCard adventureCardParent;
public AdventureCardSpellImpl(UUID ownerId, CardSetInfo setInfo, String adventureName, CardType[] cardTypes, String costs, AdventureCard adventureCardParent) { public AdventureSpellCard(UUID ownerId, CardSetInfo setInfo, String adventureName, CardType[] cardTypes, String costs, AdventureCard adventureCardParent) {
super(ownerId, setInfo, cardTypes, costs, SpellAbilityType.ADVENTURE_SPELL); super(ownerId, setInfo, cardTypes, costs, SpellAbilityType.ADVENTURE_SPELL);
this.subtype.add(SubType.ADVENTURE); this.subtype.add(SubType.ADVENTURE);
@ -35,13 +35,13 @@ public class AdventureCardSpellImpl extends CardImpl implements AdventureCardSpe
this.adventureCardParent = adventureCardParent; this.adventureCardParent = adventureCardParent;
} }
public void finalizeAdventure() { public void finalizeSpell() {
if (spellAbility instanceof AdventureCardSpellAbility) { if (spellAbility instanceof AdventureCardSpellAbility) {
((AdventureCardSpellAbility) spellAbility).finalizeAdventure(); ((AdventureCardSpellAbility) spellAbility).finalizeAdventure();
} }
} }
protected AdventureCardSpellImpl(final AdventureCardSpellImpl card) { protected AdventureSpellCard(final AdventureSpellCard card) {
super(card); super(card);
this.adventureCardParent = card.adventureCardParent; this.adventureCardParent = card.adventureCardParent;
} }
@ -83,13 +83,13 @@ public class AdventureCardSpellImpl extends CardImpl implements AdventureCardSpe
} }
@Override @Override
public AdventureCardSpellImpl copy() { public AdventureSpellCard copy() {
return new AdventureCardSpellImpl(this); return new AdventureSpellCard(this);
} }
@Override @Override
public void setParentCard(AdventureCard card) { public void setParentCard(CardWithSpellOption card) {
this.adventureCardParent = card; this.adventureCardParent = (AdventureCard) card;
} }
@Override @Override
@ -102,6 +102,11 @@ public class AdventureCardSpellImpl extends CardImpl implements AdventureCardSpe
// id must send to main card (popup card hint in game logs) // id must send to main card (popup card hint in game logs)
return getName() + " [" + adventureCardParent.getId().toString().substring(0, 3) + ']'; return getName() + " [" + adventureCardParent.getId().toString().substring(0, 3) + ']';
} }
@Override
public String getSpellType() {
return "Adventure";
}
} }
class AdventureCardSpellAbility extends SpellAbility { class AdventureCardSpellAbility extends SpellAbility {
@ -141,8 +146,8 @@ class AdventureCardSpellAbility extends SpellAbility {
public ActivationStatus canActivate(UUID playerId, Game game) { public ActivationStatus canActivate(UUID playerId, Game game) {
ExileZone adventureExileZone = game.getExile().getExileZone(ExileAdventureSpellEffect.adventureExileId(playerId, game)); ExileZone adventureExileZone = game.getExile().getExileZone(ExileAdventureSpellEffect.adventureExileId(playerId, game));
Card spellCard = game.getCard(this.getSourceId()); Card spellCard = game.getCard(this.getSourceId());
if (spellCard instanceof AdventureCardSpell) { if (spellCard instanceof AdventureSpellCard) {
Card card = ((AdventureCardSpell) spellCard).getParentCard(); Card card = ((AdventureSpellCard) spellCard).getParentCard();
if (adventureExileZone != null && adventureExileZone.contains(card.getId())) { if (adventureExileZone != null && adventureExileZone.contains(card.getId())) {
return ActivationStatus.getFalse(); return ActivationStatus.getFalse();
} }

View file

@ -530,8 +530,8 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
} }
} }
if (stackObject == null && (this instanceof AdventureCard)) { if (stackObject == null && (this instanceof CardWithSpellOption)) {
stackObject = game.getStack().getSpell(((AdventureCard) this).getSpellCard().getId(), false); stackObject = game.getStack().getSpell(((CardWithSpellOption) this).getSpellCard().getId(), false);
} }
if (stackObject == null) { if (stackObject == null) {

View file

@ -0,0 +1,131 @@
package mage.cards;
import mage.abilities.Abilities;
import mage.abilities.AbilitiesImpl;
import mage.abilities.Ability;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.ZoneChangeEvent;
import mage.util.CardUtil;
import java.util.List;
import java.util.UUID;
/**
* @author phulin, jmlundeen
*/
public abstract class CardWithSpellOption extends CardImpl {
/* The adventure/omen spell card, i.e. Swift End. */
protected SpellOptionCard spellCard;
public CardWithSpellOption(UUID ownerId, CardSetInfo setInfo, CardType[] types, String costs) {
super(ownerId, setInfo, types, costs);
}
public CardWithSpellOption(CardWithSpellOption card) {
super(card);
this.spellCard = card.getSpellCard().copy();
this.spellCard.setParentCard(this);
}
public SpellOptionCard getSpellCard() {
return spellCard;
}
public void setParts(SpellOptionCard cardSpell) {
// for card copy only - set new parts
this.spellCard = cardSpell;
cardSpell.setParentCard(this);
}
@Override
public void assignNewId() {
super.assignNewId();
spellCard.assignNewId();
}
@Override
public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List<UUID> appliedEffects) {
if (super.moveToZone(toZone, source, game, flag, appliedEffects)) {
Zone currentZone = game.getState().getZone(getId());
game.getState().setZone(getSpellCard().getId(), currentZone);
return true;
}
return false;
}
@Override
public void setZone(Zone zone, Game game) {
super.setZone(zone, game);
game.setZone(getSpellCard().getId(), zone);
}
@Override
public boolean moveToExile(UUID exileId, String name, Ability source, Game game, List<UUID> appliedEffects) {
if (super.moveToExile(exileId, name, source, game, appliedEffects)) {
Zone currentZone = game.getState().getZone(getId());
game.getState().setZone(getSpellCard().getId(), currentZone);
return true;
}
return false;
}
@Override
public boolean removeFromZone(Game game, Zone fromZone, Ability source) {
// zone contains only one main card
return super.removeFromZone(game, fromZone, source);
}
@Override
public void updateZoneChangeCounter(Game game, ZoneChangeEvent event) {
if (isCopy()) { // same as meld cards
super.updateZoneChangeCounter(game, event);
return;
}
super.updateZoneChangeCounter(game, event);
getSpellCard().updateZoneChangeCounter(game, event);
}
@Override
public Abilities<Ability> getAbilities() {
Abilities<Ability> allAbilities = new AbilitiesImpl<>();
allAbilities.addAll(spellCard.getAbilities());
allAbilities.addAll(super.getAbilities());
return allAbilities;
}
@Override
public Abilities<Ability> getInitAbilities() {
// must init only parent related abilities, spell card must be init separately
return super.getAbilities();
}
@Override
public Abilities<Ability> getAbilities(Game game) {
Abilities<Ability> allAbilities = new AbilitiesImpl<>();
allAbilities.addAll(spellCard.getAbilities(game));
allAbilities.addAll(super.getAbilities(game));
return allAbilities;
}
public Abilities<Ability> getSharedAbilities(Game game) {
// abilities without spellCard
return super.getAbilities(game);
}
public List<String> getSharedRules(Game game) {
// rules without spellCard
Abilities<Ability> sourceAbilities = this.getSharedAbilities(game);
return CardUtil.getCardRulesWithAdditionalInfo(game, this, sourceAbilities, sourceAbilities);
}
@Override
public void setOwnerId(UUID ownerId) {
super.setOwnerId(ownerId);
abilities.setControllerId(ownerId);
spellCard.getAbilities().setControllerId(ownerId);
spellCard.setOwnerId(ownerId);
}
}

View file

@ -0,0 +1,34 @@
package mage.cards;
import mage.abilities.SpellAbility;
import mage.constants.CardType;
import mage.constants.SpellAbilityType;
import mage.constants.Zone;
import mage.game.Game;
import java.util.UUID;
public abstract class OmenCard extends CardWithSpellOption {
public OmenCard(UUID ownerId, CardSetInfo setInfo, CardType[] types, CardType[] typesSpell, String costs, String omenName, String costsSpell) {
super(ownerId, setInfo, types, costs);
this.spellCard = new OmenSpellCard(ownerId, setInfo, omenName, typesSpell, costsSpell, this);
}
public OmenCard(OmenCard card) {
super(card);
}
public void finalizeOmen() {
spellCard.finalizeSpell();
}
@Override
public boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId) {
if (ability.getSpellAbilityType() == SpellAbilityType.OMEN_SPELL) {
return this.getSpellCard().cast(game, fromZone, ability, controllerId);
}
this.getSpellCard().getSpellAbility().setControllerId(controllerId);
return super.cast(game, fromZone, ability, controllerId);
}
}

View file

@ -0,0 +1,174 @@
package mage.cards;
import mage.abilities.Ability;
import mage.abilities.Modes;
import mage.abilities.SpellAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.ShuffleIntoLibrarySourceEffect;
import mage.constants.CardType;
import mage.constants.SpellAbilityType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
public class OmenSpellCard extends CardImpl implements SpellOptionCard {
private OmenCard omenCardParent;
public OmenSpellCard(UUID ownerId, CardSetInfo setInfo, String omenName, CardType[] cardTypes, String costs, OmenCard omenCard) {
super(ownerId, setInfo, cardTypes, costs, SpellAbilityType.OMEN_SPELL);
this.subtype.add(SubType.OMEN);
OmenCardSpellAbility newSpellAbility = new OmenCardSpellAbility(getSpellAbility(), omenName, cardTypes, costs);
this.replaceSpellAbility(newSpellAbility);
spellAbility = newSpellAbility;
this.setName(omenName);
this.omenCardParent = omenCard;
}
public void finalizeSpell() {
if (spellAbility instanceof OmenCardSpellAbility) {
((OmenCardSpellAbility) spellAbility).finalizeOmen();
}
}
protected OmenSpellCard(final OmenSpellCard card) {
super(card);
this.omenCardParent = card.omenCardParent;
}
@Override
public UUID getOwnerId() {
return omenCardParent.getOwnerId();
}
@Override
public String getExpansionSetCode() {
return omenCardParent.getExpansionSetCode();
}
@Override
public String getCardNumber() {
return omenCardParent.getCardNumber();
}
@Override
public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List<UUID> appliedEffects) {
return omenCardParent.moveToZone(toZone, source, game, flag, appliedEffects);
}
@Override
public boolean moveToExile(UUID exileId, String name, Ability source, Game game, List<UUID> appliedEffects) {
return omenCardParent.moveToExile(exileId, name, source, game, appliedEffects);
}
@Override
public OmenCard getMainCard() {
return omenCardParent;
}
@Override
public void setZone(Zone zone, Game game) {
game.setZone(omenCardParent.getId(), zone);
game.setZone(omenCardParent.getSpellCard().getId(), zone);
}
@Override
public OmenSpellCard copy() {
return new OmenSpellCard(this);
}
@Override
public void setParentCard(CardWithSpellOption card) {
this.omenCardParent = (OmenCard) card;
}
@Override
public OmenCard getParentCard() {
return this.omenCardParent;
}
@Override
public String getIdName() {
// id must send to main card (popup card hint in game logs)
return getName() + " [" + omenCardParent.getId().toString().substring(0, 3) + ']';
}
@Override
public String getSpellType() {
return "Omen";
}
}
class OmenCardSpellAbility extends SpellAbility {
private String nameFull;
private boolean finalized = false;
public OmenCardSpellAbility(final SpellAbility baseSpellAbility, String omenName, CardType[] cardTypes, String costs) {
super(baseSpellAbility);
this.setName(cardTypes, omenName, costs);
this.setCardName(omenName);
}
public void finalizeOmen() {
if (finalized) {
throw new IllegalStateException("Wrong code usage. "
+ "Omen (" + cardName + ") "
+ "need to call finalizeOmen() exactly once.");
}
Effect effect = new ShuffleIntoLibrarySourceEffect();
effect.setText("");
this.addEffect(effect);
this.finalized = true;
}
protected OmenCardSpellAbility(final OmenCardSpellAbility ability) {
super(ability);
this.nameFull = ability.nameFull;
if (!ability.finalized) {
throw new IllegalStateException("Wrong code usage. "
+ "Omen (" + cardName + ") "
+ "need to call finalizeOmen() at the very end of the card's constructor.");
}
this.finalized = true;
}
public void setName(CardType[] cardTypes, String omenName, String costs) {
this.nameFull = "Omen " + Arrays.stream(cardTypes).map(CardType::toString).collect(Collectors.joining(" ")) + " &mdash; " + omenName;
this.name = this.nameFull + " " + costs;
}
@Override
public String getRule(boolean all) {
return this.getRule();
}
@Override
public String getRule() {
StringBuilder sbRule = new StringBuilder();
sbRule.append(this.nameFull);
sbRule.append(" ");
sbRule.append(getManaCosts().getText());
sbRule.append(" &mdash; ");
Modes modes = this.getModes();
if (modes.size() <= 1) {
sbRule.append(modes.getMode().getEffects().getTextStartingUpperCase(modes.getMode()));
} else {
sbRule.append(getModes().getText());
}
sbRule.append(" <i>(Then shuffle this card into its owner's library.)<i>");
return sbRule.toString();
}
@Override
public OmenCardSpellAbility copy() {
return new OmenCardSpellAbility(this);
}
}

View file

@ -0,0 +1,18 @@
package mage.cards;
public interface SpellOptionCard extends SubCard<CardWithSpellOption> {
@Override
SpellOptionCard copy();
/**
* Adds the final shared ability to the card. e.g. Adventure exile effect / Omen shuffle effect
*/
void finalizeSpell();
/**
* Used to get the card type text such as Adventure. Currently only used in {@link mage.game.stack.Spell#getSpellCastText Spell} for logging the spell
* being cast as part of the two part card.
*/
String getSpellType();
}

View file

@ -20,7 +20,7 @@ import java.util.List;
*/ */
public class MockCard extends CardImpl implements MockableCard { public class MockCard extends CardImpl implements MockableCard {
public static String ADVENTURE_NAME_SEPARATOR = " // "; public static String CARD_WITH_SPELL_OPTION_NAME_SEPARATOR = " // ";
public static String MODAL_DOUBLE_FACES_NAME_SEPARATOR = " // "; public static String MODAL_DOUBLE_FACES_NAME_SEPARATOR = " // ";
// Needs to be here, as it is normally calculated from the // Needs to be here, as it is normally calculated from the
@ -34,7 +34,7 @@ public class MockCard extends CardImpl implements MockableCard {
protected List<String> manaCostLeftStr; protected List<String> manaCostLeftStr;
protected List<String> manaCostRightStr; protected List<String> manaCostRightStr;
protected List<String> manaCostStr; protected List<String> manaCostStr;
protected String adventureSpellName; protected String spellOptionName; // adventure/omen spell name
protected boolean isModalDoubleFacedCard; protected boolean isModalDoubleFacedCard;
protected int manaValue; protected int manaValue;
@ -71,8 +71,8 @@ public class MockCard extends CardImpl implements MockableCard {
this.secondSideCard = new MockCard(CardRepository.instance.findCardWithPreferredSetAndNumber(card.getSecondSideName(), card.getSetCode(), card.getCardNumber())); this.secondSideCard = new MockCard(CardRepository.instance.findCardWithPreferredSetAndNumber(card.getSecondSideName(), card.getSetCode(), card.getCardNumber()));
} }
if (card.isAdventureCard()) { if (card.isCardWithSpellOption()) {
this.adventureSpellName = card.getAdventureSpellName(); this.spellOptionName = card.getSpellOptionCardName();
} }
if (card.isModalDoubleFacedCard()) { if (card.isModalDoubleFacedCard()) {
@ -101,7 +101,7 @@ public class MockCard extends CardImpl implements MockableCard {
this.manaCostLeftStr = new ArrayList<>(card.manaCostLeftStr); this.manaCostLeftStr = new ArrayList<>(card.manaCostLeftStr);
this.manaCostRightStr = new ArrayList<>(card.manaCostRightStr); this.manaCostRightStr = new ArrayList<>(card.manaCostRightStr);
this.manaCostStr = new ArrayList<>(card.manaCostStr); this.manaCostStr = new ArrayList<>(card.manaCostStr);
this.adventureSpellName = card.adventureSpellName; this.spellOptionName = card.spellOptionName;
this.isModalDoubleFacedCard = card.isModalDoubleFacedCard; this.isModalDoubleFacedCard = card.isModalDoubleFacedCard;
this.manaValue = card.manaValue; this.manaValue = card.manaValue;
} }
@ -155,8 +155,8 @@ public class MockCard extends CardImpl implements MockableCard {
return getName(); return getName();
} }
if (adventureSpellName != null) { if (spellOptionName != null) {
return getName() + ADVENTURE_NAME_SEPARATOR + adventureSpellName; return getName() + CARD_WITH_SPELL_OPTION_NAME_SEPARATOR + spellOptionName;
} else if (isModalDoubleFacedCard) { } else if (isModalDoubleFacedCard) {
return getName() + MODAL_DOUBLE_FACES_NAME_SEPARATOR + this.getSecondCardFace().getName(); return getName() + MODAL_DOUBLE_FACES_NAME_SEPARATOR + this.getSecondCardFace().getName();
} else { } else {

View file

@ -106,9 +106,9 @@ public class CardInfo {
@DatabaseField @DatabaseField
protected String secondSideName; protected String secondSideName;
@DatabaseField @DatabaseField
protected boolean adventureCard; protected boolean cardWithSpellOption;
@DatabaseField @DatabaseField
protected String adventureSpellName; protected String spellOptionCardName;
@DatabaseField @DatabaseField
protected boolean modalDoubleFacedCard; protected boolean modalDoubleFacedCard;
@DatabaseField @DatabaseField
@ -157,9 +157,9 @@ public class CardInfo {
this.secondSideName = secondSide.getName(); this.secondSideName = secondSide.getName();
} }
if (card instanceof AdventureCard) { if (card instanceof CardWithSpellOption) {
this.adventureCard = true; this.cardWithSpellOption = true;
this.adventureSpellName = ((AdventureCard) card).getSpellCard().getName(); this.spellOptionCardName = ((CardWithSpellOption) card).getSpellCard().getName();
} }
if (card instanceof ModalDoubleFacedCard) { if (card instanceof ModalDoubleFacedCard) {
@ -189,8 +189,8 @@ public class CardInfo {
List<String> manaCostLeft = ((ModalDoubleFacedCard) card).getLeftHalfCard().getManaCostSymbols(); List<String> manaCostLeft = ((ModalDoubleFacedCard) card).getLeftHalfCard().getManaCostSymbols();
List<String> manaCostRight = ((ModalDoubleFacedCard) card).getRightHalfCard().getManaCostSymbols(); List<String> manaCostRight = ((ModalDoubleFacedCard) card).getRightHalfCard().getManaCostSymbols();
this.setManaCosts(CardUtil.concatManaSymbols(SPLIT_MANA_SEPARATOR_FULL, manaCostLeft, manaCostRight)); this.setManaCosts(CardUtil.concatManaSymbols(SPLIT_MANA_SEPARATOR_FULL, manaCostLeft, manaCostRight));
} else if (card instanceof AdventureCard) { } else if (card instanceof CardWithSpellOption) {
List<String> manaCostLeft = ((AdventureCard) card).getSpellCard().getManaCostSymbols(); List<String> manaCostLeft = ((CardWithSpellOption) card).getSpellCard().getManaCostSymbols();
List<String> manaCostRight = card.getManaCostSymbols(); List<String> manaCostRight = card.getManaCostSymbols();
this.setManaCosts(CardUtil.concatManaSymbols(SPLIT_MANA_SEPARATOR_FULL, manaCostLeft, manaCostRight)); this.setManaCosts(CardUtil.concatManaSymbols(SPLIT_MANA_SEPARATOR_FULL, manaCostLeft, manaCostRight));
} else { } else {
@ -469,12 +469,16 @@ public class CardInfo {
return secondSideName; return secondSideName;
} }
public boolean isAdventureCard() { public boolean isCardWithSpellOption() {
return adventureCard; return cardWithSpellOption;
} }
public String getAdventureSpellName() { /**
return adventureSpellName; * used for spell card portion of adventure/omen cards
* @return name of the spell
*/
public String getSpellOptionCardName() {
return spellOptionCardName;
} }
public boolean isModalDoubleFacedCard() { public boolean isModalDoubleFacedCard() {

View file

@ -147,8 +147,8 @@ public enum CardRepository {
if (card.getMeldsToCardName() != null && !card.getMeldsToCardName().isEmpty()) { if (card.getMeldsToCardName() != null && !card.getMeldsToCardName().isEmpty()) {
namesList.add(card.getMeldsToCardName()); namesList.add(card.getMeldsToCardName());
} }
if (card.getAdventureSpellName() != null && !card.getAdventureSpellName().isEmpty()) { if (card.getSpellOptionCardName() != null && !card.getSpellOptionCardName().isEmpty()) {
namesList.add(card.getAdventureSpellName()); namesList.add(card.getSpellOptionCardName());
} }
} }
@ -160,7 +160,7 @@ public enum CardRepository {
Set<String> names = new TreeSet<>(); Set<String> names = new TreeSet<>();
try { try {
QueryBuilder<CardInfo, Object> qb = cardsDao.queryBuilder(); QueryBuilder<CardInfo, Object> qb = cardsDao.queryBuilder();
qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "adventureSpellName"); qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName");
List<CardInfo> results = cardsDao.query(qb.prepare()); List<CardInfo> results = cardsDao.query(qb.prepare());
for (CardInfo card : results) { for (CardInfo card : results) {
addNewNames(card, names); addNewNames(card, names);
@ -176,7 +176,7 @@ public enum CardRepository {
Set<String> names = new TreeSet<>(); Set<String> names = new TreeSet<>();
try { try {
QueryBuilder<CardInfo, Object> qb = cardsDao.queryBuilder(); QueryBuilder<CardInfo, Object> qb = cardsDao.queryBuilder();
qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "adventureSpellName"); qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName");
qb.where().not().like("types", new SelectArg('%' + CardType.LAND.name() + '%')); qb.where().not().like("types", new SelectArg('%' + CardType.LAND.name() + '%'));
List<CardInfo> results = cardsDao.query(qb.prepare()); List<CardInfo> results = cardsDao.query(qb.prepare());
for (CardInfo card : results) { for (CardInfo card : results) {
@ -193,7 +193,7 @@ public enum CardRepository {
Set<String> names = new TreeSet<>(); Set<String> names = new TreeSet<>();
try { try {
QueryBuilder<CardInfo, Object> qb = cardsDao.queryBuilder(); QueryBuilder<CardInfo, Object> qb = cardsDao.queryBuilder();
qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "adventureSpellName"); qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName");
Where<CardInfo, Object> where = qb.where(); Where<CardInfo, Object> where = qb.where();
where.and( where.and(
where.not().like("supertypes", '%' + SuperType.BASIC.name() + '%'), where.not().like("supertypes", '%' + SuperType.BASIC.name() + '%'),
@ -214,7 +214,7 @@ public enum CardRepository {
Set<String> names = new TreeSet<>(); Set<String> names = new TreeSet<>();
try { try {
QueryBuilder<CardInfo, Object> qb = cardsDao.queryBuilder(); QueryBuilder<CardInfo, Object> qb = cardsDao.queryBuilder();
qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "adventureSpellName"); qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName");
qb.where().not().like("supertypes", new SelectArg('%' + SuperType.BASIC.name() + '%')); qb.where().not().like("supertypes", new SelectArg('%' + SuperType.BASIC.name() + '%'));
List<CardInfo> results = cardsDao.query(qb.prepare()); List<CardInfo> results = cardsDao.query(qb.prepare());
for (CardInfo card : results) { for (CardInfo card : results) {
@ -231,7 +231,7 @@ public enum CardRepository {
Set<String> names = new TreeSet<>(); Set<String> names = new TreeSet<>();
try { try {
QueryBuilder<CardInfo, Object> qb = cardsDao.queryBuilder(); QueryBuilder<CardInfo, Object> qb = cardsDao.queryBuilder();
qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "adventureSpellName"); qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName");
qb.where().like("types", new SelectArg('%' + CardType.CREATURE.name() + '%')); qb.where().like("types", new SelectArg('%' + CardType.CREATURE.name() + '%'));
List<CardInfo> results = cardsDao.query(qb.prepare()); List<CardInfo> results = cardsDao.query(qb.prepare());
for (CardInfo card : results) { for (CardInfo card : results) {
@ -248,7 +248,7 @@ public enum CardRepository {
Set<String> names = new TreeSet<>(); Set<String> names = new TreeSet<>();
try { try {
QueryBuilder<CardInfo, Object> qb = cardsDao.queryBuilder(); QueryBuilder<CardInfo, Object> qb = cardsDao.queryBuilder();
qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "adventureSpellName"); qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName");
qb.where().like("types", new SelectArg('%' + CardType.ARTIFACT.name() + '%')); qb.where().like("types", new SelectArg('%' + CardType.ARTIFACT.name() + '%'));
List<CardInfo> results = cardsDao.query(qb.prepare()); List<CardInfo> results = cardsDao.query(qb.prepare());
for (CardInfo card : results) { for (CardInfo card : results) {
@ -265,7 +265,7 @@ public enum CardRepository {
Set<String> names = new TreeSet<>(); Set<String> names = new TreeSet<>();
try { try {
QueryBuilder<CardInfo, Object> qb = cardsDao.queryBuilder(); QueryBuilder<CardInfo, Object> qb = cardsDao.queryBuilder();
qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "adventureSpellName"); qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName");
Where<CardInfo, Object> where = qb.where(); Where<CardInfo, Object> where = qb.where();
where.and( where.and(
where.not().like("types", '%' + CardType.CREATURE.name() + '%'), where.not().like("types", '%' + CardType.CREATURE.name() + '%'),
@ -286,7 +286,7 @@ public enum CardRepository {
Set<String> names = new TreeSet<>(); Set<String> names = new TreeSet<>();
try { try {
QueryBuilder<CardInfo, Object> qb = cardsDao.queryBuilder(); QueryBuilder<CardInfo, Object> qb = cardsDao.queryBuilder();
qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "adventureSpellName"); qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName");
Where<CardInfo, Object> where = qb.where(); Where<CardInfo, Object> where = qb.where();
where.and( where.and(
where.not().like("types", '%' + CardType.ARTIFACT.name() + '%'), where.not().like("types", '%' + CardType.ARTIFACT.name() + '%'),
@ -511,7 +511,7 @@ public enum CardRepository {
queryBuilder.where() queryBuilder.where()
.eq("flipCardName", new SelectArg(name)).or() .eq("flipCardName", new SelectArg(name)).or()
.eq("secondSideName", new SelectArg(name)).or() .eq("secondSideName", new SelectArg(name)).or()
.eq("adventureSpellName", new SelectArg(name)).or() .eq("spellOptionCardName", new SelectArg(name)).or()
.eq("modalDoubleFacedSecondSideName", new SelectArg(name)); .eq("modalDoubleFacedSecondSideName", new SelectArg(name));
results = cardsDao.query(queryBuilder.prepare()); results = cardsDao.query(queryBuilder.prepare());
} else { } else {

View file

@ -15,7 +15,8 @@ public enum SpellAbilityType {
MODAL_LEFT("LeftModal SpellAbility"), MODAL_LEFT("LeftModal SpellAbility"),
MODAL_RIGHT("RightModal SpellAbility"), MODAL_RIGHT("RightModal SpellAbility"),
SPLICE("Spliced SpellAbility"), SPLICE("Spliced SpellAbility"),
ADVENTURE_SPELL("Adventure SpellAbility"); ADVENTURE_SPELL("Adventure SpellAbility"),
OMEN_SPELL("Omen SpellAbility");
private final String text; private final String text;

View file

@ -13,6 +13,7 @@ public enum SubType {
ADVENTURE("Adventure", SubTypeSet.SpellType), ADVENTURE("Adventure", SubTypeSet.SpellType),
ARCANE("Arcane", SubTypeSet.SpellType), ARCANE("Arcane", SubTypeSet.SpellType),
LESSON("Lesson", SubTypeSet.SpellType), LESSON("Lesson", SubTypeSet.SpellType),
OMEN("Omen", SubTypeSet.SpellType),
TRAP("Trap", SubTypeSet.SpellType), TRAP("Trap", SubTypeSet.SpellType),
// Battle subtypes // Battle subtypes

View file

@ -1,9 +1,6 @@
package mage.filter.predicate.card; package mage.filter.predicate.card;
import mage.cards.AdventureCard; import mage.cards.*;
import mage.cards.Card;
import mage.cards.ModalDoubleFacedCard;
import mage.cards.SplitCard;
import mage.cards.mock.MockCard; import mage.cards.mock.MockCard;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType; import mage.constants.SuperType;
@ -55,8 +52,8 @@ public class CardTextPredicate implements Predicate<Card> {
fullName = ((MockCard) input).getFullName(true); fullName = ((MockCard) input).getFullName(true);
} else if (input instanceof ModalDoubleFacedCard) { } else if (input instanceof ModalDoubleFacedCard) {
fullName = input.getName() + MockCard.MODAL_DOUBLE_FACES_NAME_SEPARATOR + ((ModalDoubleFacedCard) input).getRightHalfCard().getName(); fullName = input.getName() + MockCard.MODAL_DOUBLE_FACES_NAME_SEPARATOR + ((ModalDoubleFacedCard) input).getRightHalfCard().getName();
} else if (input instanceof AdventureCard) { } else if (input instanceof CardWithSpellOption) {
fullName = input.getName() + MockCard.ADVENTURE_NAME_SEPARATOR + ((AdventureCard) input).getSpellCard().getName(); fullName = input.getName() + MockCard.CARD_WITH_SPELL_OPTION_NAME_SEPARATOR + ((CardWithSpellOption) input).getSpellCard().getName();
} }
if (fullName.toLowerCase(Locale.ENGLISH).contains(text.toLowerCase(Locale.ENGLISH))) { if (fullName.toLowerCase(Locale.ENGLISH).contains(text.toLowerCase(Locale.ENGLISH))) {
@ -107,8 +104,8 @@ public class CardTextPredicate implements Predicate<Card> {
} }
} }
if (input instanceof AdventureCard) { if (input instanceof CardWithSpellOption) {
for (String rule : ((AdventureCard) input).getSpellCard().getRules(game)) { for (String rule : ((CardWithSpellOption) input).getSpellCard().getRules(game)) {
if (rule.toLowerCase(Locale.ENGLISH).contains(token)) { if (rule.toLowerCase(Locale.ENGLISH).contains(token)) {
found = true; found = true;
break; break;

View file

@ -334,8 +334,8 @@ public abstract class GameImpl implements Game {
Card rightCard = ((ModalDoubleFacedCard) card).getRightHalfCard(); Card rightCard = ((ModalDoubleFacedCard) card).getRightHalfCard();
rightCard.setOwnerId(ownerId); rightCard.setOwnerId(ownerId);
addCardToState(rightCard); addCardToState(rightCard);
} else if (card instanceof AdventureCard) { } else if (card instanceof CardWithSpellOption) {
Card spellCard = ((AdventureCard) card).getSpellCard(); Card spellCard = ((CardWithSpellOption) card).getSpellCard();
spellCard.setOwnerId(ownerId); spellCard.setOwnerId(ownerId);
addCardToState(spellCard); addCardToState(spellCard);
} else if (card.isTransformable() && card.getSecondCardFace() != null) { } else if (card.isTransformable() && card.getSecondCardFace() != null) {

View file

@ -1639,14 +1639,14 @@ public class GameState implements Serializable, Copyable<GameState> {
copiedParts.add(rightCopied); copiedParts.add(rightCopied);
// sync parts // sync parts
((ModalDoubleFacedCard) copiedCard).setParts(leftCopied, rightCopied); ((ModalDoubleFacedCard) copiedCard).setParts(leftCopied, rightCopied);
} else if (copiedCard instanceof AdventureCard) { } else if (copiedCard instanceof CardWithSpellOption) {
// right // right
AdventureCardSpell rightOriginal = ((AdventureCard) copiedCard).getSpellCard(); SpellOptionCard rightOriginal = ((CardWithSpellOption) copiedCard).getSpellCard();
AdventureCardSpell rightCopied = rightOriginal.copy(); SpellOptionCard rightCopied = rightOriginal.copy();
prepareCardForCopy(rightOriginal, rightCopied, newController); prepareCardForCopy(rightOriginal, rightCopied, newController);
copiedParts.add(rightCopied); copiedParts.add(rightCopied);
// sync parts // sync parts
((AdventureCard) copiedCard).setParts(rightCopied); ((CardWithSpellOption) copiedCard).setParts(rightCopied);
} }
// main part prepare (must be called after other parts cause it change ids for all) // main part prepare (must be called after other parts cause it change ids for all)

View file

@ -209,10 +209,11 @@ public class Spell extends StackObjectImpl implements Card {
+ " using " + this.getSpellAbility().getSpellAbilityCastMode(); + " using " + this.getSpellAbility().getSpellAbilityCastMode();
} }
if (card instanceof AdventureCardSpell) { if (card instanceof SpellOptionCard) {
AdventureCard adventureCard = ((AdventureCardSpell) card).getParentCard(); CardWithSpellOption parentCard = ((SpellOptionCard) card).getParentCard();
return GameLog.replaceNameByColoredName(card, getSpellAbility().toString(), adventureCard) String type = ((SpellOptionCard) card).getSpellType();
+ " as Adventure spell of " + GameLog.getColoredObjectIdName(adventureCard); return GameLog.replaceNameByColoredName(card, getSpellAbility().toString(), parentCard)
+ " as " + type + " spell of " + GameLog.getColoredObjectIdName(parentCard);
} }
if (card instanceof ModalDoubleFacedCardHalf) { if (card instanceof ModalDoubleFacedCardHalf) {
@ -539,8 +540,8 @@ public class Spell extends StackObjectImpl implements Card {
public String getIdName() { public String getIdName() {
String idName; String idName;
if (card != null) { if (card != null) {
if (card instanceof AdventureCardSpell) { if (card instanceof SpellOptionCard) {
idName = ((AdventureCardSpell) card).getParentCard().getId().toString().substring(0, 3); idName = ((SpellOptionCard) card).getParentCard().getId().toString().substring(0, 3);
} else { } else {
idName = card.getId().toString().substring(0, 3); idName = card.getId().toString().substring(0, 3);
} }

View file

@ -4068,11 +4068,11 @@ public abstract class PlayerImpl implements Player, Serializable {
getPlayableFromObjectSingle(game, fromZone, mainCard.getLeftHalfCard(), mainCard.getLeftHalfCard().getAbilities(game), availableMana, output); getPlayableFromObjectSingle(game, fromZone, mainCard.getLeftHalfCard(), mainCard.getLeftHalfCard().getAbilities(game), availableMana, output);
getPlayableFromObjectSingle(game, fromZone, mainCard.getRightHalfCard(), mainCard.getRightHalfCard().getAbilities(game), availableMana, output); getPlayableFromObjectSingle(game, fromZone, mainCard.getRightHalfCard(), mainCard.getRightHalfCard().getAbilities(game), availableMana, output);
getPlayableFromObjectSingle(game, fromZone, mainCard, mainCard.getSharedAbilities(game), availableMana, output); getPlayableFromObjectSingle(game, fromZone, mainCard, mainCard.getSharedAbilities(game), availableMana, output);
} else if (object instanceof AdventureCard) { } else if (object instanceof CardWithSpellOption) {
// adventure must use different card characteristics for different spells (main or adventure) // adventure must use different card characteristics for different spells (main or adventure)
AdventureCard adventureCard = (AdventureCard) object; CardWithSpellOption cardWithSpellOption = (CardWithSpellOption) object;
getPlayableFromObjectSingle(game, fromZone, adventureCard.getSpellCard(), adventureCard.getSpellCard().getAbilities(game), availableMana, output); getPlayableFromObjectSingle(game, fromZone, cardWithSpellOption.getSpellCard(), cardWithSpellOption.getSpellCard().getAbilities(game), availableMana, output);
getPlayableFromObjectSingle(game, fromZone, adventureCard, adventureCard.getSharedAbilities(game), availableMana, output); getPlayableFromObjectSingle(game, fromZone, cardWithSpellOption, cardWithSpellOption.getSharedAbilities(game), availableMana, output);
} else if (object instanceof Card) { } else if (object instanceof Card) {
getPlayableFromObjectSingle(game, fromZone, object, ((Card) object).getAbilities(game), availableMana, output); getPlayableFromObjectSingle(game, fromZone, object, ((Card) object).getAbilities(game), availableMana, output);
} else if (object instanceof StackObject) { } else if (object instanceof StackObject) {

View file

@ -1272,7 +1272,7 @@ public final class CardUtil {
Card permCard; Card permCard;
if (card instanceof SplitCard) { if (card instanceof SplitCard) {
permCard = card; permCard = card;
} else if (card instanceof AdventureCard) { } else if (card instanceof CardWithSpellOption) {
permCard = card; permCard = card;
} else if (card instanceof ModalDoubleFacedCard) { } else if (card instanceof ModalDoubleFacedCard) {
permCard = ((ModalDoubleFacedCard) card).getLeftHalfCard(); permCard = ((ModalDoubleFacedCard) card).getLeftHalfCard();
@ -1460,9 +1460,9 @@ public final class CardUtil {
if (cardToCast instanceof CardWithHalves) { if (cardToCast instanceof CardWithHalves) {
cards.add(((CardWithHalves) cardToCast).getLeftHalfCard()); cards.add(((CardWithHalves) cardToCast).getLeftHalfCard());
cards.add(((CardWithHalves) cardToCast).getRightHalfCard()); cards.add(((CardWithHalves) cardToCast).getRightHalfCard());
} else if (cardToCast instanceof AdventureCard) { } else if (cardToCast instanceof CardWithSpellOption) {
cards.add(cardToCast); cards.add(cardToCast);
cards.add(((AdventureCard) cardToCast).getSpellCard()); cards.add(((CardWithSpellOption) cardToCast).getSpellCard());
} else { } else {
cards.add(cardToCast); cards.add(cardToCast);
} }
@ -1651,9 +1651,9 @@ public final class CardUtil {
} }
// handle adventure cards // handle adventure cards
if (card instanceof AdventureCard) { if (card instanceof CardWithSpellOption) {
Card creatureCard = card.getMainCard(); Card creatureCard = card.getMainCard();
Card spellCard = ((AdventureCard) card).getSpellCard(); Card spellCard = ((CardWithSpellOption) card).getSpellCard();
if (manaCost != null) { if (manaCost != null) {
// get additional cost if any // get additional cost if any
Costs<Cost> additionalCostsCreature = creatureCard.getSpellAbility().getCosts(); Costs<Cost> additionalCostsCreature = creatureCard.getSpellAbility().getCosts();
@ -1691,9 +1691,9 @@ public final class CardUtil {
game.getState().setValue("PlayFromNotOwnHandZone" + leftHalfCard.getId(), null); game.getState().setValue("PlayFromNotOwnHandZone" + leftHalfCard.getId(), null);
game.getState().setValue("PlayFromNotOwnHandZone" + rightHalfCard.getId(), null); game.getState().setValue("PlayFromNotOwnHandZone" + rightHalfCard.getId(), null);
} }
if (card instanceof AdventureCard) { if (card instanceof CardWithSpellOption) {
Card creatureCard = card.getMainCard(); Card creatureCard = card.getMainCard();
Card spellCard = ((AdventureCard) card).getSpellCard(); Card spellCard = ((CardWithSpellOption) card).getSpellCard();
game.getState().setValue("PlayFromNotOwnHandZone" + creatureCard.getId(), null); game.getState().setValue("PlayFromNotOwnHandZone" + creatureCard.getId(), null);
game.getState().setValue("PlayFromNotOwnHandZone" + spellCard.getId(), null); game.getState().setValue("PlayFromNotOwnHandZone" + spellCard.getId(), null);
} }
@ -2078,8 +2078,8 @@ public final class CardUtil {
res.add(mainCard); res.add(mainCard);
res.add(mainCard.getLeftHalfCard()); res.add(mainCard.getLeftHalfCard());
res.add(mainCard.getRightHalfCard()); res.add(mainCard.getRightHalfCard());
} else if (object instanceof AdventureCard || object instanceof AdventureCardSpell) { } else if (object instanceof CardWithSpellOption || object instanceof SpellOptionCard) {
AdventureCard mainCard = (AdventureCard) ((Card) object).getMainCard(); CardWithSpellOption mainCard = (CardWithSpellOption) ((Card) object).getMainCard();
res.add(mainCard); res.add(mainCard);
res.add(mainCard.getSpellCard()); res.add(mainCard.getSpellCard());
} else if (object instanceof Spell) { } else if (object instanceof Spell) {

View file

@ -13,10 +13,7 @@ import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.dynamicvalue.common.GetXValue;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.mana.*; import mage.abilities.mana.*;
import mage.cards.AdventureCard; import mage.cards.*;
import mage.cards.Card;
import mage.cards.ModalDoubleFacedCard;
import mage.cards.SplitCard;
import mage.choices.Choice; import mage.choices.Choice;
import mage.constants.ColoredManaSymbol; import mage.constants.ColoredManaSymbol;
import mage.constants.ManaType; import mage.constants.ManaType;
@ -644,8 +641,8 @@ public final class ManaUtil {
Card secondSide; Card secondSide;
if (card instanceof SplitCard) { if (card instanceof SplitCard) {
secondSide = ((SplitCard) card).getRightHalfCard(); secondSide = ((SplitCard) card).getRightHalfCard();
} else if (card instanceof AdventureCard) { } else if (card instanceof CardWithSpellOption) {
secondSide = ((AdventureCard) card).getSpellCard(); secondSide = ((CardWithSpellOption) card).getSpellCard();
} else if (card instanceof ModalDoubleFacedCard) { } else if (card instanceof ModalDoubleFacedCard) {
secondSide = ((ModalDoubleFacedCard) card).getRightHalfCard(); secondSide = ((ModalDoubleFacedCard) card).getRightHalfCard();
} else { } else {