[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

@ -0,0 +1,189 @@
package mage.cards;
import mage.abilities.Ability;
import mage.abilities.Modes;
import mage.abilities.SpellAbility;
import mage.abilities.effects.common.ExileAdventureSpellEffect;
import mage.constants.CardType;
import mage.constants.SpellAbilityType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.ExileZone;
import mage.game.Game;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author phulin
*/
public class AdventureSpellCard extends CardImpl implements SpellOptionCard {
private AdventureCard adventureCardParent;
public AdventureSpellCard(UUID ownerId, CardSetInfo setInfo, String adventureName, CardType[] cardTypes, String costs, AdventureCard adventureCardParent) {
super(ownerId, setInfo, cardTypes, costs, SpellAbilityType.ADVENTURE_SPELL);
this.subtype.add(SubType.ADVENTURE);
AdventureCardSpellAbility newSpellAbility = new AdventureCardSpellAbility(getSpellAbility(), adventureName, cardTypes, costs);
this.replaceSpellAbility(newSpellAbility);
spellAbility = newSpellAbility;
this.setName(adventureName);
this.adventureCardParent = adventureCardParent;
}
public void finalizeSpell() {
if (spellAbility instanceof AdventureCardSpellAbility) {
((AdventureCardSpellAbility) spellAbility).finalizeAdventure();
}
}
protected AdventureSpellCard(final AdventureSpellCard card) {
super(card);
this.adventureCardParent = card.adventureCardParent;
}
@Override
public UUID getOwnerId() {
return adventureCardParent.getOwnerId();
}
@Override
public String getExpansionSetCode() {
return adventureCardParent.getExpansionSetCode();
}
@Override
public String getCardNumber() {
return adventureCardParent.getCardNumber();
}
@Override
public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List<UUID> appliedEffects) {
return adventureCardParent.moveToZone(toZone, source, game, flag, appliedEffects);
}
@Override
public boolean moveToExile(UUID exileId, String name, Ability source, Game game, List<UUID> appliedEffects) {
return adventureCardParent.moveToExile(exileId, name, source, game, appliedEffects);
}
@Override
public AdventureCard getMainCard() {
return adventureCardParent;
}
@Override
public void setZone(Zone zone, Game game) {
game.setZone(adventureCardParent.getId(), zone);
game.setZone(adventureCardParent.getSpellCard().getId(), zone);
}
@Override
public AdventureSpellCard copy() {
return new AdventureSpellCard(this);
}
@Override
public void setParentCard(CardWithSpellOption card) {
this.adventureCardParent = (AdventureCard) card;
}
@Override
public AdventureCard getParentCard() {
return this.adventureCardParent;
}
@Override
public String getIdName() {
// id must send to main card (popup card hint in game logs)
return getName() + " [" + adventureCardParent.getId().toString().substring(0, 3) + ']';
}
@Override
public String getSpellType() {
return "Adventure";
}
}
class AdventureCardSpellAbility extends SpellAbility {
private String nameFull;
private boolean finalized = false;
public AdventureCardSpellAbility(final SpellAbility baseSpellAbility, String adventureName, CardType[] cardTypes, String costs) {
super(baseSpellAbility);
this.setName(cardTypes, adventureName, costs);
this.setCardName(adventureName);
}
// The exile effect needs to be added last.
public void finalizeAdventure() {
if (finalized) {
throw new IllegalStateException("Wrong code usage. "
+ "Adventure (" + cardName + ") "
+ "need to call finalizeAdventure() exactly once.");
}
this.addEffect(ExileAdventureSpellEffect.getInstance());
this.finalized = true;
}
protected AdventureCardSpellAbility(final AdventureCardSpellAbility ability) {
super(ability);
this.nameFull = ability.nameFull;
if (!ability.finalized) {
throw new IllegalStateException("Wrong code usage. "
+ "Adventure (" + cardName + ") "
+ "need to call finalizeAdventure() at the very end of the card's constructor.");
}
this.finalized = true;
}
@Override
public ActivationStatus canActivate(UUID playerId, Game game) {
ExileZone adventureExileZone = game.getExile().getExileZone(ExileAdventureSpellEffect.adventureExileId(playerId, game));
Card spellCard = game.getCard(this.getSourceId());
if (spellCard instanceof AdventureSpellCard) {
Card card = ((AdventureSpellCard) spellCard).getParentCard();
if (adventureExileZone != null && adventureExileZone.contains(card.getId())) {
return ActivationStatus.getFalse();
}
}
return super.canActivate(playerId, game);
}
public void setName(CardType[] cardTypes, String name, String costs) {
this.nameFull = "Adventure " + Arrays.stream(cardTypes).map(CardType::toString).collect(Collectors.joining(" ")) + " &mdash; " + name;
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 exile this card. You may cast the creature later from exile.)</i>");
return sbRule.toString();
}
@Override
public AdventureCardSpellAbility copy() {
return new AdventureCardSpellAbility(this);
}
}