Partner commanders: Partner, Partner—<variant>, Partner with, Background, Doctor

A Commander/Brawl deck can now have two commanders when their abilities
allow it. Partner abilities are parsed from oracle text (Scryfall's keyword
list files every "Partner—Survivors"-style variant under plain "Partner"),
and a second search box offers only cards that can pair with the commander.
The legality check accepts a valid pair and checks color identity against
both; suggestions and decklist import/export handle both commanders.

Closes #4
This commit is contained in:
2026-10-23 22:29:56 -05:00
parent 5f19ddfa4a
commit bfad4c1f27
11 changed files with 526 additions and 54 deletions

View File

@@ -329,6 +329,32 @@ pub fn set_deck_commander(db: Db, deck_id: i64, oracle_id: Option<String>) -> Re
.map_err(|e| e.to_string())
}
/// Set the deck's commanders — one, or a partner pair — first is primary.
#[tauri::command]
pub fn set_deck_commanders(db: Db, deck_id: i64, oracle_ids: Vec<String>) -> Res<()> {
let s = db.lock().unwrap();
let ids: Vec<&str> = oracle_ids.iter().map(String::as_str).collect();
s.catalog()?
.set_deck_commanders(deck_id, &ids)
.map_err(|e| e.to_string())
}
/// Name search narrowed to cards that could partner with the given commander.
/// Searches wide before filtering, since most name matches won't qualify.
#[tauri::command]
pub fn search_partners(
db: Db,
commander_oracle_id: String,
query: String,
limit: usize,
) -> Res<Vec<CardRef>> {
let s = db.lock().unwrap();
let candidates = s.index()?.search(&query, 500);
s.catalog()?
.partner_candidates(&commander_oracle_id, candidates, limit)
.map_err(|e| e.to_string())
}
#[tauri::command]
pub fn set_deck_card(
db: Db,

View File

@@ -103,6 +103,8 @@ pub fn run() {
commands::duplicate_deck,
commands::set_deck_format,
commands::set_deck_commander,
commands::set_deck_commanders,
commands::search_partners,
commands::set_deck_card,
commands::deck_contents,
commands::suggest_cards,