Add deck legality checking, deck/library import-export, and a command palette
Threads Scryfall's per-format legalities through the reference db and adds a deck-page indicator (structural rules + banned/restricted lists) that lists violation reasons inline. Decks and selected library cards can now be exported to/imported from plain-text decklists, with best-effort name resolution and a report of anything that didn't match. Also adds a shuffle- and-draw sample hand modal, and an Alt+/ command palette for jumping to a tab, deck, or card without leaving the keyboard. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
45
src/api.ts
45
src/api.ts
@@ -15,6 +15,7 @@ export interface CardRef {
|
||||
produced_mana: number; // WUBRG bitmask of mana this card can tap for
|
||||
produces_colorless: boolean; // can produce {C}
|
||||
price_usd: number; // USD market price, or 0 if unknown
|
||||
legalities: number; // 2 bits/format bitmask, see LEGALITY_FORMATS
|
||||
}
|
||||
|
||||
export interface LibraryCard extends CardRef {
|
||||
@@ -41,6 +42,16 @@ export interface Deck {
|
||||
notes: string;
|
||||
}
|
||||
|
||||
export interface DeckImportResult {
|
||||
deck: Deck;
|
||||
unresolved: string[];
|
||||
}
|
||||
|
||||
export interface LibraryImportResult {
|
||||
added: [string, number][];
|
||||
unresolved: string[];
|
||||
}
|
||||
|
||||
export interface LibraryFilter {
|
||||
text?: string | null;
|
||||
colors_exact?: number | null;
|
||||
@@ -107,6 +118,32 @@ export function maskToLetters(mask: number): string {
|
||||
.join("");
|
||||
}
|
||||
|
||||
// --- Legality bitmask helpers ----------------------------------------------
|
||||
// Mirrors mtgc-core's model::LEGALITY_FORMATS / Legalities exactly: 2 bits per
|
||||
// format, in this fixed order. Do not reorder.
|
||||
|
||||
export const LEGALITY_FORMATS: { key: string; label: string }[] = [
|
||||
{ key: "standard", label: "Standard" },
|
||||
{ key: "pioneer", label: "Pioneer" },
|
||||
{ key: "modern", label: "Modern" },
|
||||
{ key: "legacy", label: "Legacy" },
|
||||
{ key: "vintage", label: "Vintage" },
|
||||
{ key: "pauper", label: "Pauper" },
|
||||
{ key: "commander", label: "Commander" },
|
||||
{ key: "brawl", label: "Brawl" },
|
||||
];
|
||||
|
||||
export type LegalStatus = "not_legal" | "legal" | "banned" | "restricted";
|
||||
|
||||
const LEGAL_STATUS_CODES: readonly LegalStatus[] = ["not_legal", "legal", "banned", "restricted"];
|
||||
|
||||
export function legalStatusFor(legalities: number, formatLabel: string): LegalStatus {
|
||||
const i = LEGALITY_FORMATS.findIndex((f) => f.label === formatLabel);
|
||||
if (i < 0) return "not_legal";
|
||||
const code = (legalities >> (i * 2)) & 0b11;
|
||||
return LEGAL_STATUS_CODES[code];
|
||||
}
|
||||
|
||||
// --- Commands -------------------------------------------------------------
|
||||
|
||||
export const api = {
|
||||
@@ -150,4 +187,12 @@ export const api = {
|
||||
) => invoke<void>("set_deck_card", { deckId, oracleId, quantity, isCommander, isMaybeboard }),
|
||||
deckContents: (deckId: number) => invoke<DeckEntry[]>("deck_contents", { deckId }),
|
||||
cardDecks: (oracleId: string) => invoke<Deck[]>("card_decks", { oracleId }),
|
||||
|
||||
exportDeck: (deckId: number, path: string) => invoke<void>("export_deck", { deckId, path }),
|
||||
importDeck: (path: string, name: string) =>
|
||||
invoke<DeckImportResult>("import_deck", { path, name }),
|
||||
exportLibraryCards: (oracleIds: string[], path: string) =>
|
||||
invoke<void>("export_library_cards", { oracleIds, path }),
|
||||
importLibraryCards: (path: string) =>
|
||||
invoke<LibraryImportResult>("import_library_cards", { path }),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user