fix(gacha-points): include IsLeader cards regardless of draw tier
Prod's /pack/get_gacha_point_rewards offers leader cards from packs where the leader sits in a non-Legendary tier — UCL pack 16015 has Kyoka (711531010, Runecraft) and Miyako (711331010, Dragoncraft) as Gold-tier rows with is_leader=1 in the drawrates. The old filter (Tier == Legendary && !IsAltArt) excluded them, so the in-game exchange UI was empty despite the banner advertising leader-card draw rates. Fix: filter on (Tier == Legendary || IsLeader) && !IsAltArt. Captures every legendary plus any leader card regardless of page tier. Verified against the captured 16015 response in traffic_prod_all_gacha_exchange.ndjson (28 entries: 26 legendaries + 2 Gold-tier leaders). Across the seeded data this surfaces 6 additional cards: 3 Bronze-tier leaders + 3 Gold-tier leaders. The 68 Legendary-tier and 81 Special- tier leaders were already included. Renames legendaryCardIds -> exchangeableCardIds for clarity. Regression test seeds a Gold-tier IsLeader=true card with a Skin row and asserts the exchange catalog returns it with the Skin reward entry. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -38,23 +38,27 @@ public sealed class GachaPointService : IGachaPointService
|
||||
.Select(r => r.CardId)
|
||||
.ToListAsync()).ToHashSet();
|
||||
|
||||
// Legendaries in the pack's draw table — exchange ignores foils (the alt-art foil
|
||||
// printing is gated separately) and tiers other than Legendary.
|
||||
var legendaryCardIds = drawTable.CardWeights
|
||||
.Where(w => w.Tier == DrawTier.Legendary && !w.IsAltArt)
|
||||
// Cards exchangeable for gacha points: the pack's draw-table pool, excluding alt-art
|
||||
// (the foil/alt printing is gated separately). The exchange covers (a) every Legendary
|
||||
// and (b) any IsLeader card regardless of tier — UCL pack 16015 has Kyoka and Miyako
|
||||
// as Gold-tier leaders that prod still offers. Filtering on Legendary alone would miss
|
||||
// them. Verified against the captured 16015 response in
|
||||
// traffic_prod_all_gacha_exchange.ndjson.
|
||||
var exchangeableCardIds = drawTable.CardWeights
|
||||
.Where(w => !w.IsAltArt && (w.Tier == DrawTier.Legendary || w.IsLeader))
|
||||
.Select(w => w.CardId)
|
||||
.ToHashSet();
|
||||
|
||||
// Re-query legendaries with Class loaded — pool provider doesn't include navs,
|
||||
// so card.Class is null on every pool entry and class_id would collapse to "0".
|
||||
// Re-query with Class loaded — pool provider doesn't include navs, so card.Class is
|
||||
// null on every pool entry and class_id would collapse to "0".
|
||||
var legendariesWithClass = await _db.Cards
|
||||
.Where(c => legendaryCardIds.Contains(c.Id))
|
||||
.Where(c => exchangeableCardIds.Contains(c.Id))
|
||||
.Include(c => c.Class)
|
||||
.ToListAsync();
|
||||
|
||||
// Pull both cosmetic types in one trip. Group by card_id for O(1) lookup below.
|
||||
var cosmeticsByCard = await _db.CardCosmeticRewards
|
||||
.Where(r => legendaryCardIds.Contains(r.CardId)
|
||||
.Where(r => exchangeableCardIds.Contains(r.CardId)
|
||||
&& (r.Type == CosmeticType.Emblem || r.Type == CosmeticType.Skin))
|
||||
.ToListAsync();
|
||||
var cosmeticLookup = cosmeticsByCard
|
||||
|
||||
Reference in New Issue
Block a user