diff --git a/openfut-adapter-fifa17/src/fut/store_catalog.rs b/openfut-adapter-fifa17/src/fut/store_catalog.rs index 3319cc3..053c9fe 100644 --- a/openfut-adapter-fifa17/src/fut/store_catalog.rs +++ b/openfut-adapter-fifa17/src/fut/store_catalog.rs @@ -170,8 +170,30 @@ pub fn pack_body(p: &PackDef, idx: u64, owned: bool) -> Value { _ => 1, } }; + // My Packs cover art. LIVE-MAPPED on the retail client 2026-08-18 across all + // three store tabs and two reward tiles: + // * `assetId` only gates whether art renders AT ALL. A reward pack's own id + // (70-75) is not a known client asset, so its tile renders BLANK; any valid + // catalogue asset (1-6) makes art appear. + // * WHICH art is drawn comes from `packType` + `packContentInfo.rareQuantity`, + // not from `assetId`: BRONZE+1rare -> bronze card, BRONZE+3 -> silver, + // SILVER+1 -> gold, SILVER+3 -> silver trio, GOLD+1 -> blue special, + // GOLD+3 -> red inform. (Remapping assetId 5->3 and 3->2 left both frames + // unchanged and only rotated the featured player, which proves this.) + // So a reward tile automatically shows the same art as the equivalent + // purchasable pack; we only need a valid asset, and we use the tier's own store + // pack for clarity. `id` stays the pack's own id (the open packId / SERVER_ID). + let art_asset: u64 = if owned { + match p.category { + "gold" => 5, + "silver" => 3, + _ => 1, + } + } else { + p.id + }; let mut body = json!({ - "assetId": p.id, + "assetId": art_asset, "id": p.id, "packType": pack_type, "description": p.name, @@ -249,6 +271,9 @@ pub fn sentinel_body(idx: u64) -> Value { // The sentinel must stay non-openable (it is only a resolve-without-crash shim // for an empty My Packs), so it keeps no purchase path. obj.remove("currencies"); + // Keep the sentinel's own id as its asset: it must render as an inert blank + // placeholder, never borrow a real pack's cover. + obj.insert("assetId".into(), json!(SENTINEL_PACK_ID)); body } @@ -346,6 +371,28 @@ mod tests { assert_eq!(owned_pack_id_for_definition("mystery_pack"), None); } + #[test] + fn reward_tiles_carry_a_renderable_cover_asset() { + // A reward pack's own id is not a client art asset, so its My Packs tile + // renders blank. Each reward tile must therefore carry a valid catalogue + // assetId (its tier's store pack) while `id` stays the open packId. + for (reward_id, want_asset) in [(71, 1), (72, 3), (73, 5), (74, 5), (75, 5)] { + let pack = pack_by_id(reward_id).expect("reward pack in catalogue"); + let tile = pack_body(pack, 1, true); + assert_eq!(tile["id"], reward_id, "open packId stays the pack's own id"); + assert_eq!( + tile["assetId"], want_asset, + "reward tile borrows its tier's store-pack cover asset" + ); + assert!( + pack_by_id(tile["assetId"].as_u64().unwrap()).is_some_and(|p| !p.owned_only), + "the cover asset must be a real purchasable catalogue pack" + ); + } + // The sentinel must NOT borrow a real cover — it stays an inert placeholder. + assert_eq!(sentinel_body(1)["assetId"], SENTINEL_PACK_ID); + } + #[test] fn symbolic_reward_pack_renders_as_openable_my_packs_tile() { // A granted silver reward pack (resolved to id 72) must appear as an owned diff --git a/openfut-adapter-fifa17/tests/fixtures/purchasegroup_pack70.json b/openfut-adapter-fifa17/tests/fixtures/purchasegroup_pack70.json index db4c3dc..e3f1cca 100644 --- a/openfut-adapter-fifa17/tests/fixtures/purchasegroup_pack70.json +++ b/openfut-adapter-fifa17/tests/fixtures/purchasegroup_pack70.json @@ -199,7 +199,7 @@ } }, { - "assetId": 70, + "assetId": 5, "id": 70, "packType": "GOLD", "description": "Reward Gold Pack",