[CLB] Implemented Faceless One

This commit is contained in:
Evan Kranzler 2022-05-17 20:05:18 -04:00
parent 7db20ecc72
commit 4777466b50
7 changed files with 136 additions and 44 deletions

View file

@ -1,9 +1,9 @@
package mage.deck;
import mage.MageObject;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.CanBeYourCommanderAbility;
import mage.abilities.common.ChooseABackgroundAbility;
import mage.abilities.common.CommanderChooseColorAbility;
import mage.abilities.keyword.CompanionAbility;
import mage.abilities.keyword.FriendsForeverAbility;
@ -14,6 +14,7 @@ import mage.cards.decks.Constructed;
import mage.cards.decks.Deck;
import mage.cards.decks.DeckValidatorErrorType;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.FilterMana;
import mage.util.CardUtil;
import mage.util.ManaUtil;
@ -46,14 +47,53 @@ public abstract class AbstractCommander extends Constructed {
protected abstract boolean checkBanned(Map<String, Integer> counts);
protected boolean checkCommander(Card commander) {
if ((!commander.hasCardTypeForDeckbuilding(CardType.CREATURE) || !commander.isLegendary())
&& !commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance())) {
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander invalid (" + commander.getName() + ')', true);
protected boolean checkCommander(Card commander, Set<Card> commanders) {
return commander.hasCardTypeForDeckbuilding(CardType.CREATURE) && commander.isLegendary()
|| commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance())
|| commander.hasSubTypeForDeckbuilding(SubType.BACKGROUND) && commanders.size() == 2;
}
protected boolean checkPartners(Set<Card> commanders) {
switch (commanders.size()) {
case 1:
return true;
case 2:
break;
default:
return false;
}
Iterator<Card> iter = commanders.iterator();
Card commander1 = iter.next();
Card commander2 = iter.next();
if (commander1.getAbilities().containsClass(PartnerAbility.class)
&& commander2.getAbilities().containsClass(PartnerAbility.class)
|| commander1.getAbilities().containsClass(FriendsForeverAbility.class)
&& commander2.getAbilities().containsClass(FriendsForeverAbility.class)) {
return true;
}
if (commander1.getAbilities().containsClass(PartnerWithAbility.class)
&& commander2.getAbilities().containsClass(PartnerWithAbility.class)) {
String name1 = CardUtil.castStream(commander2.getAbilities().stream(), PartnerWithAbility.class).map(PartnerWithAbility::getPartnerName).findFirst().orElse(null);
String name2 = CardUtil.castStream(commander1.getAbilities().stream(), PartnerWithAbility.class).map(PartnerWithAbility::getPartnerName).findFirst().orElse(null);
if (commander1.getName().equals(name1) && commander2.getName().equals(name2)) {
return true;
}
addError(DeckValidatorErrorType.PRIMARY, commander1.getName(), "Commander with invalid Partner (" + commander1.getName() + ')', true);
addError(DeckValidatorErrorType.PRIMARY, commander2.getName(), "Commander with invalid Partner (" + commander2.getName() + ')', true);
return false;
}
if (commander1.getAbilities().containsClass(ChooseABackgroundAbility.class) == commander2.hasSubTypeForDeckbuilding(SubType.BACKGROUND)
|| commander2.getAbilities().containsClass(ChooseABackgroundAbility.class) == commander1.hasSubTypeForDeckbuilding(SubType.BACKGROUND)) {
return true;
}
if (commander1.hasSubTypeForDeckbuilding(SubType.BACKGROUND)) {
addError(DeckValidatorErrorType.PRIMARY, commander1.getName(), "Background without valid Commander (" + commander1.getName() + ')', true);
}
if (commander2.hasSubTypeForDeckbuilding(SubType.BACKGROUND)) {
addError(DeckValidatorErrorType.PRIMARY, commander1.getName(), "Background without valid Commander (" + commander2.getName() + ')', true);
}
return false;
}
private boolean checkColorIdentity(Deck deck, FilterMana colorIdentity, Set<Card> commanders) {
int piperCount = commanders
@ -175,40 +215,15 @@ public abstract class AbstractCommander extends Constructed {
countCards(counts, deck.getCards());
countCards(counts, deck.getSideboard());
valid = checkCounts(1, counts) && valid;
valid = checkBanned(counts) && valid;
valid = checkPartners(commanders) && valid;
Set<String> commanderNames = new HashSet<>();
for (Card commander : commanders) {
commanderNames.add(commander.getName());
}
if (commanders.size() == 2
&& commanders
.stream()
.map(MageObject::getAbilities)
.filter(abilities -> abilities.contains(PartnerAbility.getInstance()))
.count() != 2
&& commanders
.stream()
.map(MageObject::getAbilities)
.filter(abilities -> abilities.contains(FriendsForeverAbility.getInstance()))
.count() != 2
&& !CardUtil
.castStream(commanders.stream().map(MageObject::getAbilities), PartnerWithAbility.class)
.map(PartnerWithAbility::getPartnerName)
.allMatch(commanderNames::contains)) {
for (Card commander : commanders) {
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander with invalid Partner (" + commander.getName() + ')', true);
valid = false;
}
}
for (Card commander : commanders) {
if (bannedCommander.contains(commander.getName())) {
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander banned (" + commander.getName() + ')', true);
valid = false;
}
if ((!commander.hasCardTypeForDeckbuilding(CardType.CREATURE) || !commander.isLegendary())
&& !commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance())) {
if (!checkCommander(commander, commanders)) {
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander invalid (" + commander.getName() + ')', true);
valid = false;
}
@ -246,17 +261,15 @@ public abstract class AbstractCommander extends Constructed {
if (companion != null) {
Set<Card> cards = new HashSet<>(deck.getCards());
cards.addAll(commanders);
for (Ability ability : companion.getAbilities()) {
if (ability instanceof CompanionAbility) {
CompanionAbility companionAbility = (CompanionAbility) ability;
if (!companionAbility.isLegal(cards, getDeckMinSize())) {
CompanionAbility companionAbility = CardUtil.castStream(
companion.getAbilities().stream(),
CompanionAbility.class
).findFirst().orElse(null);
if (companionAbility == null || !companionAbility.isLegal(cards, getDeckMinSize())) {
addError(DeckValidatorErrorType.PRIMARY, companion.getName(),
String.format("Commander companion illegal: %s", companionAbility.getLegalRule()), true);
valid = false;
}
break;
}
}
}
return valid;
}

View file

@ -7,6 +7,7 @@ import mage.cards.decks.DeckValidatorErrorType;
import mage.constants.CardType;
import java.util.Map;
import java.util.Set;
/**
* @author spjspj
@ -33,7 +34,7 @@ public class FreeformCommander extends AbstractCommander {
}
@Override
protected boolean checkCommander(Card commander) {
protected boolean checkCommander(Card commander, Set<Card> commanders) {
if (!commander.hasCardTypeForDeckbuilding(CardType.CREATURE) && !commander.isLegendary()) {
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "For Freeform Commander, the commander must be a creature or be legendary. Yours was: " + commander.getName(), true);
return false;

View file

@ -0,0 +1,42 @@
package mage.cards.f;
import mage.MageInt;
import mage.abilities.common.ChooseABackgroundAbility;
import mage.abilities.common.CommanderChooseColorAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class FacelessOne extends CardImpl {
public FacelessOne(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{5}");
this.addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.BACKGROUND);
this.power = new MageInt(3);
this.toughness = new MageInt(3);
// If Faceless One is your commander, choose a color before the game begins. Faceless One is the chosen color.
this.addAbility(new CommanderChooseColorAbility());
// Choose a Background
this.addAbility(ChooseABackgroundAbility.getInstance());
}
private FacelessOne(final FacelessOne card) {
super(card);
}
@Override
public FacelessOne copy() {
return new FacelessOne(this);
}
}

View file

@ -24,6 +24,7 @@ public final class CommanderLegendsBattleForBaldursGate extends ExpansionSet {
cards.add(new SetCardInfo("Ancient Brass Dragon", 111, Rarity.MYTHIC, mage.cards.a.AncientBrassDragon.class));
cards.add(new SetCardInfo("Bountiful Promenade", 348, Rarity.RARE, mage.cards.b.BountifulPromenade.class));
cards.add(new SetCardInfo("Elder Brain", 125, Rarity.RARE, mage.cards.e.ElderBrain.class));
cards.add(new SetCardInfo("Faceless One", 1, Rarity.COMMON, mage.cards.f.FacelessOne.class));
cards.add(new SetCardInfo("Fireball", 175, Rarity.UNCOMMON, mage.cards.f.Fireball.class));
cards.add(new SetCardInfo("Lightning Bolt", 187, Rarity.COMMON, mage.cards.l.LightningBolt.class));
cards.add(new SetCardInfo("Luxury Suite", 355, Rarity.RARE, mage.cards.l.LuxurySuite.class));

View file

@ -0,0 +1,33 @@
package mage.abilities.common;
import mage.abilities.MageSingleton;
import mage.abilities.StaticAbility;
import mage.abilities.effects.common.InfoEffect;
import mage.constants.Zone;
import java.io.ObjectStreamException;
/**
* @author TheElk801
*/
public class ChooseABackgroundAbility extends StaticAbility implements MageSingleton {
private static final ChooseABackgroundAbility instance = new ChooseABackgroundAbility();
private Object readResolve() throws ObjectStreamException {
return instance;
}
public static ChooseABackgroundAbility getInstance() {
return instance;
}
private ChooseABackgroundAbility() {
super(Zone.ALL, new InfoEffect("choose a background"));
}
@Override
public ChooseABackgroundAbility copy() {
return instance;
}
}

View file

@ -31,6 +31,7 @@ public enum SubType {
TOWER("Tower", SubTypeSet.NonBasicLandType),
// 205.3h Enchantments have their own unique set of subtypes; these subtypes are called enchantment types.
AURA("Aura", SubTypeSet.EnchantmentType),
BACKGROUND("Background", SubTypeSet.EnchantmentType),
CARTOUCHE("Cartouche", SubTypeSet.EnchantmentType),
CLASS("Class", SubTypeSet.EnchantmentType),
CURSE("Curse", SubTypeSet.EnchantmentType),

View file

@ -44183,6 +44183,7 @@ Island|Streets of New Capenna|264|C||Basic Land - Island|||({T}: Add {U}.)|
Swamp|Streets of New Capenna|266|C||Basic Land - Swamp|||({T}: Add {B}.)|
Mountain|Streets of New Capenna|268|C||Basic Land - Mountain|||({T}: Add {R}.)|
Forest|Streets of New Capenna|270|C||Basic Land - Forest|||({T}: Add {G}.)|
Faceless One|Commander Legends: Battle for Baldur's Gate|1|C|{5}|Legendary Enchantment Creature - Background|3|3|If Faceless One is your commander, choose a color before the game begins. Faceless One is the chosen color.$Choose a Background|
Ancient Brass Dragon|Commander Legends: Battle for Baldur's Gate|111|M|{5}{B}{B}|Creature - Elder Dragon|7|6|Flying$Whenever Ancient Brass Dragon deals combat damage to a player, roll a d20. When you do, put any number of target creature cards with mana value X or less from graveyards onto the battlefield under your control, where X is the result.|
Elder Brain|Commander Legends: Battle for Baldur's Gate|125|R|{5}{B}{B}|Creature - Horror|6|6|Menace$Whenever Elder Brain attacks a player, exile all cards from that player's hand, then they draw that many cards. You may play lands and cast spells from among the exiled cards for as long as they remain exiled. If you cast a spell this way, you may spend mana as though it were mana of any color to cast it.|
Fireball|Commander Legends: Battle for Baldur's Gate|175|U|{X}{R}|Sorcery|||This spell costs {1} more to cast for each target beyond the first.$Fireball deals X damage divided evenly, rounded down, among any number of targets.|