Prebuilt deck purchasing and fixes

This commit is contained in:
gamer147
2026-05-26 09:16:21 -04:00
parent fa0901b776
commit b6966ece6e
39 changed files with 7392 additions and 15 deletions

View File

@@ -0,0 +1,17 @@
using Microsoft.EntityFrameworkCore;
namespace SVSim.Database.Models;
/// <summary>
/// One card in a prebuilt-deck product's 40-card list. Owned by BuildDeckProductEntry.
/// Shape mirrors `build_deck_package_master.csv` rows: (ProductId, CardId, Number, IsSpot).
/// IsSpot=true marks the special prize/featured cards rendered in the separate _spotCardRoot
/// panel by BuildDeckProductDetail.cs.
/// </summary>
[Owned]
public class BuildDeckProductCardEntry
{
public long CardId { get; set; }
public int Number { get; set; }
public bool IsSpot { get; set; }
}

View File

@@ -0,0 +1,32 @@
using SVSim.Database.Common;
namespace SVSim.Database.Models;
/// <summary>
/// One purchasable prebuilt-deck product. PK = wire product_id. FK SeriesId.
/// Pricing columns are nullable; either Crystal or Rupy pair (or both, both zero for free) must
/// be populated for an enabled product. The Intro/Regular pair captures the two-tier pricing
/// pattern: Intro applies to the first purchase, Regular to subsequent. For PurchaseNumMax=1
/// products, Regular stays null and only Intro is ever served.
/// </summary>
public class BuildDeckProductEntry : BaseEntity<int>
{
public int SeriesId { get; set; }
public int LeaderId { get; set; }
public string DeckCode { get; set; } = string.Empty;
public string ProductNameKey { get; set; } = string.Empty; // BDPN_*
public long FeaturedCardId { get; set; }
public int PurchaseNumMax { get; set; }
public int? IntroPriceCrystal { get; set; }
public int? RegularPriceCrystal { get; set; }
public int? IntroPriceRupy { get; set; }
public int? RegularPriceRupy { get; set; }
public bool IsEnabled { get; set; }
public List<BuildDeckProductCardEntry> Cards { get; set; } = new();
public List<BuildDeckProductRewardEntry> Rewards { get; set; } = new();
public BuildDeckSeriesEntry? Series { get; set; }
}

View File

@@ -0,0 +1,18 @@
using Microsoft.EntityFrameworkCore;
namespace SVSim.Database.Models;
/// <summary>
/// One per-buy reward attached to a prebuilt-deck product. Owned by BuildDeckProductEntry.
/// Wire shape: one entry of the product-level `rewards` dict in /build_deck/info, keyed by
/// RewardIndex (the wire string keys "1","2","3").
/// </summary>
[Owned]
public class BuildDeckProductRewardEntry
{
public int RewardIndex { get; set; }
public int RewardType { get; set; } // Wizard.UserGoods.Type
public long RewardDetailId { get; set; }
public int RewardNumber { get; set; }
public int MessageId { get; set; }
}

View File

@@ -0,0 +1,22 @@
using SVSim.Database.Common;
namespace SVSim.Database.Models;
/// <summary>
/// One prebuilt-deck series ("Structure Deck Set 7", "Trial 19", etc.). PK = wire series_id.
/// IsEnabled gates whether /build_deck/info renders this series — disabled rows are placeholder
/// stubs created from the client CSV until we capture a /info response that enriches them.
/// </summary>
public class BuildDeckSeriesEntry : BaseEntity<int>
{
public int OrderIndex { get; set; } // wire order_id; controls display order
public string NameKey { get; set; } = string.Empty; // BDSSN_*
public string IntroKey { get; set; } = string.Empty; // BDSI_*
public string TitlePath { get; set; } = string.Empty;
public string DrumrollPath { get; set; } = string.Empty;
public bool IsNew { get; set; }
public bool IsEnabled { get; set; }
public List<BuildDeckSeriesRewardEntry> SeriesRewards { get; set; } = new();
public List<BuildDeckProductEntry> Products { get; set; } = new();
}

View File

@@ -0,0 +1,20 @@
using Microsoft.EntityFrameworkCore;
namespace SVSim.Database.Models;
/// <summary>
/// One tier-reward item attached to a prebuilt-deck series. Owned by BuildDeckSeriesEntry.
/// Wire shape: flattened from /build_deck/info's `series_rewards` dict — each tier (keyed
/// by total-purchases-from-series threshold) carries a list of rewards; this row is one
/// (TierIndex, ItemIndex) cell.
/// </summary>
[Owned]
public class BuildDeckSeriesRewardEntry
{
public int TierIndex { get; set; } // 1, 2, 3, ... — unlock threshold
public int ItemIndex { get; set; } // ordinal within tier
public int RewardType { get; set; }
public long RewardDetailId { get; set; }
public int RewardNumber { get; set; }
public int MessageId { get; set; }
}

View File

@@ -57,6 +57,8 @@ public class Viewer : BaseEntity<long>
public List<ViewerPackOpenCount> PackOpenCounts { get; set; } = new List<ViewerPackOpenCount>();
public List<ViewerBuildDeckProductPurchase> BuildDeckPurchases { get; set; } = new List<ViewerBuildDeckProductPurchase>();
#endregion
#region Navigation Properties

View File

@@ -0,0 +1,14 @@
using Microsoft.EntityFrameworkCore;
namespace SVSim.Database.Models;
/// <summary>
/// Per-viewer, per-product purchase counter. Owned collection on Viewer.
/// Unique (ViewerId, ProductId) enforced in SVSimDbContext per project_owned_collection_unique_index.
/// </summary>
[Owned]
public class ViewerBuildDeckProductPurchase
{
public int ProductId { get; set; }
public int PurchaseCount { get; set; }
}