mirror of
https://github.com/correl/mage.git
synced 2024-11-14 11:09:31 +00:00
Implementing The Prismatic Piper (Ready for review) (#8164)
* [CMR] Implemented The Prismatic Piper * updated commander validation to handle The Prismatic Piper * created abstract base class for commander variants * added ability to prismatic piper * added game init handling * small revert * small reorganization of tests * added some validation tests for piper * added more tests for piper * add another test * added decklist comments to tests * added some more piper tests * added another test * added mana option tests * added a companion test * fix conflict * updated abstract commander to work with Friends forever * merge fix * Deck: added details for illegal validation of companion card; Co-authored-by: Oleg Agafonov <jaydi85@gmail.com>
This commit is contained in:
parent
966cb7ccb7
commit
02017b9a88
33 changed files with 1753 additions and 1272 deletions
File diff suppressed because it is too large
Load diff
|
@ -156,7 +156,8 @@ public class Brawl extends Constructed {
|
|||
if (ability instanceof CompanionAbility) {
|
||||
CompanionAbility companionAbility = (CompanionAbility) ability;
|
||||
if (!companionAbility.isLegal(cards, getDeckMinSize())) {
|
||||
addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Brawl Companion Invalid", true);
|
||||
addError(DeckValidatorErrorType.PRIMARY, companion.getName(),
|
||||
String.format("Brawl companion illegal: %s", companionAbility.getLegalRule()), true);
|
||||
valid = false;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -1,34 +1,15 @@
|
|||
package mage.deck;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.CanBeYourCommanderAbility;
|
||||
import mage.abilities.keyword.CompanionAbility;
|
||||
import mage.abilities.keyword.FriendsForeverAbility;
|
||||
import mage.abilities.keyword.PartnerAbility;
|
||||
import mage.abilities.keyword.PartnerWithAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.ExpansionSet;
|
||||
import mage.cards.Sets;
|
||||
import mage.cards.decks.Constructed;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.cards.decks.DeckValidatorErrorType;
|
||||
import mage.constants.CardType;
|
||||
import mage.filter.FilterMana;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.ManaUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Plopman
|
||||
*/
|
||||
public class Commander extends Constructed {
|
||||
|
||||
protected final List<String> bannedCommander = new ArrayList<>();
|
||||
protected final List<String> bannedPartner = new ArrayList<>();
|
||||
protected boolean partnerAllowed = true;
|
||||
public class Commander extends AbstractCommander {
|
||||
|
||||
public Commander() {
|
||||
super("Commander");
|
||||
|
@ -97,922 +78,14 @@ public class Commander extends Constructed {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int getDeckMinSize() {
|
||||
return 98;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSideboardMinSize() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(Deck deck) {
|
||||
protected boolean checkBanned(Map<String, Integer> counts) {
|
||||
boolean valid = true;
|
||||
errorsList.clear();
|
||||
FilterMana colorIdentity = new FilterMana();
|
||||
Set<Card> commanders = new HashSet<>();
|
||||
Card companion;
|
||||
|
||||
int sbsize = deck.getSideboard().size();
|
||||
Card card1;
|
||||
Card card2;
|
||||
Card card3;
|
||||
Iterator<Card> iter;
|
||||
switch (deck.getSideboard().size()) {
|
||||
case 1:
|
||||
companion = null;
|
||||
commanders.add(deck.getSideboard().iterator().next());
|
||||
break;
|
||||
case 2:
|
||||
iter = deck.getSideboard().iterator();
|
||||
card1 = iter.next();
|
||||
card2 = iter.next();
|
||||
if (card1.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) {
|
||||
companion = card1;
|
||||
commanders.add(card2);
|
||||
} else if (card2.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) {
|
||||
companion = card2;
|
||||
commanders.add(card1);
|
||||
} else {
|
||||
companion = null;
|
||||
commanders.add(card1);
|
||||
commanders.add(card2);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
iter = deck.getSideboard().iterator();
|
||||
card1 = iter.next();
|
||||
card2 = iter.next();
|
||||
card3 = iter.next();
|
||||
if (card1.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) {
|
||||
companion = card1;
|
||||
commanders.add(card2);
|
||||
commanders.add(card3);
|
||||
} else if (card2.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) {
|
||||
companion = card2;
|
||||
commanders.add(card1);
|
||||
commanders.add(card3);
|
||||
} else if (card3.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) {
|
||||
companion = card3;
|
||||
commanders.add(card1);
|
||||
commanders.add(card2);
|
||||
} else {
|
||||
companion = null;
|
||||
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion");
|
||||
valid = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
companion = null;
|
||||
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (companion != null && deck.getCards().size() + deck.getSideboard().size() != 101) {
|
||||
addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 101 + " cards (companion doesn't count for deck size): has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards");
|
||||
valid = false;
|
||||
} else if (companion == null && deck.getCards().size() + deck.getSideboard().size() != 100) {
|
||||
addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 100 + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
Map<String, Integer> counts = new HashMap<>();
|
||||
countCards(counts, deck.getCards());
|
||||
countCards(counts, deck.getSideboard());
|
||||
valid = checkCounts(1, counts) && valid;
|
||||
|
||||
for (String bannedCard : banned) {
|
||||
if (counts.containsKey(bannedCard)) {
|
||||
addError(DeckValidatorErrorType.BANNED, bannedCard, "Banned", true);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
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())) {
|
||||
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander invalid (" + commander.getName() + ')', true);
|
||||
valid = false;
|
||||
}
|
||||
if (commanders.size() == 2 && bannedPartner.contains(commander.getName())) {
|
||||
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander Partner banned (" + commander.getName() + ')', true);
|
||||
valid = false;
|
||||
}
|
||||
ManaUtil.collectColorIdentity(colorIdentity, commander.getColorIdentity());
|
||||
}
|
||||
|
||||
// no needs in cards check on wrong commanders
|
||||
if (!valid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Card card : deck.getCards()) {
|
||||
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
|
||||
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
for (Card card : deck.getSideboard()) {
|
||||
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
|
||||
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
for (Card card : deck.getCards()) {
|
||||
if (!isSetAllowed(card.getExpansionSetCode())) {
|
||||
if (!legalSets(card)) {
|
||||
addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Card card : deck.getSideboard()) {
|
||||
if (!isSetAllowed(card.getExpansionSetCode())) {
|
||||
if (!legalSets(card)) {
|
||||
addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check for companion legality
|
||||
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())) {
|
||||
addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Commander Companion (deck invalid for companion)", true);
|
||||
valid = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEdhPowerLevel(Deck deck) {
|
||||
if (deck == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int edhPowerLevel = 0;
|
||||
int commanderColors = 0;
|
||||
int numberInfinitePieces = 0;
|
||||
|
||||
for (Card card : deck.getCards()) {
|
||||
|
||||
int thisMaxPower = 0;
|
||||
|
||||
// Examine rules to work out most egregious functions in edh
|
||||
boolean anyNumberOfTarget = false;
|
||||
boolean annihilator = false;
|
||||
boolean buyback = false;
|
||||
boolean cascade = false;
|
||||
boolean cantBe = false;
|
||||
boolean cantUntap = false;
|
||||
boolean copy = false;
|
||||
boolean costLessEach = false;
|
||||
boolean createToken = false;
|
||||
boolean dredge = false;
|
||||
boolean exile = false;
|
||||
boolean exileAll = false;
|
||||
boolean counter = false;
|
||||
boolean destroy = false;
|
||||
boolean destroyAll = false;
|
||||
boolean each = false;
|
||||
boolean exalted = false;
|
||||
boolean doesntUntap = false;
|
||||
boolean drawCards = false;
|
||||
boolean evoke = false;
|
||||
boolean extraTurns = false;
|
||||
boolean flash = false;
|
||||
boolean flashback = false;
|
||||
boolean flicker = false;
|
||||
boolean gainControl = false;
|
||||
boolean hexproof = false;
|
||||
boolean infect = false;
|
||||
boolean lifeTotalBecomes = false;
|
||||
boolean mayCastForFree = false;
|
||||
boolean menace = false;
|
||||
boolean miracle = false;
|
||||
boolean overload = false;
|
||||
boolean persist = false;
|
||||
boolean preventDamage = false;
|
||||
boolean proliferate = false;
|
||||
boolean protection = false;
|
||||
boolean putUnderYourControl = false;
|
||||
boolean retrace = false;
|
||||
boolean returnFromYourGY = false;
|
||||
boolean sacrifice = false;
|
||||
boolean shroud = false;
|
||||
boolean skip = false;
|
||||
boolean sliver = false;
|
||||
boolean storm = false;
|
||||
boolean trample = false;
|
||||
boolean tutor = false;
|
||||
boolean tutorBasic = false;
|
||||
boolean twiceAs = false;
|
||||
boolean unblockable = false;
|
||||
boolean undying = false;
|
||||
boolean untapTarget = false;
|
||||
boolean wheneverEnters = false;
|
||||
boolean whenCounterThatSpell = false;
|
||||
boolean xCost = false;
|
||||
boolean youControlTarget = false;
|
||||
boolean yourOpponentsControl = false;
|
||||
boolean whenYouCast = false;
|
||||
|
||||
for (String str : card.getRules()) {
|
||||
String s = str.toLowerCase(Locale.ENGLISH);
|
||||
annihilator |= s.contains("annihilator");
|
||||
anyNumberOfTarget |= s.contains("any number");
|
||||
buyback |= s.contains("buyback");
|
||||
cantUntap |= s.contains("can't untap") || s.contains("don't untap");
|
||||
cantBe |= s.contains("can't be");
|
||||
cascade |= s.contains("cascade");
|
||||
copy |= s.contains("copy");
|
||||
costLessEach |= s.contains("cost") || s.contains("less") || s.contains("each");
|
||||
counter |= s.contains("counter") && s.contains("target");
|
||||
createToken |= s.contains("create") && s.contains("token");
|
||||
destroy |= s.contains("destroy");
|
||||
destroyAll |= s.contains("destroy all");
|
||||
doesntUntap |= s.contains("doesn't untap");
|
||||
doesntUntap |= s.contains("don't untap");
|
||||
drawCards |= s.contains("draw cards");
|
||||
dredge |= s.contains("dredge");
|
||||
each |= s.contains("each");
|
||||
evoke |= s.contains("evoke");
|
||||
exalted |= s.contains("exalted");
|
||||
exile |= s.contains("exile");
|
||||
exileAll |= s.contains("exile") && s.contains(" all ");
|
||||
extraTurns |= s.contains("extra turn");
|
||||
flicker |= s.contains("exile") && s.contains("return") && s.contains("to the battlefield under");
|
||||
flash |= s.contains("flash");
|
||||
flashback |= s.contains("flashback");
|
||||
gainControl |= s.contains("gain control");
|
||||
hexproof |= s.contains("hexproof");
|
||||
infect |= s.contains("infect");
|
||||
lifeTotalBecomes |= s.contains("life total becomes");
|
||||
mayCastForFree |= s.contains("may cast") && s.contains("without paying");
|
||||
menace |= s.contains("menace");
|
||||
miracle |= s.contains("miracle");
|
||||
overload |= s.contains("overload");
|
||||
persist |= s.contains("persist");
|
||||
preventDamage |= s.contains("prevent") && s.contains("all") && s.contains("damage");
|
||||
proliferate |= s.contains("proliferate");
|
||||
protection |= s.contains("protection");
|
||||
putUnderYourControl |= s.contains("put") && s.contains("under your control");
|
||||
retrace |= s.contains("retrace");
|
||||
returnFromYourGY |= s.contains("return") && s.contains("from your graveyard");
|
||||
sacrifice |= s.contains("sacrifice");
|
||||
shroud |= s.contains("shroud");
|
||||
skip |= s.contains("skip");
|
||||
sliver |= s.contains("sliver");
|
||||
storm |= s.contains("storm");
|
||||
trample |= s.contains("trample");
|
||||
tutor |= s.contains("search your library") && !s.contains("basic land");
|
||||
tutorBasic |= s.contains("search your library") && s.contains("basic land");
|
||||
twiceAs |= s.contains("twice that many") || s.contains("twice as much");
|
||||
unblockable |= s.contains("can't be blocked");
|
||||
undying |= s.contains("undying");
|
||||
untapTarget |= s.contains("untap target");
|
||||
whenCounterThatSpell |= s.contains("when") && s.contains("counter that spell");
|
||||
wheneverEnters |= s.contains("when") && s.contains("another") && s.contains("enters");
|
||||
youControlTarget |= s.contains("you control target");
|
||||
yourOpponentsControl |= s.contains("your opponents control");
|
||||
whenYouCast |= s.contains("when you cast") || s.contains("whenever you cast");
|
||||
}
|
||||
|
||||
for (String s : card.getManaCostSymbols()) {
|
||||
if (s.contains("X")) {
|
||||
xCost = true;
|
||||
}
|
||||
}
|
||||
for (Ability a : card.getAbilities()) {
|
||||
for (String s : a.getManaCostSymbols()) {
|
||||
if (s.contains("X")) {
|
||||
xCost = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (extraTurns) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 7);
|
||||
}
|
||||
if (buyback) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 6);
|
||||
}
|
||||
if (tutor) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 6);
|
||||
}
|
||||
if (annihilator) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 5);
|
||||
}
|
||||
if (cantUntap) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 5);
|
||||
}
|
||||
if (costLessEach) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 5);
|
||||
}
|
||||
if (infect) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 5);
|
||||
}
|
||||
if (overload) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 5);
|
||||
}
|
||||
if (twiceAs) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 5);
|
||||
}
|
||||
if (cascade) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (doesntUntap) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (each) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (exileAll) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (flash) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (flashback) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (flicker) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (gainControl) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (lifeTotalBecomes) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (mayCastForFree) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (preventDamage) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (proliferate) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (protection) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (putUnderYourControl) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (returnFromYourGY) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (sacrifice) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 2);
|
||||
}
|
||||
if (skip) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (storm) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (unblockable) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (whenCounterThatSpell) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (wheneverEnters) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (xCost) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (youControlTarget) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (yourOpponentsControl) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (whenYouCast) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 4);
|
||||
}
|
||||
if (anyNumberOfTarget) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 3);
|
||||
}
|
||||
if (createToken) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 3);
|
||||
}
|
||||
if (destroyAll) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 3);
|
||||
}
|
||||
if (dredge) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 3);
|
||||
}
|
||||
if (hexproof) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 3);
|
||||
}
|
||||
if (shroud) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 3);
|
||||
}
|
||||
if (undying) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 3);
|
||||
}
|
||||
if (persist) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 3);
|
||||
}
|
||||
if (cantBe) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 2);
|
||||
}
|
||||
if (evoke) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 2);
|
||||
}
|
||||
if (exile) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 2);
|
||||
}
|
||||
if (menace) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 2);
|
||||
}
|
||||
if (miracle) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 2);
|
||||
}
|
||||
if (sliver) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 2);
|
||||
}
|
||||
if (untapTarget) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 2);
|
||||
}
|
||||
if (copy) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 1);
|
||||
}
|
||||
if (counter) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 1);
|
||||
}
|
||||
if (destroy) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 1);
|
||||
}
|
||||
if (drawCards) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 1);
|
||||
}
|
||||
if (exalted) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 1);
|
||||
}
|
||||
if (retrace) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 1);
|
||||
}
|
||||
if (trample) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 1);
|
||||
}
|
||||
if (tutorBasic) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 1);
|
||||
}
|
||||
|
||||
if (card.isPlaneswalker()) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 6);
|
||||
}
|
||||
|
||||
String cn = card.getName().toLowerCase(Locale.ENGLISH);
|
||||
if (cn.equals("ancient tomb")
|
||||
|| cn.equals("anafenza, the foremost")
|
||||
|| cn.equals("arcum dagsson")
|
||||
|| cn.equals("armageddon")
|
||||
|| cn.equals("aura shards")
|
||||
|| cn.equals("azami, lady of scrolls")
|
||||
|| cn.equals("azusa, lost but seeking")
|
||||
|| cn.equals("back to basics")
|
||||
|| cn.equals("bane of progress")
|
||||
|| cn.equals("basalt monolith")
|
||||
|| cn.equals("blightsteel collossus")
|
||||
|| cn.equals("blood moon")
|
||||
|| cn.equals("braids, cabal minion")
|
||||
|| cn.equals("cabal coffers")
|
||||
|| cn.equals("captain sisay")
|
||||
|| cn.equals("celestial dawn")
|
||||
|| cn.equals("child of alara")
|
||||
|| cn.equals("coalition relic")
|
||||
|| cn.equals("craterhoof behemoth")
|
||||
|| cn.equals("deepglow skate")
|
||||
|| cn.equals("derevi, empyrial tactician")
|
||||
|| cn.equals("dig through time")
|
||||
|| cn.equals("edric, spymaster of trest")
|
||||
|| cn.equals("elesh norn, grand cenobite")
|
||||
|| cn.equals("entomb")
|
||||
|| cn.equals("force of will")
|
||||
|| cn.equals("food chain")
|
||||
|| cn.equals("gaddock teeg")
|
||||
|| cn.equals("gaea's cradle")
|
||||
|| cn.equals("grand arbiter augustin iv")
|
||||
|| cn.equals("grim monolith")
|
||||
|| cn.equals("hermit druid")
|
||||
|| cn.equals("hokori, dust drinker")
|
||||
|| cn.equals("humility")
|
||||
|| cn.equals("imperial seal")
|
||||
|| cn.equals("iona, shield of emeria")
|
||||
|| cn.equals("jin-gitaxias, core augur")
|
||||
|| cn.equals("karador, ghost chieftain")
|
||||
|| cn.equals("karakas")
|
||||
|| cn.equals("kataki, war's wage")
|
||||
|| cn.equals("knowledge pool")
|
||||
|| cn.equals("linvala, keeper of silence")
|
||||
|| cn.equals("living death")
|
||||
|| cn.equals("llawan, cephalid empress")
|
||||
|| cn.equals("loyal retainers")
|
||||
|| cn.equals("maelstrom wanderer")
|
||||
|| cn.equals("malfegor")
|
||||
|| cn.equals("master of cruelties")
|
||||
|| cn.equals("mana crypt")
|
||||
|| cn.equals("mana drain")
|
||||
|| cn.equals("mana vault")
|
||||
|| cn.equals("michiko konda, truth seeker")
|
||||
|| cn.equals("nath of the gilt-leaf")
|
||||
|| cn.equals("natural order")
|
||||
|| cn.equals("necrotic ooze")
|
||||
|| cn.equals("nicol bolas")
|
||||
|| cn.equals("numot, the devastator")
|
||||
|| cn.equals("oath of druids")
|
||||
|| cn.equals("pattern of rebirth")
|
||||
|| cn.equals("protean hulk")
|
||||
|| cn.equals("purphoros, god of the forge")
|
||||
|| cn.equals("ravages of war")
|
||||
|| cn.equals("reclamation sage")
|
||||
|| cn.equals("sen triplets")
|
||||
|| cn.equals("serra's sanctum")
|
||||
|| cn.equals("sheoldred, whispering one")
|
||||
|| cn.equals("sol ring")
|
||||
|| cn.equals("spore frog")
|
||||
|| cn.equals("stasis")
|
||||
|| cn.equals("strip mine")
|
||||
|| cn.equals("the tabernacle at pendrell vale")
|
||||
|| cn.equals("tinker")
|
||||
|| cn.equals("treasure cruise")
|
||||
|| cn.equals("urabrask the hidden")
|
||||
|| cn.equals("vorinclex, voice of hunger")
|
||||
|| cn.equals("winter orb")
|
||||
|| cn.equals("zur the enchanter")) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 12);
|
||||
}
|
||||
|
||||
// Parts of infinite combos
|
||||
if (cn.equals("animate artifact") || cn.equals("animar, soul of element")
|
||||
|| cn.equals("archaeomancer")
|
||||
|| cn.equals("ashnod's altar") || cn.equals("azami, lady of scrolls")
|
||||
|| cn.equals("aura flux")
|
||||
|| cn.equals("basalt monolith") || cn.equals("brago, king eternal")
|
||||
|| cn.equals("candelabra of tawnos") || cn.equals("cephalid aristocrat")
|
||||
|| cn.equals("cephalid illusionist") || cn.equals("changeling berserker")
|
||||
|| cn.equals("consecrated sphinx")
|
||||
|| cn.equals("cyclonic rift")
|
||||
|| cn.equals("the chain veil")
|
||||
|| cn.equals("cinderhaze wretch") || cn.equals("cryptic gateway")
|
||||
|| cn.equals("deadeye navigator") || cn.equals("derevi, empyrial tactician")
|
||||
|| cn.equals("doubling season") || cn.equals("dross scorpion")
|
||||
|| cn.equals("earthcraft") || cn.equals("erratic portal")
|
||||
|| cn.equals("enter the infinite") || cn.equals("omniscience")
|
||||
|| cn.equals("exquisite blood") || cn.equals("future sight")
|
||||
|| cn.equals("genesis chamber")
|
||||
|| cn.equals("ghave, guru of spores")
|
||||
|| cn.equals("grave pact")
|
||||
|| cn.equals("grave titan") || cn.equals("great whale")
|
||||
|| cn.equals("grim monolith") || cn.equals("gush")
|
||||
|| cn.equals("hellkite charger") || cn.equals("intruder alarm")
|
||||
|| cn.equals("helm of obedience")
|
||||
|| cn.equals("hermit druid")
|
||||
|| cn.equals("humility")
|
||||
|| cn.equals("iona, shield of emeria")
|
||||
|| cn.equals("karn, silver golem") || cn.equals("kiki-jiki, mirror breaker")
|
||||
|| cn.equals("krark-clan ironworks") || cn.equals("krenko, mob boss")
|
||||
|| cn.equals("krosan restorer") || cn.equals("laboratory maniac")
|
||||
|| cn.equals("leonin relic-warder") || cn.equals("leyline of the void")
|
||||
|| cn.equals("memnarch")
|
||||
|| cn.equals("meren of clan nel toth") || cn.equals("mikaeus, the unhallowed")
|
||||
|| cn.equals("mindcrank") || cn.equals("mindslaver")
|
||||
|| cn.equals("minion reflector") || cn.equals("mycosynth lattice")
|
||||
|| cn.equals("myr turbine") || cn.equals("narset, enlightened master")
|
||||
|| cn.equals("nekusar, the mindrazer") || cn.equals("norin the wary")
|
||||
|| cn.equals("notion thief")
|
||||
|| cn.equals("opalescence") || cn.equals("ornithopter")
|
||||
|| cn.equals("paradox engine")
|
||||
|| cn.equals("purphoros, god of the forge")
|
||||
|| cn.equals("peregrine drake") || cn.equals("palinchron")
|
||||
|| cn.equals("planar portal") || cn.equals("power artifact")
|
||||
|| cn.equals("rings of brighthearth") || cn.equals("rite of replication")
|
||||
|| cn.equals("sanguine bond") || cn.equals("sensei's divining top")
|
||||
|| cn.equals("splinter twin") || cn.equals("stony silence")
|
||||
|| cn.equals("sunder")
|
||||
|| cn.equals("storm cauldron") || cn.equals("teferi's puzzle box")
|
||||
|| cn.equals("tangle wire")
|
||||
|| cn.equals("teferi, mage of zhalfir")
|
||||
|| cn.equals("tezzeret the seeker") || cn.equals("time stretch")
|
||||
|| cn.equals("time warp") || cn.equals("training grounds")
|
||||
|| cn.equals("triskelavus") || cn.equals("triskelion")
|
||||
|| cn.equals("turnabout") || cn.equals("umbral mantle")
|
||||
|| cn.equals("uyo, silent prophet") || cn.equals("voltaic key")
|
||||
|| cn.equals("workhorse") || cn.equals("worldgorger dragon")
|
||||
|| cn.equals("worthy cause") || cn.equals("yawgmoth's will")
|
||||
|| cn.equals("zealous conscripts")) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 15);
|
||||
numberInfinitePieces++;
|
||||
}
|
||||
|
||||
// Saltiest cards (edhrec)
|
||||
if (cn.equals("acid rain")
|
||||
|| cn.equals("agent of treachery")
|
||||
|| cn.equals("apocalypse")
|
||||
|| cn.equals("armageddon")
|
||||
|| cn.equals("atraxa, praetors' voice")
|
||||
|| cn.equals("aura shards")
|
||||
|| cn.equals("avacyn, angel of hope")
|
||||
|| cn.equals("back to basics")
|
||||
|| cn.equals("bend or break")
|
||||
|| cn.equals("blightsteel colossus")
|
||||
|| cn.equals("blood moon")
|
||||
|| cn.equals("boil")
|
||||
|| cn.equals("boiling seas")
|
||||
|| cn.equals("bribery")
|
||||
|| cn.equals("burning sands")
|
||||
|| cn.equals("card view")
|
||||
|| cn.equals("cataclysm")
|
||||
|| cn.equals("catastrophe")
|
||||
|| cn.equals("chulane, teller of tales")
|
||||
|| cn.equals("confusion in the ranks")
|
||||
|| cn.equals("consecrated sphinx")
|
||||
|| cn.equals("contamination")
|
||||
|| cn.equals("craterhoof behemoth")
|
||||
|| cn.equals("cyclonic rift")
|
||||
|| cn.equals("death cloud")
|
||||
|| cn.equals("decree of annihilation")
|
||||
|| cn.equals("decree of silence")
|
||||
|| cn.equals("demonic consultation")
|
||||
|| cn.equals("derevi, empyrial tactician")
|
||||
|| cn.equals("devastation")
|
||||
|| cn.equals("divine intervention")
|
||||
|| cn.equals("dockside extortionist")
|
||||
|| cn.equals("doomsday")
|
||||
|| cn.equals("doubling season")
|
||||
|| cn.equals("drannith magistrate")
|
||||
|| cn.equals("elesh norn, grand cenobite")
|
||||
|| cn.equals("embargo")
|
||||
|| cn.equals("emrakul, the promised end")
|
||||
|| cn.equals("epicenter")
|
||||
|| cn.equals("expropriate")
|
||||
|| cn.equals("fall of the thran")
|
||||
|| cn.equals("fierce guardianship")
|
||||
|| cn.equals("food chain")
|
||||
|| cn.equals("force of negation")
|
||||
|| cn.equals("force of will")
|
||||
|| cn.equals("gaddock teeg")
|
||||
|| cn.equals("gaea's cradle")
|
||||
|| cn.equals("gilded drake")
|
||||
|| cn.equals("glenn, the voice of calm")
|
||||
|| cn.equals("global ruin")
|
||||
|| cn.equals("golos, tireless pilgrim")
|
||||
|| cn.equals("grand arbiter augustin iv")
|
||||
|| cn.equals("grip of chaos")
|
||||
|| cn.equals("hokori, dust drinker")
|
||||
|| cn.equals("humility")
|
||||
|| cn.equals("impending disaster")
|
||||
|| cn.equals("invoke prejudice")
|
||||
|| cn.equals("iona, shield of emeria")
|
||||
|| cn.equals("jin-gitaxias, core augur")
|
||||
|| cn.equals("jokulhaups")
|
||||
|| cn.equals("keldon firebombers")
|
||||
|| cn.equals("kinnan, bonder prodigy")
|
||||
|| cn.equals("kozilek, butcher of truth")
|
||||
|| cn.equals("land equilibrium")
|
||||
|| cn.equals("linvala, keeper of silence")
|
||||
|| cn.equals("magister sphinx")
|
||||
|| cn.equals("mana breach")
|
||||
|| cn.equals("mana crypt")
|
||||
|| cn.equals("mana drain")
|
||||
|| cn.equals("mana vortex")
|
||||
|| cn.equals("mindslaver")
|
||||
|| cn.equals("narset, enlightened master")
|
||||
|| cn.equals("narset, parter of veils")
|
||||
|| cn.equals("negan, the cold-blooded")
|
||||
|| cn.equals("nether void")
|
||||
|| cn.equals("nexus of fate")
|
||||
|| cn.equals("notion thief")
|
||||
|| cn.equals("obliterate")
|
||||
|| cn.equals("oko, thief of crowns")
|
||||
|| cn.equals("oloro, ageless ascetic")
|
||||
|| cn.equals("omniscience")
|
||||
|| cn.equals("opposition agent")
|
||||
|| cn.equals("oppression")
|
||||
|| cn.equals("overwhelming splendor")
|
||||
|| cn.equals("palinchron")
|
||||
|| cn.equals("paradox engine")
|
||||
|| cn.equals("possessed portal")
|
||||
|| cn.equals("price of glory")
|
||||
|| cn.equals("protean hulk")
|
||||
|| cn.equals("ravages of war")
|
||||
|| cn.equals("rhystic study")
|
||||
|| cn.equals("rick, steadfast leader")
|
||||
|| cn.equals("rising waters")
|
||||
|| cn.equals("ruination")
|
||||
|| cn.equals("scrambleverse")
|
||||
|| cn.equals("seedborn muse")
|
||||
|| cn.equals("sen triplets")
|
||||
|| cn.equals("sire of insanity")
|
||||
|| cn.equals("skithiryx, the blight dragon")
|
||||
|| cn.equals("smokestack")
|
||||
|| cn.equals("smothering tithe")
|
||||
|| cn.equals("sorin markov")
|
||||
|| cn.equals("stasis")
|
||||
|| cn.equals("static orb")
|
||||
|| cn.equals("storage matrix")
|
||||
|| cn.equals("sunder")
|
||||
|| cn.equals("survival of the fittest")
|
||||
|| cn.equals("table view")
|
||||
|| cn.equals("tainted aether")
|
||||
|| cn.equals("tectonic break")
|
||||
|| cn.equals("teferi's protection")
|
||||
|| cn.equals("teferi, master of time")
|
||||
|| cn.equals("teferi, time raveler")
|
||||
|| cn.equals("temporal manipulation")
|
||||
|| cn.equals("tergrid, god of fright")
|
||||
|| cn.equals("text view")
|
||||
|| cn.equals("thassa's oracle")
|
||||
|| cn.equals("the tabernacle at pendrell vale")
|
||||
|| cn.equals("thieves' auction")
|
||||
|| cn.equals("thoughts of ruin")
|
||||
|| cn.equals("thrasios, triton hero")
|
||||
|| cn.equals("time stretch")
|
||||
|| cn.equals("time warp")
|
||||
|| cn.equals("tooth and nail")
|
||||
|| cn.equals("torment of hailfire")
|
||||
|| cn.equals("torpor orb")
|
||||
|| cn.equals("triumph of the hordes")
|
||||
|| cn.equals("ugin, the spirit dragon")
|
||||
|| cn.equals("ulamog, the ceaseless hunger")
|
||||
|| cn.equals("ulamog, the infinite gyre")
|
||||
|| cn.equals("urza, lord high artificer")
|
||||
|| cn.equals("void winnower")
|
||||
|| cn.equals("vorinclex, voice of hunger")
|
||||
|| cn.equals("wake of destruction")
|
||||
|| cn.equals("warp world")
|
||||
|| cn.equals("winter orb")
|
||||
|| cn.equals("xanathar, guild kingpin")
|
||||
|| cn.equals("zur the enchanter")) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 15);
|
||||
}
|
||||
edhPowerLevel += thisMaxPower;
|
||||
}
|
||||
|
||||
ObjectColor color = null;
|
||||
for (Card commander : deck.getSideboard()) {
|
||||
int thisMaxPower = 0;
|
||||
String cn = commander.getName().toLowerCase(Locale.ENGLISH);
|
||||
if (color == null) {
|
||||
color = commander.getColor(null);
|
||||
} else {
|
||||
color = color.union(commander.getColor(null));
|
||||
}
|
||||
|
||||
FilterMana commanderColor = commander.getColorIdentity();
|
||||
if (commanderColor.isWhite()) {
|
||||
color.setWhite(true);
|
||||
}
|
||||
if (commanderColor.isBlue()) {
|
||||
color.setBlue(true);
|
||||
}
|
||||
if (commanderColor.isBlack()) {
|
||||
color.setBlack(true);
|
||||
}
|
||||
if (commanderColor.isRed()) {
|
||||
color.setRed(true);
|
||||
}
|
||||
if (commanderColor.isGreen()) {
|
||||
color.setGreen(true);
|
||||
}
|
||||
|
||||
// Least fun commanders
|
||||
if (cn.equals("animar, soul of element")
|
||||
|| cn.equals("anafenza, the foremost")
|
||||
|| cn.equals("arcum dagsson")
|
||||
|| cn.equals("azami, lady of scrolls")
|
||||
|| cn.equals("azusa, lost but seeking")
|
||||
|| cn.equals("brago, king eternal")
|
||||
|| cn.equals("braids, cabal minion")
|
||||
|| cn.equals("captain sisay")
|
||||
|| cn.equals("child of alara")
|
||||
|| cn.equals("derevi, empyrial tactician")
|
||||
|| cn.equals("edric, spymaster of trest")
|
||||
|| cn.equals("elesh norn, grand cenobite")
|
||||
|| cn.equals("gaddock teeg")
|
||||
|| cn.equals("grand arbiter augustin iv")
|
||||
|| cn.equals("hokori, dust drinker")
|
||||
|| cn.equals("iona, shield of emeria")
|
||||
|| cn.equals("jin-gitaxias, core augur")
|
||||
|| cn.equals("kaalia of the vast")
|
||||
|| cn.equals("karador, ghost chieftain")
|
||||
|| cn.equals("leovold, emissary of trest")
|
||||
|| cn.equals("linvala, keeper of silence")
|
||||
|| cn.equals("llawan, cephalid empress")
|
||||
|| cn.equals("maelstrom wanderer")
|
||||
|| cn.equals("malfegor")
|
||||
|| cn.equals("memnarch")
|
||||
|| cn.equals("meren of clan nel toth")
|
||||
|| cn.equals("michiko konda, truth seeker")
|
||||
|| cn.equals("mikaeus the unhallowed")
|
||||
|| cn.equals("narset, enlightened master")
|
||||
|| cn.equals("nath of the gilt-leaf")
|
||||
|| cn.equals("nekusar, the mindrazer")
|
||||
|| cn.equals("norin the wary")
|
||||
|| cn.equals("numot, the devastator")
|
||||
|| cn.equals("prossh, skyraider of kher")
|
||||
|| cn.equals("purphoros, god of the forge")
|
||||
|| cn.equals("sen triplets")
|
||||
|| cn.equals("sheoldred, whispering one")
|
||||
|| cn.equals("teferi, mage of zhalfir")
|
||||
|| cn.equals("urabrask the hidden")
|
||||
|| cn.equals("vorinclex, voice of hunger")
|
||||
|| cn.equals("zur the enchanter")) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 25);
|
||||
}
|
||||
|
||||
// Saltiest commanders
|
||||
if (cn.equals("atraxa, praetors' voice")
|
||||
|| cn.equals("avacyn, angel of hope")
|
||||
|| cn.equals("chulane, teller of tales")
|
||||
|| cn.equals("derevi, empyrial tactician")
|
||||
|| cn.equals("elesh norn, grand cenobite")
|
||||
|| cn.equals("emrakul, the promised end")
|
||||
|| cn.equals("gaddock teeg")
|
||||
|| cn.equals("glenn, the voice of calm")
|
||||
|| cn.equals("golos, tireless pilgrim")
|
||||
|| cn.equals("grand arbiter augustin iv")
|
||||
|| cn.equals("hokori, dust drinker")
|
||||
|| cn.equals("iona, shield of emeria")
|
||||
|| cn.equals("jin-gitaxias, core augur")
|
||||
|| cn.equals("kinnan, bonder prodigy")
|
||||
|| cn.equals("kozilek, butcher of truth")
|
||||
|| cn.equals("linvala, keeper of silence")
|
||||
|| cn.equals("narset, enlightened master")
|
||||
|| cn.equals("negan, the cold-blooded")
|
||||
|| cn.equals("oko, thief of crowns")
|
||||
|| cn.equals("oloro, ageless ascetic")
|
||||
|| cn.equals("rick, steadfast leader")
|
||||
|| cn.equals("sen triplets")
|
||||
|| cn.equals("skithiryx, the blight dragon")
|
||||
|| cn.equals("teferi, master of time")
|
||||
|| cn.equals("teferi, time raveler")
|
||||
|| cn.equals("thrasios, triton hero")
|
||||
|| cn.equals("ulamog, the ceaseless hunger")
|
||||
|| cn.equals("ulamog, the infinite gyre")
|
||||
|| cn.equals("urza, lord high artificer")
|
||||
|| cn.equals("vorinclex, voice of hunger")
|
||||
|| cn.equals("xanathar, guild kingpin")
|
||||
|| cn.equals("zur the enchanter")) {
|
||||
thisMaxPower = Math.max(thisMaxPower, 20);
|
||||
}
|
||||
edhPowerLevel += thisMaxPower;
|
||||
}
|
||||
|
||||
edhPowerLevel += numberInfinitePieces * 18;
|
||||
edhPowerLevel = Math.round(edhPowerLevel / 10);
|
||||
if (edhPowerLevel >= 100) {
|
||||
edhPowerLevel = 99;
|
||||
}
|
||||
if (color != null) {
|
||||
edhPowerLevel += (color.isWhite() ? 10000000 : 0);
|
||||
edhPowerLevel += (color.isBlue() ? 1000000 : 0);
|
||||
edhPowerLevel += (color.isBlack() ? 100000 : 0);
|
||||
edhPowerLevel += (color.isRed() ? 10000 : 0);
|
||||
edhPowerLevel += (color.isGreen() ? 1000 : 0);
|
||||
}
|
||||
return edhPowerLevel;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,17 @@
|
|||
package mage.deck;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.keyword.CompanionAbility;
|
||||
import mage.abilities.keyword.PartnerAbility;
|
||||
import mage.abilities.keyword.PartnerWithAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.ExpansionSet;
|
||||
import mage.cards.Sets;
|
||||
import mage.cards.decks.Constructed;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.cards.decks.DeckValidatorErrorType;
|
||||
import mage.constants.CardType;
|
||||
import mage.filter.FilterMana;
|
||||
import mage.util.ManaUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author spjspj
|
||||
*/
|
||||
public class FreeformCommander extends Constructed {
|
||||
|
||||
protected List<String> bannedCommander = new ArrayList<>();
|
||||
private static final Map<String, Integer> pdAllowed = new HashMap<>();
|
||||
public class FreeformCommander extends AbstractCommander {
|
||||
|
||||
public FreeformCommander() {
|
||||
super("Freeform Commander");
|
||||
|
@ -43,136 +32,16 @@ public class FreeformCommander extends Constructed {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int getDeckMinSize() {
|
||||
return 98;
|
||||
protected boolean checkBanned(Map<String, Integer> counts) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSideboardMinSize() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(Deck deck) {
|
||||
boolean valid = true;
|
||||
errorsList.clear();
|
||||
FilterMana colorIdentity = new FilterMana();
|
||||
Set<Card> commanders = new HashSet<>();
|
||||
Card companion = null;
|
||||
|
||||
if (deck.getSideboard().size() == 1) {
|
||||
commanders.add(deck.getSideboard().iterator().next());
|
||||
} else if (deck.getSideboard().size() == 2) {
|
||||
Iterator<Card> iter = deck.getSideboard().iterator();
|
||||
Card card1 = iter.next();
|
||||
Card card2 = iter.next();
|
||||
if (card1.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
|
||||
companion = card1;
|
||||
commanders.add(card2);
|
||||
} else if (card2.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
|
||||
companion = card2;
|
||||
commanders.add(card1);
|
||||
} else {
|
||||
commanders.add(card1);
|
||||
commanders.add(card2);
|
||||
}
|
||||
} else if (deck.getSideboard().size() == 3) {
|
||||
Iterator<Card> iter = deck.getSideboard().iterator();
|
||||
Card card1 = iter.next();
|
||||
Card card2 = iter.next();
|
||||
Card card3 = iter.next();
|
||||
if (card1.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
|
||||
companion = card1;
|
||||
commanders.add(card2);
|
||||
commanders.add(card3);
|
||||
} else if (card2.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
|
||||
companion = card2;
|
||||
commanders.add(card1);
|
||||
commanders.add(card3);
|
||||
} else if (card3.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
|
||||
companion = card3;
|
||||
commanders.add(card1);
|
||||
commanders.add(card2);
|
||||
} else {
|
||||
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion");
|
||||
valid = false;
|
||||
}
|
||||
} else {
|
||||
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (companion != null && deck.getCards().size() + deck.getSideboard().size() != 101) {
|
||||
addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 101 + " cards (companion doesn't count for deck size): has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards");
|
||||
valid = false;
|
||||
} else if (companion == null && deck.getCards().size() + deck.getSideboard().size() != 100) {
|
||||
addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 100 + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
Map<String, Integer> counts = new HashMap<>();
|
||||
countCards(counts, deck.getCards());
|
||||
countCards(counts, deck.getSideboard());
|
||||
valid = checkCounts(1, counts) && valid;
|
||||
|
||||
Set<String> commanderNames = new HashSet<>();
|
||||
for (Card commander : commanders) {
|
||||
commanderNames.add(commander.getName());
|
||||
}
|
||||
for (Card commander : 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);
|
||||
valid = false;
|
||||
}
|
||||
if (commanders.size() == 2) {
|
||||
if (!commander.getAbilities().contains(PartnerAbility.getInstance())) {
|
||||
boolean partnersWith = commander.getAbilities()
|
||||
.stream()
|
||||
.filter(PartnerWithAbility.class::isInstance)
|
||||
.map(PartnerWithAbility.class::cast)
|
||||
.map(PartnerWithAbility::getPartnerName)
|
||||
.anyMatch(commanderNames::contains);
|
||||
if (!partnersWith) {
|
||||
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander without Partner (" + commander.getName() + ')', true);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
ManaUtil.collectColorIdentity(colorIdentity, commander.getColorIdentity());
|
||||
}
|
||||
|
||||
// no needs in cards check on wrong commanders
|
||||
if (!valid) {
|
||||
protected boolean checkCommander(Card commander) {
|
||||
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;
|
||||
}
|
||||
|
||||
for (Card card : deck.getCards()) {
|
||||
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
|
||||
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
for (Card card : deck.getSideboard()) {
|
||||
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
|
||||
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
// Check for companion legality
|
||||
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())) {
|
||||
addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Commander Companion (deck invalid for companion)", true);
|
||||
valid = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +1,18 @@
|
|||
package mage.deck;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.CanBeYourCommanderAbility;
|
||||
import mage.abilities.keyword.CompanionAbility;
|
||||
import mage.abilities.keyword.PartnerAbility;
|
||||
import mage.abilities.keyword.PartnerWithAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.ExpansionSet;
|
||||
import mage.cards.Sets;
|
||||
import mage.cards.decks.Constructed;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.cards.decks.DeckValidatorErrorType;
|
||||
import mage.cards.decks.PennyDreadfulLegalityUtil;
|
||||
import mage.constants.CardType;
|
||||
import mage.filter.FilterMana;
|
||||
import mage.util.ManaUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author spjspj
|
||||
*/
|
||||
public class PennyDreadfulCommander extends Constructed {
|
||||
public class PennyDreadfulCommander extends AbstractCommander {
|
||||
|
||||
protected List<String> bannedCommander = new ArrayList<>();
|
||||
private static final Map<String, Integer> pdAllowed = new HashMap<>();
|
||||
|
||||
public PennyDreadfulCommander() {
|
||||
|
@ -36,168 +25,17 @@ public class PennyDreadfulCommander extends Constructed {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int getDeckMinSize() {
|
||||
return 98;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSideboardMinSize() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(Deck deck) {
|
||||
boolean valid = true;
|
||||
errorsList.clear();
|
||||
FilterMana colorIdentity = new FilterMana();
|
||||
Set<Card> commanders = new HashSet<>();
|
||||
Card companion = null;
|
||||
|
||||
if (deck.getSideboard().size() == 1) {
|
||||
commanders.add(deck.getSideboard().iterator().next());
|
||||
} else if (deck.getSideboard().size() == 2) {
|
||||
Iterator<Card> iter = deck.getSideboard().iterator();
|
||||
Card card1 = iter.next();
|
||||
Card card2 = iter.next();
|
||||
if (card1.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
|
||||
companion = card1;
|
||||
commanders.add(card2);
|
||||
} else if (card2.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
|
||||
companion = card2;
|
||||
commanders.add(card1);
|
||||
} else {
|
||||
commanders.add(card1);
|
||||
commanders.add(card2);
|
||||
}
|
||||
} else if (deck.getSideboard().size() == 3) {
|
||||
Iterator<Card> iter = deck.getSideboard().iterator();
|
||||
Card card1 = iter.next();
|
||||
Card card2 = iter.next();
|
||||
Card card3 = iter.next();
|
||||
if (card1.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
|
||||
companion = card1;
|
||||
commanders.add(card2);
|
||||
commanders.add(card3);
|
||||
} else if (card2.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
|
||||
companion = card2;
|
||||
commanders.add(card1);
|
||||
commanders.add(card3);
|
||||
} else if (card3.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
|
||||
companion = card3;
|
||||
commanders.add(card1);
|
||||
commanders.add(card2);
|
||||
} else {
|
||||
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion");
|
||||
valid = false;
|
||||
}
|
||||
} else {
|
||||
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (companion != null && deck.getCards().size() + deck.getSideboard().size() != 101) {
|
||||
addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 101 + " cards (companion doesn't count for deck size): has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards");
|
||||
valid = false;
|
||||
} else if (companion == null && deck.getCards().size() + deck.getSideboard().size() != 100) {
|
||||
addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 100 + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
Map<String, Integer> counts = new HashMap<>();
|
||||
countCards(counts, deck.getCards());
|
||||
countCards(counts, deck.getSideboard());
|
||||
valid = checkCounts(1, counts) && valid;
|
||||
|
||||
protected boolean checkBanned(Map<String, Integer> counts) {
|
||||
if (pdAllowed.isEmpty()) {
|
||||
pdAllowed.putAll(PennyDreadfulLegalityUtil.getLegalCardList());
|
||||
}
|
||||
|
||||
boolean valid = true;
|
||||
for (String wantedCard : counts.keySet()) {
|
||||
if (!(pdAllowed.containsKey(wantedCard))) {
|
||||
addError(DeckValidatorErrorType.BANNED, wantedCard, "Banned", true);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> commanderNames = new HashSet<>();
|
||||
for (Card commander : commanders) {
|
||||
commanderNames.add(commander.getName());
|
||||
}
|
||||
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())) {
|
||||
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander invalid (" + commander.getName() + ')', true);
|
||||
valid = false;
|
||||
}
|
||||
if (commanders.size() == 2) {
|
||||
if (!commander.getAbilities().contains(PartnerAbility.getInstance())) {
|
||||
boolean partnersWith = commander.getAbilities()
|
||||
.stream()
|
||||
.filter(PartnerWithAbility.class::isInstance)
|
||||
.map(PartnerWithAbility.class::cast)
|
||||
.map(PartnerWithAbility::getPartnerName)
|
||||
.anyMatch(commanderNames::contains);
|
||||
if (!partnersWith) {
|
||||
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander without Partner (" + commander.getName() + ')', true);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
ManaUtil.collectColorIdentity(colorIdentity, commander.getColorIdentity());
|
||||
}
|
||||
|
||||
// no needs in cards check on wrong commanders
|
||||
if (!valid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Card card : deck.getCards()) {
|
||||
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
|
||||
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
for (Card card : deck.getSideboard()) {
|
||||
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
|
||||
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
for (Card card : deck.getCards()) {
|
||||
if (!isSetAllowed(card.getExpansionSetCode())) {
|
||||
if (!legalSets(card)) {
|
||||
addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Card card : deck.getSideboard()) {
|
||||
if (!isSetAllowed(card.getExpansionSetCode())) {
|
||||
if (!legalSets(card)) {
|
||||
addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check for companion legality
|
||||
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())) {
|
||||
addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Commander Companion (deck invalid for companion)", true);
|
||||
valid = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
|
42
Mage.Sets/src/mage/cards/t/ThePrismaticPiper.java
Normal file
42
Mage.Sets/src/mage/cards/t/ThePrismaticPiper.java
Normal file
|
@ -0,0 +1,42 @@
|
|||
package mage.cards.t;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.CommanderChooseColorAbility;
|
||||
import mage.abilities.keyword.PartnerAbility;
|
||||
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 ThePrismaticPiper extends CardImpl {
|
||||
|
||||
public ThePrismaticPiper(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}");
|
||||
|
||||
this.addSuperType(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.SHAPESHIFTER);
|
||||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// If The Prismatic Piper is your commander, choose a color before the game begins. The Prismatic Piper is the chosen color.
|
||||
this.addAbility(new CommanderChooseColorAbility());
|
||||
|
||||
// Partner
|
||||
this.addAbility(PartnerAbility.getInstance());
|
||||
}
|
||||
|
||||
private ThePrismaticPiper(final ThePrismaticPiper card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThePrismaticPiper copy() {
|
||||
return new ThePrismaticPiper(this);
|
||||
}
|
||||
}
|
|
@ -657,6 +657,8 @@ public final class CommanderLegends extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Tevesh Szat, Doom of Fools", 512, Rarity.MYTHIC, mage.cards.t.TeveshSzatDoomOfFools.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Thalisse, Reverent Medium", 291, Rarity.UNCOMMON, mage.cards.t.ThalisseReverentMedium.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Thalisse, Reverent Medium", 611, Rarity.UNCOMMON, mage.cards.t.ThalisseReverentMedium.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("The Prismatic Piper", 1, Rarity.COMMON, mage.cards.t.ThePrismaticPiper.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("The Prismatic Piper", 546, Rarity.COMMON, mage.cards.t.ThePrismaticPiper.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Thirst for Knowledge", 103, Rarity.UNCOMMON, mage.cards.t.ThirstForKnowledge.class));
|
||||
cards.add(new SetCardInfo("Thorn of the Black Rose", 154, Rarity.COMMON, mage.cards.t.ThornOfTheBlackRose.class));
|
||||
cards.add(new SetCardInfo("Thornwood Falls", 498, Rarity.COMMON, mage.cards.t.ThornwoodFalls.class));
|
||||
|
|
3
Mage.Tests/piperDecks/ThePrismaticPiper1.dck
Normal file
3
Mage.Tests/piperDecks/ThePrismaticPiper1.dck
Normal file
|
@ -0,0 +1,3 @@
|
|||
NAME:The Prismatic Piper Test
|
||||
99 [CMR:506] Island
|
||||
SB: 1 [CMR:1] The Prismatic Piper
|
5
Mage.Tests/piperDecks/ThePrismaticPiper2.dck
Normal file
5
Mage.Tests/piperDecks/ThePrismaticPiper2.dck
Normal file
|
@ -0,0 +1,5 @@
|
|||
NAME:The Prismatic Piper Test
|
||||
98 [CMR:506] Island
|
||||
1 [CMR:508] Mountain
|
||||
SB: 1 [CMR:1] The Prismatic Piper
|
||||
SB: 1 [CMR:71] Ghost of Ramirez DePietro
|
5
Mage.Tests/piperDecks/ThePrismaticPiper3.dck
Normal file
5
Mage.Tests/piperDecks/ThePrismaticPiper3.dck
Normal file
|
@ -0,0 +1,5 @@
|
|||
NAME:The Prismatic Piper Test
|
||||
98 [CMR:506] Island
|
||||
1 [CMR:508] Mountain
|
||||
SB: 1 [CMR:1] The Prismatic Piper
|
||||
SB: 1 [C16:34] Kraum, Ludevic's Opus
|
4
Mage.Tests/piperDecks/ThePrismaticPiper4.dck
Normal file
4
Mage.Tests/piperDecks/ThePrismaticPiper4.dck
Normal file
|
@ -0,0 +1,4 @@
|
|||
NAME:The Prismatic Piper Test
|
||||
98 [CMR:508] Mountain
|
||||
1 [CMR:506] Island
|
||||
SB: 1 [CMR:1] The Prismatic Piper
|
6
Mage.Tests/piperDecks/ThePrismaticPiper5.dck
Normal file
6
Mage.Tests/piperDecks/ThePrismaticPiper5.dck
Normal file
|
@ -0,0 +1,6 @@
|
|||
NAME:The Prismatic Piper Test
|
||||
97 [CMR:508] Mountain
|
||||
1 [CMR:506] Island
|
||||
1 [CMR:504] Plains
|
||||
SB: 1 [CMR:1] The Prismatic Piper
|
||||
SB: 1 [C16:34] Kraum, Ludevic's Opus
|
7
Mage.Tests/piperDecks/ThePrismaticPiper6.dck
Normal file
7
Mage.Tests/piperDecks/ThePrismaticPiper6.dck
Normal file
|
@ -0,0 +1,7 @@
|
|||
NAME:The Prismatic Piper Test
|
||||
96 [CMR:508] Mountain
|
||||
1 [CMR:506] Island
|
||||
1 [CMR:504] Plains
|
||||
1 [CMR:510] Forest
|
||||
SB: 1 [CMR:1] The Prismatic Piper
|
||||
SB: 1 [C16:34] Kraum, Ludevic's Opus
|
4
Mage.Tests/piperDecks/ThePrismaticPiper7.dck
Normal file
4
Mage.Tests/piperDecks/ThePrismaticPiper7.dck
Normal file
|
@ -0,0 +1,4 @@
|
|||
NAME:The Prismatic Piper Test
|
||||
97 [CMR:508] Mountain
|
||||
1 [CMR:510] Forest
|
||||
SB: 2 [CMR:1] The Prismatic Piper
|
7
Mage.Tests/piperDecks/ThePrismaticPiper8.dck
Normal file
7
Mage.Tests/piperDecks/ThePrismaticPiper8.dck
Normal file
|
@ -0,0 +1,7 @@
|
|||
NAME:The Prismatic Piper Test
|
||||
97 [CMR:508] Mountain
|
||||
1 [CMR:506] Island
|
||||
1 [CMR:510] Forest
|
||||
SB: 1 [CMR:1] The Prismatic Piper
|
||||
SB: 1 [C16:34] Kraum, Ludevic's Opus
|
||||
SB: 1 [IKO:225] Keruga, the Macrosage
|
|
@ -0,0 +1,16 @@
|
|||
package org.mage.test.commander.piper;
|
||||
|
||||
import org.mage.test.serverside.base.CardTestCommanderDuelBase;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public abstract class ThePrismaticPiperBaseTest extends CardTestCommanderDuelBase {
|
||||
|
||||
protected static final String piper = "The Prismatic Piper";
|
||||
|
||||
protected ThePrismaticPiperBaseTest(int number) {
|
||||
super();
|
||||
this.deckNameA = "piperDecks/ThePrismaticPiper" + number + ".dck";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package org.mage.test.commander.piper;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class ThePrismaticPiperTest1 extends ThePrismaticPiperBaseTest {
|
||||
|
||||
// Decklist:
|
||||
// 99 Island
|
||||
// SB: 1 The Prismatic Piper
|
||||
|
||||
public ThePrismaticPiperTest1() {
|
||||
super(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColor() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piper);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertColor(playerA, piper, "U", true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package org.mage.test.commander.piper;
|
||||
|
||||
import mage.abilities.mana.ManaOptions;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.utils.ManaOptionsTestUtils;
|
||||
|
||||
import static org.mage.test.utils.ManaOptionsTestUtils.assertDuplicatedManaOptions;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class ThePrismaticPiperTest2 extends ThePrismaticPiperBaseTest {
|
||||
|
||||
// Decklist:
|
||||
// 98 Island
|
||||
// 1 Mountain
|
||||
// SB: 1 The Prismatic Piper
|
||||
// SB: 1 Ghost of Ramirez DePietro
|
||||
|
||||
public ThePrismaticPiperTest2() {
|
||||
super(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColor() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piper);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertColor(playerA, piper, "R", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManaOptions() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Command Tower");
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
|
||||
assertDuplicatedManaOptions(manaOptions);
|
||||
Assert.assertEquals("mana variations don't fit", 2, manaOptions.size());
|
||||
ManaOptionsTestUtils.assertManaOptions("{U}", manaOptions);
|
||||
ManaOptionsTestUtils.assertManaOptions("{R}", manaOptions);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package org.mage.test.commander.piper;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class ThePrismaticPiperTest3 extends ThePrismaticPiperBaseTest {
|
||||
|
||||
// Decklist:
|
||||
// 98 Island
|
||||
// 1 Mountain
|
||||
// SB: 1 The Prismatic Piper
|
||||
// SB: 1 Kraum, Ludevic's Opus
|
||||
|
||||
public ThePrismaticPiperTest3() {
|
||||
super(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColor() {
|
||||
setChoice(playerA, "White");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piper);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertColor(playerA, piper, "W", true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package org.mage.test.commander.piper;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class ThePrismaticPiperTest4 extends ThePrismaticPiperBaseTest {
|
||||
|
||||
// Decklist:
|
||||
// 98 Mountain
|
||||
// 1 Island
|
||||
// SB: 1 The Prismatic Piper
|
||||
|
||||
public ThePrismaticPiperTest4() {
|
||||
super(4);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testColor() {
|
||||
execute();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package org.mage.test.commander.piper;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class ThePrismaticPiperTest5 extends ThePrismaticPiperBaseTest {
|
||||
|
||||
// Decklist:
|
||||
// 97 Mountain
|
||||
// 1 Island
|
||||
// 1 Plains
|
||||
// SB: 1 The Prismatic Piper
|
||||
// SB: 1 Kraum, Ludevic's Opus
|
||||
|
||||
public ThePrismaticPiperTest5() {
|
||||
super(5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColor() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piper);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertColor(playerA, piper, "W", true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package org.mage.test.commander.piper;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class ThePrismaticPiperTest6 extends ThePrismaticPiperBaseTest {
|
||||
|
||||
// Decklist:
|
||||
// 96 Mountain
|
||||
// 1 Island
|
||||
// 1 Plains
|
||||
// 1 Forest
|
||||
// SB: 1 The Prismatic Piper
|
||||
// SB: 1 Kraum, Ludevic's Opus
|
||||
|
||||
public ThePrismaticPiperTest6() {
|
||||
super(6);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testColor() {
|
||||
execute();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package org.mage.test.commander.piper;
|
||||
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.mana.ManaOptions;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.CommanderCardType;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.utils.ManaOptionsTestUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.mage.test.utils.ManaOptionsTestUtils.assertDuplicatedManaOptions;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class ThePrismaticPiperTest7 extends ThePrismaticPiperBaseTest {
|
||||
|
||||
// Decklist:
|
||||
// 97 Mountain
|
||||
// 1 Forest
|
||||
// SB: 2 The Prismatic Piper
|
||||
|
||||
public ThePrismaticPiperTest7() {
|
||||
super(7);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColor() {
|
||||
execute();
|
||||
|
||||
List<Card> commanders = new ArrayList<>(currentGame.getCommanderCardsFromCommandZone(playerA, CommanderCardType.ANY));
|
||||
Card piper1;
|
||||
Card piper2;
|
||||
if (commanders.get(0).getColor(currentGame).isRed()) {
|
||||
piper1 = commanders.get(0);
|
||||
piper2 = commanders.get(1);
|
||||
} else {
|
||||
piper1 = commanders.get(1);
|
||||
piper2 = commanders.get(0);
|
||||
}
|
||||
Assert.assertEquals("One Piper must be red", piper1.getColor(currentGame), ObjectColor.RED);
|
||||
Assert.assertEquals("One Piper must be green", piper2.getColor(currentGame), ObjectColor.GREEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManaOptions() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Command Tower");
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
|
||||
assertDuplicatedManaOptions(manaOptions);
|
||||
Assert.assertEquals("mana variations don't fit", 2, manaOptions.size());
|
||||
ManaOptionsTestUtils.assertManaOptions("{R}", manaOptions);
|
||||
ManaOptionsTestUtils.assertManaOptions("{G}", manaOptions);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package org.mage.test.commander.piper;
|
||||
|
||||
import mage.abilities.mana.ManaOptions;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.utils.ManaOptionsTestUtils;
|
||||
|
||||
import static org.mage.test.utils.ManaOptionsTestUtils.assertDuplicatedManaOptions;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class ThePrismaticPiperTest8 extends ThePrismaticPiperBaseTest {
|
||||
|
||||
// Decklist:
|
||||
// 97 Mountain
|
||||
// 1 Island
|
||||
// 1 Forest
|
||||
// SB: 1 The Prismatic Piper
|
||||
// SB: 1 Kraum, Ludevic's Opus
|
||||
// SB: 1 Keruga, the Macrosage
|
||||
|
||||
public ThePrismaticPiperTest8() {
|
||||
super(8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColor() {
|
||||
setChoice(playerA, true); // Companion
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 8);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piper);
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Companion");
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertColor(playerA, piper, "G", true);
|
||||
assertHandCount(playerA, "Keruga, the Macrosage", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManaOptions() {
|
||||
setChoice(playerA, true); // Companion
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Command Tower");
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame);
|
||||
assertDuplicatedManaOptions(manaOptions);
|
||||
Assert.assertEquals("mana variations don't fit", 3, manaOptions.size());
|
||||
ManaOptionsTestUtils.assertManaOptions("{U}", manaOptions);
|
||||
ManaOptionsTestUtils.assertManaOptions("{R}", manaOptions);
|
||||
ManaOptionsTestUtils.assertManaOptions("{G}", manaOptions);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package org.mage.test.serverside.deck;
|
||||
|
||||
import mage.deck.Commander;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.MageTestBase;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class CommanderDeckValidationTest extends MageTestBase {
|
||||
|
||||
private static final String piper = "The Prismatic Piper";
|
||||
|
||||
@Test
|
||||
public void testGristCommander() {
|
||||
// Grist, the Hunger Tide can be your commander as its first ability applies during deck construction.
|
||||
DeckTester deckTester = new DeckTester(new Commander());
|
||||
deckTester.addMaindeck("Forest", 49);
|
||||
deckTester.addMaindeck("Swamp", 50);
|
||||
|
||||
deckTester.addSideboard("Grist, the Hunger Tide", 1);
|
||||
|
||||
deckTester.validate("Grist should be legal as a commander");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrismaticPiperOneCopy() {
|
||||
DeckTester deckTester = new DeckTester(new Commander());
|
||||
deckTester.addMaindeck("Forest", 99);
|
||||
|
||||
deckTester.addSideboard(piper, 1);
|
||||
|
||||
deckTester.validate();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrismaticPiper2() {
|
||||
DeckTester deckTester = new DeckTester(new Commander());
|
||||
deckTester.addMaindeck("Forest", 49);
|
||||
deckTester.addMaindeck("Island", 49);
|
||||
|
||||
deckTester.addSideboard(piper, 1);
|
||||
deckTester.addSideboard("Anara, Wolvid Familiar", 1);
|
||||
|
||||
deckTester.validate();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrismaticPiper3() {
|
||||
DeckTester deckTester = new DeckTester(new Commander());
|
||||
deckTester.addMaindeck("Forest", 48);
|
||||
deckTester.addMaindeck("Island", 48);
|
||||
deckTester.addMaindeck("Mountain", 2);
|
||||
|
||||
deckTester.addSideboard(piper, 1);
|
||||
deckTester.addSideboard("Thrasios, Triton Hero", 1);
|
||||
|
||||
deckTester.validate();
|
||||
}
|
||||
|
||||
@Test(expected = AssertionError.class)
|
||||
public void testPrismaticPiper4() {
|
||||
DeckTester deckTester = new DeckTester(new Commander());
|
||||
deckTester.addMaindeck("Forest", 48);
|
||||
deckTester.addMaindeck("Island", 48);
|
||||
deckTester.addMaindeck("Mountain", 1);
|
||||
deckTester.addMaindeck("Plains", 1);
|
||||
|
||||
deckTester.addSideboard(piper, 1);
|
||||
deckTester.addSideboard("Thrasios, Triton Hero", 1);
|
||||
|
||||
deckTester.validate();
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ import org.mage.test.serverside.base.MageTestBase;
|
|||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class CompanionTest extends MageTestBase {
|
||||
public class CompanionDeckValidationTest extends MageTestBase {
|
||||
|
||||
@Test
|
||||
public void testGyrudaTrue() {
|
|
@ -68,18 +68,6 @@ public class DeckValidatorTest extends MageTestBase {
|
|||
deckTester.validate("only 4 of a card are allowed", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGristCommander() {
|
||||
// Grist, the Hunger Tide can be your commander as its first ability applies during deck construction.
|
||||
DeckTester deckTester = new DeckTester(new Commander());
|
||||
deckTester.addMaindeck("Forest", 49);
|
||||
deckTester.addMaindeck("Swamp", 50);
|
||||
|
||||
deckTester.addSideboard("Grist, the Hunger Tide", 1);
|
||||
|
||||
deckTester.validate("Grist should be legal as a commander");
|
||||
}
|
||||
|
||||
private void assertCounterspellValid(ArrayList<DeckValidationUtil.CardNameAmount> deckList) {
|
||||
final boolean needValid = true; // card valid after Modern Horizons 2
|
||||
boolean valid = testDeckValid(new Modern(), deckList);
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Zone;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class CommanderChooseColorAbility extends StaticAbility {
|
||||
|
||||
public CommanderChooseColorAbility() {
|
||||
super(Zone.ALL, null);
|
||||
}
|
||||
|
||||
private CommanderChooseColorAbility(final CommanderChooseColorAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommanderChooseColorAbility copy() {
|
||||
return new CommanderChooseColorAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "If {this} is your commander, choose a color before the game begins. {this} is the chosen color.";
|
||||
}
|
||||
|
||||
public static boolean checkCard(Card card) {
|
||||
return card.getAbilities().stream().anyMatch(CommanderChooseColorAbility.class::isInstance);
|
||||
}
|
||||
}
|
|
@ -41,8 +41,12 @@ public class CompanionAbility extends SpecialAction {
|
|||
return "Companion — " + companionCondition.getRule();
|
||||
}
|
||||
|
||||
public boolean isLegal(Set<Card> cards, int startingHandSize) {
|
||||
final public boolean isLegal(Set<Card> cards, int startingHandSize) {
|
||||
return companionCondition.isLegal(cards, startingHandSize);
|
||||
}
|
||||
|
||||
final public String getLegalRule() {
|
||||
return companionCondition.getRule();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import java.util.Map.Entry;
|
|||
*/
|
||||
public class Constructed extends DeckValidator {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DeckValidator.class);
|
||||
private static final Logger logger = Logger.getLogger(Constructed.class);
|
||||
|
||||
private static final List<String> anyNumberCardsAllowed = new ArrayList<>(Arrays.asList(
|
||||
"Relentless Rats", "Shadowborn Apostle", "Rat Colony",
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package mage.filter;
|
||||
|
||||
import mage.ObjectColor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author nantuko
|
||||
|
@ -108,6 +112,62 @@ public class FilterMana implements Serializable {
|
|||
return colorCount;
|
||||
}
|
||||
|
||||
public void addAll(FilterMana filterMana) {
|
||||
if (filterMana.white) {
|
||||
this.white = true;
|
||||
}
|
||||
if (filterMana.blue) {
|
||||
this.blue = true;
|
||||
}
|
||||
if (filterMana.black) {
|
||||
this.black = true;
|
||||
}
|
||||
if (filterMana.red) {
|
||||
this.red = true;
|
||||
}
|
||||
if (filterMana.green) {
|
||||
this.green = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAll(FilterMana filterMana) {
|
||||
if (filterMana.white) {
|
||||
this.white = false;
|
||||
}
|
||||
if (filterMana.blue) {
|
||||
this.blue = false;
|
||||
}
|
||||
if (filterMana.black) {
|
||||
this.black = false;
|
||||
}
|
||||
if (filterMana.red) {
|
||||
this.red = false;
|
||||
}
|
||||
if (filterMana.green) {
|
||||
this.green = false;
|
||||
}
|
||||
}
|
||||
|
||||
public List<ObjectColor> getColors() {
|
||||
List<ObjectColor> colors = new ArrayList<>();
|
||||
if (this.white) {
|
||||
colors.add(ObjectColor.WHITE);
|
||||
}
|
||||
if (this.blue) {
|
||||
colors.add(ObjectColor.BLUE);
|
||||
}
|
||||
if (this.black) {
|
||||
colors.add(ObjectColor.BLACK);
|
||||
}
|
||||
if (this.red) {
|
||||
colors.add(ObjectColor.RED);
|
||||
}
|
||||
if (this.green) {
|
||||
colors.add(ObjectColor.GREEN);
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
public FilterMana copy() {
|
||||
return new FilterMana(this);
|
||||
}
|
||||
|
|
|
@ -1,21 +1,25 @@
|
|||
package mage.game;
|
||||
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.CommanderChooseColorAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.common.InfoEffect;
|
||||
import mage.abilities.effects.common.continuous.CommanderReplacementEffect;
|
||||
import mage.abilities.effects.common.cost.CommanderCostModification;
|
||||
import mage.abilities.keyword.CompanionAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.choices.ChoiceColor;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterMana;
|
||||
import mage.game.mulligan.Mulligan;
|
||||
import mage.game.turn.TurnMod;
|
||||
import mage.players.Player;
|
||||
import mage.watchers.common.CommanderInfoWatcher;
|
||||
import mage.watchers.common.CommanderPlaysCountWatcher;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public abstract class GameCommanderImpl extends GameImpl {
|
||||
|
||||
|
@ -40,6 +44,49 @@ public abstract class GameCommanderImpl extends GameImpl {
|
|||
this.checkCommanderDamage = game.checkCommanderDamage;
|
||||
}
|
||||
|
||||
private void handlePipers(Player player, Set<Card> commanders) {
|
||||
int piperCount = commanders
|
||||
.stream()
|
||||
.filter(CommanderChooseColorAbility::checkCard)
|
||||
.mapToInt(x -> 1)
|
||||
.sum();
|
||||
if (piperCount < 1) {
|
||||
return;
|
||||
}
|
||||
FilterMana leftoverColors = new FilterMana();
|
||||
Stream.concat(
|
||||
player.getLibrary().getCards(this).stream(),
|
||||
player.getSideboard().getCards(this).stream()
|
||||
).map(Card::getColorIdentity).forEach(leftoverColors::addAll);
|
||||
FilterMana nonPiperIdentity = new FilterMana();
|
||||
commanders
|
||||
.stream()
|
||||
.filter(card -> !CommanderChooseColorAbility.checkCard(card))
|
||||
.map(Card::getColorIdentity)
|
||||
.forEach(nonPiperIdentity::addAll);
|
||||
leftoverColors.removeAll(nonPiperIdentity);
|
||||
if (piperCount < leftoverColors.getColorCount()) {
|
||||
throw new UnsupportedOperationException("This deck should not be legal, something went wrong");
|
||||
}
|
||||
Iterator<ObjectColor> iterator = leftoverColors.getColors().listIterator();
|
||||
for (Card commander : commanders) {
|
||||
if (!CommanderChooseColorAbility.checkCard(commander)) {
|
||||
continue;
|
||||
}
|
||||
ObjectColor color;
|
||||
if (!iterator.hasNext()) {
|
||||
ChoiceColor choiceColor = new ChoiceColor(
|
||||
true, "Choose a color for " + commander.getName()
|
||||
);
|
||||
player.choose(Outcome.Neutral, choiceColor, this);
|
||||
color = choiceColor.getColor();
|
||||
} else {
|
||||
color = iterator.next();
|
||||
}
|
||||
commander.getColor().addColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(UUID choosingPlayerId) {
|
||||
// Karn Liberated calls it to restart game, all data and commanders must be re-initialized
|
||||
|
@ -50,25 +97,31 @@ public abstract class GameCommanderImpl extends GameImpl {
|
|||
// move commanders to command zone
|
||||
for (UUID playerId : state.getPlayerList(startingPlayerId)) {
|
||||
Player player = getPlayer(playerId);
|
||||
if (player != null) {
|
||||
// add new commanders
|
||||
for (UUID cardId : player.getSideboard()) {
|
||||
Card card = this.getCard(cardId);
|
||||
if (card != null) {
|
||||
// Check for companions. If it is the only card in the sideboard, it is the commander, not a companion.
|
||||
if (player.getSideboard().size() > 1 && card.getAbilities(this).stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
|
||||
continue;
|
||||
}
|
||||
addCommander(card, player);
|
||||
}
|
||||
if (player == null) {
|
||||
continue;
|
||||
}
|
||||
// add new commanders
|
||||
Set<Card> commanders = new HashSet<>();
|
||||
for (UUID cardId : player.getSideboard()) {
|
||||
Card card = this.getCard(cardId);
|
||||
if (card == null) {
|
||||
continue;
|
||||
}
|
||||
// Check for companions. If it is the only card in the sideboard, it is the commander, not a companion.
|
||||
if (player.getSideboard().size() > 1 && card.getAbilities(this).stream().anyMatch(CompanionAbility.class::isInstance)) {
|
||||
continue;
|
||||
}
|
||||
commanders.add(card);
|
||||
addCommander(card, player);
|
||||
}
|
||||
|
||||
// init commanders
|
||||
for (UUID commanderId : this.getCommandersIds(player, CommanderCardType.ANY, false)) {
|
||||
Card commander = this.getCard(commanderId);
|
||||
if (commander != null) {
|
||||
initCommander(commander, player);
|
||||
}
|
||||
handlePipers(player, commanders);
|
||||
|
||||
// init commanders
|
||||
for (UUID commanderId : this.getCommandersIds(player, CommanderCardType.ANY, false)) {
|
||||
Card commander = this.getCard(commanderId);
|
||||
if (commander != null) {
|
||||
initCommander(commander, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1129,12 +1129,13 @@ public abstract class GameImpl implements Game {
|
|||
Map<Player, Card> playerCompanionMap = new HashMap<>();
|
||||
for (Player player : state.getPlayers().values()) {
|
||||
// Make a list of legal companions present in the sideboard
|
||||
Set<Card> cards = new HashSet<>(player.getLibrary().getCards(this));
|
||||
Set<Card> potentialCompanions = new HashSet<>();
|
||||
for (Card card : player.getSideboard().getUniqueCards(this)) {
|
||||
for (Ability ability : card.getAbilities(this)) {
|
||||
if (ability instanceof CompanionAbility) {
|
||||
CompanionAbility companionAbility = (CompanionAbility) ability;
|
||||
if (companionAbility.isLegal(new HashSet<>(player.getLibrary().getCards(this)), startingHandSize)) {
|
||||
if (companionAbility.isLegal(cards, startingHandSize)) {
|
||||
potentialCompanions.add(card);
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue