new feature: Emblem Cards (#10498)

* new feature: Emblem Cards

Allows match/tournament creator to specify cards to give each player
emblem versions of (or just the starting player for symmetric effects).

Technical details:
- new UI for specifying emblem cards (.dck files)
  - available for all match/tournament types
- new class `EmblemOfCard`
- new method `copyWithZone` on `AbilityImpl` (used to make abilities
  work from command zone)
- new fields on `GameOptions` and `MatchOptions` for emblem cards
- emblems are granted after mulligans, before first turn (technically
  after Planechase starting plane creation)

* fixes

* defaults for emblem cards in match options (fixes quick game buttons)

* minor fixes

* use DeckCardInfo instead of Card for emblem cards options

* restore accessible parent properties

* fix images for card emblems

* look up cards in a way that preserves which art

* fix typos; make Emblem.sourceObject protected

* add descriptions to planechase and emblem cards

* fixes

* add some unit tests for known working cards

* fix author name

* add explanation comment

* fix up tests

* copyWithZone: no longer modifies zone for singleton abilities

* directly check for MageSingleton
This commit is contained in:
Artemis Kearney 2023-09-26 21:47:13 -05:00 committed by GitHub
parent 04dba063aa
commit 41874b0b4b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 774 additions and 39 deletions

View file

@ -22,6 +22,7 @@ import mage.abilities.mana.TriggeredManaAbility;
import mage.actions.impl.MageAction;
import mage.cards.*;
import mage.cards.decks.Deck;
import mage.cards.decks.DeckCardInfo;
import mage.choices.Choice;
import mage.constants.*;
import mage.counters.CounterType;
@ -41,6 +42,7 @@ import mage.game.combat.Combat;
import mage.game.combat.CombatGroup;
import mage.game.command.*;
import mage.game.command.dungeons.UndercityDungeon;
import mage.game.command.emblems.EmblemOfCard;
import mage.game.command.emblems.TheRingEmblem;
import mage.game.events.*;
import mage.game.events.TableEvent.EventType;
@ -1317,6 +1319,22 @@ public abstract class GameImpl implements Game {
addPlane(plane, startingPlayerId);
state.setPlaneChase(this, gameOptions.planeChase);
}
if (!gameOptions.perPlayerEmblemCards.isEmpty()) {
for (UUID playerId : state.getPlayerList(startingPlayerId)) {
for (DeckCardInfo info : gameOptions.perPlayerEmblemCards) {
Card card = EmblemOfCard.cardFromDeckInfo(info);
addEmblem(new EmblemOfCard(card), card, playerId);
}
}
}
if (!gameOptions.globalEmblemCards.isEmpty()) {
for (DeckCardInfo info : gameOptions.globalEmblemCards) {
Card card = EmblemOfCard.cardFromDeckInfo(info);
addEmblem(new EmblemOfCard(card), card, startingPlayerId);
}
}
}
public void initGameDefaultWatchers() {