From aaf632a417675f51488b76620b83bf027d7e4652 Mon Sep 17 00:00:00 2001 From: Garrett Mills Date: Wed, 22 Jul 2026 21:30:08 -0500 Subject: [PATCH] Fix Battle cards not detected as horizontal during ingest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Real Battle cards are layout "transform" (they flip into a creature), not "battle" as previously assumed — no shipped card actually uses that layout, so the horizontal flag never got set for them. Detect Battle orientation from the front face's type line instead. --- crates/mtgc-core/src/ingest.rs | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/crates/mtgc-core/src/ingest.rs b/crates/mtgc-core/src/ingest.rs index 26b5695..075c483 100644 --- a/crates/mtgc-core/src/ingest.rs +++ b/crates/mtgc-core/src/ingest.rs @@ -546,7 +546,19 @@ fn load_oracle_cards(conn: &Connection, reader: impl Read, cancel: &CancelToken) // Battles and Planes/Phenomena store their card image portrait-shaped // with the content itself rotated — viewers must rotate it 90° to // read it right-side up (verified against real Scryfall images). - let horizontal = matches!(c.layout.as_str(), "battle" | "planar"); + // Battles are *not* `layout: "battle"` in Scryfall's data — every + // released Battle (the "Invasion of ..." Sieges) transforms into a + // creature, so it's `layout: "transform"` with the Battle type only + // on the front face. Detect it from the front face's type instead + // of the layout. + let front_type_line = type_line.split(" // ").next().unwrap_or(""); + let is_battle = front_type_line + .split('—') + .next() + .unwrap_or("") + .split_whitespace() + .any(|w| w == "Battle"); + let horizontal = is_battle || c.layout == "planar"; let changed = ins_card.execute(params![ oracle_id, @@ -1020,8 +1032,13 @@ mod tests { #[test] fn captures_horizontal_flag_for_battle_and_planar_layouts_only() { let oracle = r#"[ - {"oracle_id":"oid-battle","name":"Invasion of Zendikar","layout":"battle","cmc":4.0, - "type_line":"Battle — Siege","color_identity":["G"],"keywords":[]}, + {"oracle_id":"oid-battle","name":"Invasion of Zendikar // Awakened Skyclave", + "layout":"transform","cmc":4.0, + "card_faces":[ + {"type_line":"Battle — Siege"}, + {"type_line":"Creature — Elemental"} + ], + "color_identity":["G"],"keywords":[]}, {"oracle_id":"oid-plane","name":"Academy at Tolaria West","layout":"planar","cmc":0.0, "type_line":"Plane — Dominaria","color_identity":[],"keywords":[]}, {"oracle_id":"oid-scheme","name":"A Display of My Dark Power","layout":"scheme","cmc":0.0, @@ -1045,9 +1062,12 @@ mod tests { != 0 }; + // Real Battle cards are `layout: "transform"` (they flip into a + // creature once defeated) — only the front face carries the Battle + // type, so detection has to key off that, not the layout string. assert!(horizontal("oid-battle")); assert!(horizontal("oid-plane")); - // Schemes are oversized but not rotated — only battle/planar layouts are. + // Schemes are oversized but not rotated — only Battle/planar cards are. assert!(!horizontal("oid-scheme")); assert!(!horizontal("oid-normal")); }