refactor(pack): type PackChildGachaEntry.TypeDetail as CardPackType enum

This commit is contained in:
gamer147
2026-06-09 08:48:16 -04:00
parent 833bd85d36
commit 7118b92522
10 changed files with 84 additions and 58 deletions

View File

@@ -125,7 +125,7 @@ public class PackController : SVSimController
var today = DateTime.UtcNow.Date;
bool ChildAvailable(PackChildGachaEntry c)
{
if (c.TypeDetail != 10) return true;
if (c.TypeDetail != CardPackType.FreePacks) return true;
if (c.FreeGachaCampaignId is not int campaignId) return true;
if (!freeClaimsByCampaignId.TryGetValue(campaignId, out var claim)) return true;
if (claim.LastClaimedAt.Date != today) return true;
@@ -137,7 +137,8 @@ public class PackController : SVSimController
// Ticket-only pack: every child is TICKET (4) or TICKET_MULTI (5). These are
// gifted-currency packs (tutorial starter, throwback) that don't participate in
// gacha-point accrual or exchange, even if GachaPointConfig is set in seed.
bool isTicketOnly = visibleChildren.All(c => c.TypeDetail == 4 || c.TypeDetail == 5);
bool isTicketOnly = visibleChildren.All(c =>
c.TypeDetail == CardPackType.Ticket || c.TypeDetail == CardPackType.TicketMulti);
PackGachaPointDto? gachaPointDto = null;
if (p.GachaPointConfig is not null && !isTicketOnly)
@@ -174,7 +175,7 @@ public class PackController : SVSimController
ChildGachaInfo = visibleChildren.Select(c => new PackChildGachaDto
{
GachaId = c.GachaId,
TypeDetail = c.TypeDetail,
TypeDetail = (int)c.TypeDetail,
Cost = c.Cost,
Count = c.CardCount,
ItemId = c.ItemId?.ToString(CultureInfo.InvariantCulture),
@@ -298,14 +299,17 @@ public class PackController : SVSimController
// when buying a RUPY_MULTI (type_detail=7) child. The gacha_id alone disambiguates the
// child; gacha_type validation against child.TypeDetail would falsely reject every buy.
// Supported type_details on the normal path:
// 1 CRYSTAL / 2 CRYSTAL_MULTI -> spend crystals
// 6 RUPY / 7 RUPY_MULTI -> spend rupees
// 3 DAILY -> spend rupees, once per UTC day
// 4 TICKET / 5 TICKET_MULTI -> consume child.ItemId from OwnedItemEntry
// Skin-overload types (8/9/13) and free-pack overlays (10/11/12) need extra
// selection / banner plumbing — kept 501 until the relevant flows land.
if (!isTutorialPath && child.TypeDetail is not (1 or 2 or 3 or 4 or 5 or 6 or 7 or 10))
// Supported on the normal path: Crystal / CrystalMulti -> spend crystals; Rupy /
// RupyMulti -> spend rupees; Daily -> spend rupees, once per UTC day; Ticket /
// TicketMulti -> consume child.ItemId from OwnedItemEntry; FreePacks -> no debit,
// gated by per-campaign daily quota.
// CrystalSpecial / CrystalSelectSkin / CrystalAcquireSkinCardPack and the
// FreePackWithSkin / RotationStarterPack overlays need extra selection / banner
// plumbing — kept 501 until the relevant flows land.
if (!isTutorialPath && child.TypeDetail is not (
CardPackType.Crystal or CardPackType.CrystalMulti or CardPackType.Daily or
CardPackType.Ticket or CardPackType.TicketMulti or CardPackType.Rupy or
CardPackType.RupyMulti or CardPackType.FreePacks))
return StatusCode(StatusCodes.Status501NotImplemented, new { error = "currency_path_not_implemented" });
// Load viewer via InventoryService transaction with extra includes for pack-open needs.
@@ -331,23 +335,23 @@ public class PackController : SVSimController
{
switch (child.TypeDetail)
{
case 1: // CRYSTAL (single)
case 2: // CRYSTAL_MULTI (10-pack)
case CardPackType.Crystal:
case CardPackType.CrystalMulti:
{
long cost = (long)child.Cost * packNumber;
var r = await tx.TrySpendAsync(SpendCurrency.Crystal, cost);
if (!r.Success) return BadRequest(new { error = "insufficient_crystals" });
break;
}
case 6: // RUPY (single)
case 7: // RUPY_MULTI (10-pack)
case CardPackType.Rupy:
case CardPackType.RupyMulti:
{
long cost = (long)child.Cost * packNumber;
var r = await tx.TrySpendAsync(SpendCurrency.Rupee, cost);
if (!r.Success) return BadRequest(new { error = "insufficient_rupees" });
break;
}
case 3: // DAILY single — once per UTC day
case CardPackType.Daily:
{
// TODO(daily-reset): no project-wide daily-reset convention exists yet. Using UTC
// midnight; revisit when the global reset boundary is settled.
@@ -361,8 +365,8 @@ public class PackController : SVSimController
if (!r.Success) return BadRequest(new { error = "insufficient_rupees" });
break;
}
case 4: // TICKET (single)
case 5: // TICKET_MULTI (10-pack)
case CardPackType.Ticket:
case CardPackType.TicketMulti:
{
if (child.ItemId is not long ticketItemId)
return StatusCode(StatusCodes.Status501NotImplemented, new { error = "ticket_pack_missing_item_id" });
@@ -372,7 +376,7 @@ public class PackController : SVSimController
if (!debit.Success) return BadRequest(new { error = "insufficient_tickets" });
break;
}
case 10: // FREE_PACKS — no currency, no ticket; gated by daily quota per campaign
case CardPackType.FreePacks:
{
if (child.FreeGachaCampaignId is not int campaignId)
return StatusCode(StatusCodes.Status501NotImplemented, new { error = "free_pack_missing_campaign_id" });
@@ -417,7 +421,7 @@ public class PackController : SVSimController
if (!isTutorialPath)
{
await _packs.IncrementOpenCount(viewerId, pack.Id, packNumber);
if (child.TypeDetail == 3)
if (child.TypeDetail == CardPackType.Daily)
{
await _packs.MarkDailyFreeUsed(viewerId, pack.Id, DateTime.UtcNow);
}