diff --git a/SVSim.Database/Models/Config/LoginBonusConfig.cs b/SVSim.Database/Models/Config/LoginBonusConfig.cs new file mode 100644 index 00000000..93a17ea9 --- /dev/null +++ b/SVSim.Database/Models/Config/LoginBonusConfig.cs @@ -0,0 +1,58 @@ +using SVSim.Database.Enums; + +namespace SVSim.Database.Models.Config; + +/// +/// Daily login bonus catalog. The Normal cycle is the always-on N-day streak. Total +/// (continuous milestones) and Campaign (date-bounded specials) are placeholders — wire +/// emits empty arrays for them until a campaign is captured and seeded here. +/// +[ConfigSection("LoginBonus")] +public class LoginBonusConfig +{ + public int CampaignId { get; set; } = 3; + public string Name { get; set; } = "Daily Bonus"; + + /// BG image asset key — wire ships as string. Prod captured value is "0". + public string Img { get; set; } = "0"; + + /// + /// Normal-cycle reward entries, 1-based by Day. Defaults to a 15-day cycle copied + /// verbatim from the prod tutorial capture (traffic_prod_tutorial.ndjson). + /// + public List Normal { get; set; } = new(); + + public static LoginBonusConfig ShippedDefaults() => new() + { + CampaignId = 3, + Name = "Daily Bonus", + Img = "0", + Normal = new List + { + new() { Day = 1, EffectId = 1, RewardType = UserGoodsType.Rupy, RewardDetailId = 0, RewardNumber = 20 }, + new() { Day = 2, EffectId = 1, RewardType = UserGoodsType.Rupy, RewardDetailId = 0, RewardNumber = 20 }, + new() { Day = 3, EffectId = 1, RewardType = UserGoodsType.Rupy, RewardDetailId = 0, RewardNumber = 20 }, + new() { Day = 4, EffectId = 1, RewardType = UserGoodsType.Rupy, RewardDetailId = 0, RewardNumber = 20 }, + new() { Day = 5, EffectId = 2, RewardType = UserGoodsType.Item, RewardDetailId = 80001, RewardNumber = 1 }, + new() { Day = 6, EffectId = 1, RewardType = UserGoodsType.Rupy, RewardDetailId = 0, RewardNumber = 30 }, + new() { Day = 7, EffectId = 1, RewardType = UserGoodsType.Rupy, RewardDetailId = 0, RewardNumber = 30 }, + new() { Day = 8, EffectId = 1, RewardType = UserGoodsType.Rupy, RewardDetailId = 0, RewardNumber = 30 }, + new() { Day = 9, EffectId = 1, RewardType = UserGoodsType.Rupy, RewardDetailId = 0, RewardNumber = 30 }, + new() { Day = 10, EffectId = 2, RewardType = UserGoodsType.Item, RewardDetailId = 80001, RewardNumber = 1 }, + new() { Day = 11, EffectId = 1, RewardType = UserGoodsType.Rupy, RewardDetailId = 0, RewardNumber = 40 }, + new() { Day = 12, EffectId = 1, RewardType = UserGoodsType.Rupy, RewardDetailId = 0, RewardNumber = 40 }, + new() { Day = 13, EffectId = 1, RewardType = UserGoodsType.Rupy, RewardDetailId = 0, RewardNumber = 40 }, + new() { Day = 14, EffectId = 1, RewardType = UserGoodsType.Rupy, RewardDetailId = 0, RewardNumber = 40 }, + new() { Day = 15, EffectId = 2, RewardType = UserGoodsType.Item, RewardDetailId = 1, RewardNumber = 1 }, + }, + }; +} + +public class NormalBonusEntry +{ + public int Day { get; set; } + public int EffectId { get; set; } = 1; + public UserGoodsType RewardType { get; set; } + public long RewardDetailId { get; set; } + public int RewardNumber { get; set; } +} diff --git a/SVSim.UnitTests/Config/LoginBonusConfigTests.cs b/SVSim.UnitTests/Config/LoginBonusConfigTests.cs new file mode 100644 index 00000000..d900e20a --- /dev/null +++ b/SVSim.UnitTests/Config/LoginBonusConfigTests.cs @@ -0,0 +1,37 @@ +using NUnit.Framework; +using SVSim.Database.Enums; +using SVSim.Database.Models.Config; + +namespace SVSim.UnitTests.Config; + +public class LoginBonusConfigTests +{ + [Test] + public void ShippedDefaults_matches_prod_normal_cycle() + { + var cfg = LoginBonusConfig.ShippedDefaults(); + + Assert.That(cfg.CampaignId, Is.EqualTo(3)); + Assert.That(cfg.Name, Is.EqualTo("Daily Bonus")); + Assert.That(cfg.Img, Is.EqualTo("0")); + Assert.That(cfg.Normal, Has.Count.EqualTo(15)); + + // Day 1: 20 Rupy + Assert.That(cfg.Normal[0].Day, Is.EqualTo(1)); + Assert.That(cfg.Normal[0].RewardType, Is.EqualTo(UserGoodsType.Rupy)); + Assert.That(cfg.Normal[0].RewardDetailId, Is.EqualTo(0)); + Assert.That(cfg.Normal[0].RewardNumber, Is.EqualTo(20)); + Assert.That(cfg.Normal[0].EffectId, Is.EqualTo(1)); + + // Day 5: Item 80001 ×1 with effect 2 (the highlight ticket) + Assert.That(cfg.Normal[4].RewardType, Is.EqualTo(UserGoodsType.Item)); + Assert.That(cfg.Normal[4].RewardDetailId, Is.EqualTo(80001)); + Assert.That(cfg.Normal[4].RewardNumber, Is.EqualTo(1)); + Assert.That(cfg.Normal[4].EffectId, Is.EqualTo(2)); + + // Day 15: Item id 1 ×1 with effect 2 (cycle capstone) + Assert.That(cfg.Normal[14].RewardType, Is.EqualTo(UserGoodsType.Item)); + Assert.That(cfg.Normal[14].RewardDetailId, Is.EqualTo(1)); + Assert.That(cfg.Normal[14].RewardNumber, Is.EqualTo(1)); + } +}