mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 20:28:00 +00:00
Add menu item for setting Oathbreaker
Allow double-tapping to set Commander or Oathbreaker if one hasn't yet been set
This commit is contained in:
committed by
Michael Kamensky
parent
ce96e64edb
commit
f1e0158102
@@ -36,6 +36,8 @@ public class StaticData {
|
||||
private Predicate<PaperCard> standardPredicate;
|
||||
private Predicate<PaperCard> brawlPredicate;
|
||||
private Predicate<PaperCard> modernPredicate;
|
||||
private Predicate<PaperCard> commanderPredicate;
|
||||
private Predicate<PaperCard> oathbreakerPredicate;
|
||||
|
||||
private boolean filteredHandsEnabled = false;
|
||||
|
||||
@@ -201,17 +203,23 @@ public class StaticData {
|
||||
|
||||
public void setStandardPredicate(Predicate<PaperCard> standardPredicate) { this.standardPredicate = standardPredicate; }
|
||||
|
||||
public void setBrawlPredicate(Predicate<PaperCard> brawlPredicate) { this.brawlPredicate = brawlPredicate; }
|
||||
|
||||
public void setModernPredicate(Predicate<PaperCard> modernPredicate) { this.modernPredicate = standardPredicate; }
|
||||
|
||||
public void setCommanderPredicate(Predicate<PaperCard> commanderPredicate) { this.commanderPredicate = commanderPredicate; }
|
||||
|
||||
public void setOathbreakerPredicate(Predicate<PaperCard> oathbreakerPredicate) { this.oathbreakerPredicate = oathbreakerPredicate; }
|
||||
|
||||
public void setBrawlPredicate(Predicate<PaperCard> brawlPredicate) { this.brawlPredicate = brawlPredicate; }
|
||||
|
||||
public Predicate<PaperCard> getModernPredicate() {
|
||||
return modernPredicate;
|
||||
}
|
||||
|
||||
public Predicate<PaperCard> getBrawlPredicate() {
|
||||
return brawlPredicate;
|
||||
}
|
||||
public Predicate<PaperCard> getCommanderPredicate() { return commanderPredicate; }
|
||||
|
||||
public Predicate<PaperCard> getOathbreakerPredicate() { return oathbreakerPredicate; }
|
||||
|
||||
public Predicate<PaperCard> getBrawlPredicate() { return brawlPredicate; }
|
||||
|
||||
public void setFilteredHandsEnabled(boolean filteredHandsEnabled){
|
||||
this.filteredHandsEnabled = filteredHandsEnabled;
|
||||
|
||||
@@ -219,7 +219,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
if (upcomingSet != null) {
|
||||
addCard(new PaperCard(cr, upcomingSet.getCode(), CardRarity.Unknown, 1));
|
||||
} else {
|
||||
System.err.println("The card " + cr.getName() + " was not assigned to any set. Adding it to UNKNOWN set... to fix see res/cardeditions/ folder. ");
|
||||
System.err.println("The card " + cr.getName() + " was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. ");
|
||||
addCard(new PaperCard(cr, CardEdition.UNKNOWN.getCode(), CardRarity.Special, 1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,6 +210,16 @@ public final class CardRules implements ICardCharacteristics {
|
||||
return canBeCommander() && (hasKeyword("Partner") || !this.partnerWith.isEmpty());
|
||||
}
|
||||
|
||||
public boolean canBeOathbreaker() {
|
||||
CardType type = mainPart.getType();
|
||||
return type.isPlaneswalker();
|
||||
}
|
||||
|
||||
public boolean canBeSignatureSpell() {
|
||||
CardType type = mainPart.getType();
|
||||
return type.isInstant() || type.isSorcery();
|
||||
}
|
||||
|
||||
public boolean canBeBrawlCommander() {
|
||||
CardType type = mainPart.getType();
|
||||
return (type.isLegendary() && type.isCreature()) || type.isPlaneswalker();
|
||||
@@ -219,7 +229,7 @@ public final class CardRules implements ICardCharacteristics {
|
||||
return meldWith;
|
||||
}
|
||||
|
||||
public String getParterWith() {
|
||||
public String getPartnerWith() {
|
||||
return partnerWith;
|
||||
}
|
||||
|
||||
|
||||
@@ -570,6 +570,19 @@ public final class CardRulesPredicates {
|
||||
}
|
||||
};
|
||||
|
||||
public static final Predicate<CardRules> CAN_BE_OATHBREAKER = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules subject) {
|
||||
return subject.canBeOathbreaker();
|
||||
}
|
||||
};
|
||||
public static final Predicate<CardRules> CAN_BE_SIGNATURE_SPELL = new Predicate<CardRules>() {
|
||||
@Override
|
||||
public boolean apply(final CardRules subject) {
|
||||
return subject.canBeSignatureSpell();
|
||||
}
|
||||
};
|
||||
|
||||
public static final Predicate<CardRules> IS_PLANESWALKER = CardRulesPredicates.coreType(true, CardType.CoreType.Planeswalker);
|
||||
public static final Predicate<CardRules> IS_INSTANT = CardRulesPredicates.coreType(true, CardType.CoreType.Instant);
|
||||
public static final Predicate<CardRules> IS_SORCERY = CardRulesPredicates.coreType(true, CardType.CoreType.Sorcery);
|
||||
|
||||
@@ -122,9 +122,45 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
|
||||
for (final Entry<PaperCard, Integer> c : cp) {
|
||||
result.add(c.getKey());
|
||||
}
|
||||
if (result.size() > 1) { //sort by type so signature spell comes after oathbreaker
|
||||
Collections.sort(result, new Comparator<PaperCard>() {
|
||||
@Override
|
||||
public int compare(final PaperCard c1, final PaperCard c2) {
|
||||
return Boolean.compare(c1.getRules().canBeSignatureSpell(), c2.getRules().canBeSignatureSpell());
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//at least for now, Oathbreaker will only support one oathbreaker and one signature spell
|
||||
public PaperCard getOathbreaker() {
|
||||
final CardPool cp = get(DeckSection.Commander);
|
||||
if (cp == null) {
|
||||
return null;
|
||||
}
|
||||
for (final Entry<PaperCard, Integer> c : cp) {
|
||||
PaperCard card = c.getKey();
|
||||
if (card.getRules().canBeOathbreaker()) {
|
||||
return card;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public PaperCard getSignatureSpell() {
|
||||
final CardPool cp = get(DeckSection.Commander);
|
||||
if (cp == null) {
|
||||
return null;
|
||||
}
|
||||
for (final Entry<PaperCard, Integer> c : cp) {
|
||||
PaperCard card = c.getKey();
|
||||
if (card.getRules().canBeSignatureSpell()) {
|
||||
return card;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// may return nulls
|
||||
public CardPool get(DeckSection deckSection) {
|
||||
loadDeferredSections();
|
||||
|
||||
@@ -48,48 +48,25 @@ public enum DeckFormat {
|
||||
Constructed ( Range.between(60, Integer.MAX_VALUE), Range.between(0, 15), 4),
|
||||
QuestDeck ( Range.between(40, Integer.MAX_VALUE), Range.between(0, 15), 4),
|
||||
Limited ( Range.between(40, Integer.MAX_VALUE), null, Integer.MAX_VALUE),
|
||||
Commander ( Range.is(99), Range.between(0, 10), 1, new Predicate<CardRules>() {
|
||||
private final Set<String> bannedCards = ImmutableSet.of(
|
||||
"Adriana's Valor", "Advantageous Proclamation", "Amulet of Quoz", "Ancestral Recall", "Assemble the Rank and Vile",
|
||||
"Backup Plan", "Balance", "Biorhythm", "Black Lotus", "Brago's Favor", "Braids, Cabal Minion", "Bronze Tablet",
|
||||
"Channel", "Chaos Orb", "Coalition Victory", "Contract from Below", "Darkpact", "Demonic Attorney", "Double Stroke",
|
||||
"Echoing Boon", "Emissary's Ploy", "Emrakul, the Aeons Torn", "Erayo, Soratami Ascendant", "Falling Star",
|
||||
"Fastbond", "Gifts Ungiven", "Griselbrand", "Hired Heist", "Hold the Perimeter", "Hymn of the Wilds", "Immediate Action",
|
||||
"Incendiary Dissent", "Iterative Analysis", "Jeweled Bird", "Karakas", "Leovold, Emissary of Trest", "Library of Alexandria",
|
||||
"Limited Resources", "Mox Emerald", "Mox Jet", "Mox Pearl", "Mox Ruby", "Mox Sapphire", "Muzzio's Preparations",
|
||||
"Natural Unity", "Painter's Servant", "Panoptic Mirror", "Power Play", "Primeval Titan", "Prophet of Kruphix",
|
||||
"Rebirth", "Recurring Nightmare", "Rofellos, Llanowar Emissary", "Secret Summoning", "Secrets of Paradise",
|
||||
"Sentinel Dispatch", "Shahrazad", "Sovereign's Realm", "Summoner's Bond", "Sundering Titan", "Sway of the Stars",
|
||||
"Sylvan Primordial", "Tempest Efreet", "Time Vault", "Time Walk", "Timmerian Fiends", "Tinker", "Tolarian Academy",
|
||||
"Trade Secrets", "Unexpected Potential", "Upheaval", "Weight Advantage", "Worldfire", "Worldknit", "Yawgmoth's Bargain");
|
||||
Commander ( Range.is(99), Range.between(0, 10), 1, null, new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(CardRules rules) {
|
||||
if (bannedCards.contains(rules.getName())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
public boolean apply(PaperCard card) {
|
||||
return StaticData.instance().getCommanderPredicate().apply(card);
|
||||
}
|
||||
}),
|
||||
Oathbreaker ( Range.is(58), Range.between(0, 10), 1, null, new Predicate<PaperCard>() {
|
||||
@Override
|
||||
public boolean apply(PaperCard card) {
|
||||
return StaticData.instance().getOathbreakerPredicate().apply(card);
|
||||
}
|
||||
}),
|
||||
Pauper ( Range.is(60), Range.between(0, 10), 1),
|
||||
Brawl ( Range.is(59), Range.between(0, 15), 1, null, new Predicate<PaperCard>() {
|
||||
private final Set<String> bannedCards = ImmutableSet.of(
|
||||
"Baral, Chief of Compliance","Smuggler's Copter","Sorcerous Spyglass");
|
||||
@Override
|
||||
public boolean apply(PaperCard card) {
|
||||
//why do we need to hard code the bannings here - they are defined in the GameFormat predicate used below
|
||||
if (bannedCards.contains(card.getName())) {
|
||||
return false;
|
||||
}
|
||||
return StaticData.instance() == null ? false : StaticData.instance().getBrawlPredicate().apply(card);
|
||||
return StaticData.instance().getBrawlPredicate().apply(card);
|
||||
}
|
||||
}) {
|
||||
private final Set<String> bannedCommanders = ImmutableSet.of("Baral, Chief of Compliance");
|
||||
|
||||
@Override
|
||||
public boolean isLegalCommander(CardRules rules) {
|
||||
return super.isLegalCommander(rules) && !bannedCommanders.contains(rules.getName());
|
||||
}
|
||||
},
|
||||
}),
|
||||
TinyLeaders ( Range.is(49), Range.between(0, 10), 1, new Predicate<CardRules>() {
|
||||
private final Set<String> bannedCards = ImmutableSet.of(
|
||||
"Ancestral Recall", "Balance", "Black Lotus", "Black Vise", "Channel", "Chaos Orb", "Contract From Below", "Counterbalance", "Darkpact", "Demonic Attorney", "Demonic Tutor", "Earthcraft", "Edric, Spymaster of Trest", "Falling Star",
|
||||
@@ -167,8 +144,12 @@ public enum DeckFormat {
|
||||
cardPoolFilter = null;
|
||||
}
|
||||
|
||||
private boolean hasCommander() {
|
||||
return this == Commander || this == TinyLeaders || this == Brawl;
|
||||
public boolean hasCommander() {
|
||||
return this == Commander || this == Oathbreaker || this == TinyLeaders || this == Brawl;
|
||||
}
|
||||
|
||||
public boolean hasSignatureSpell() {
|
||||
return this == Oathbreaker;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -232,41 +213,56 @@ public enum DeckFormat {
|
||||
noBasicLands = conspiracies.countByName(SOVREALM, false) > 0;
|
||||
}
|
||||
|
||||
if (hasCommander()) { // 1 Commander, or 2 Partner Commanders
|
||||
final List<PaperCard> commanders = deck.getCommanders();
|
||||
|
||||
if (commanders.isEmpty()) {
|
||||
return "is missing a commander";
|
||||
}
|
||||
|
||||
if (commanders.size() > 2) {
|
||||
return "too many commanders";
|
||||
}
|
||||
|
||||
if (hasCommander()) {
|
||||
byte cmdCI = 0;
|
||||
for (PaperCard pc : commanders) {
|
||||
if (!isLegalCommander(pc.getRules())) {
|
||||
return "has an illegal commander";
|
||||
if (equals(DeckFormat.Oathbreaker)) { // 1 Oathbreaker and 1 Signature Spell
|
||||
PaperCard oathbreaker = deck.getOathbreaker();
|
||||
if (oathbreaker == null) {
|
||||
return "is missing an oathbreaker";
|
||||
}
|
||||
cmdCI |= pc.getRules().getColorIdentity().getColor();
|
||||
if (deck.getSignatureSpell() == null) {
|
||||
return "is missing a signature spell";
|
||||
}
|
||||
if (deck.getCommanders().size() > 2) {
|
||||
return "has too many commanders";
|
||||
}
|
||||
cmdCI = oathbreaker.getRules().getColorIdentity().getColor();
|
||||
}
|
||||
else { // 1 Commander or 2 Partner Commanders
|
||||
final List<PaperCard> commanders = deck.getCommanders();
|
||||
|
||||
// special check for Partner
|
||||
if (commanders.size() == 2) {
|
||||
// two commander = 98 cards
|
||||
min--;
|
||||
max--;
|
||||
if (commanders.isEmpty()) {
|
||||
return "is missing a commander";
|
||||
}
|
||||
|
||||
PaperCard a = commanders.get(0);
|
||||
PaperCard b = commanders.get(1);
|
||||
if (commanders.size() > 2) {
|
||||
return "has too many commanders";
|
||||
}
|
||||
|
||||
if (a.getRules().hasKeyword("Partner") && b.getRules().hasKeyword("Partner")) {
|
||||
// normal partner commander
|
||||
} else if (a.getName().equals(b.getRules().getParterWith())
|
||||
&& b.getName().equals(a.getRules().getParterWith())) {
|
||||
// paired partner commander
|
||||
} else {
|
||||
return "has an illegal commander partnership";
|
||||
for (PaperCard pc : commanders) {
|
||||
if (!isLegalCommander(pc.getRules())) {
|
||||
return "has an illegal commander";
|
||||
}
|
||||
cmdCI |= pc.getRules().getColorIdentity().getColor();
|
||||
}
|
||||
|
||||
// special check for Partner
|
||||
if (commanders.size() == 2) {
|
||||
// two commander = 98 cards
|
||||
min--;
|
||||
max--;
|
||||
|
||||
PaperCard a = commanders.get(0);
|
||||
PaperCard b = commanders.get(1);
|
||||
|
||||
if (a.getRules().hasKeyword("Partner") && b.getRules().hasKeyword("Partner")) {
|
||||
// normal partner commander
|
||||
} else if (a.getName().equals(b.getRules().getPartnerWith())
|
||||
&& b.getName().equals(a.getRules().getPartnerWith())) {
|
||||
// paired partner commander
|
||||
} else {
|
||||
return "has an illegal commander partnership";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,7 +439,10 @@ public enum DeckFormat {
|
||||
if (cardPoolFilter != null && !cardPoolFilter.apply(rules)) {
|
||||
return false;
|
||||
}
|
||||
if(this.equals(DeckFormat.Brawl)) {
|
||||
if (this.equals(DeckFormat.Oathbreaker)) {
|
||||
return rules.canBeOathbreaker();
|
||||
}
|
||||
if (this.equals(DeckFormat.Brawl)) {
|
||||
return rules.canBeBrawlCommander();
|
||||
}
|
||||
return rules.canBeCommander();
|
||||
@@ -505,19 +504,17 @@ public enum DeckFormat {
|
||||
|
||||
public Predicate<PaperCard> isLegalCardForCommanderPredicate(List<PaperCard> commanders) {
|
||||
byte cmdCI = 0;
|
||||
boolean hasPartner = false;
|
||||
for (final PaperCard p : commanders) {
|
||||
cmdCI |= p.getRules().getColorIdentity().getColor();
|
||||
if (p.getRules().canBePartnerCommander()) {
|
||||
hasPartner = true;
|
||||
}
|
||||
}
|
||||
return Predicates.compose(CardRulesPredicates.hasColorIdentity(cmdCI), PaperCard.FN_GET_RULES);
|
||||
}
|
||||
|
||||
public Predicate<PaperCard> isLegalCardForCommanderOrLegalPartnerPredicate(List<PaperCard> commanders) {
|
||||
byte cmdCI = 0;
|
||||
for (final PaperCard p : commanders) {
|
||||
cmdCI |= p.getRules().getColorIdentity().getColor();
|
||||
Predicate<CardRules> predicate = CardRulesPredicates.hasColorIdentity(cmdCI);
|
||||
if (hasPartner) { //also show available partners a commander can have a partner
|
||||
predicate = Predicates.or(predicate, CardRulesPredicates.Presets.CAN_BE_PARTNER_COMMANDER);
|
||||
}
|
||||
// TODO : check commander what kind of Partner it needs
|
||||
return Predicates.compose(Predicates.or(CardRulesPredicates.hasColorIdentity(cmdCI),
|
||||
CardRulesPredicates.Presets.CAN_BE_PARTNER_COMMANDER), PaperCard.FN_GET_RULES);
|
||||
return Predicates.compose(predicate, PaperCard.FN_GET_RULES);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user