diff --git a/Common/Data/Excel/SupportCardExcel.cs b/Common/Data/Excel/SupportCardExcel.cs index 9ceb53c..431a290 100644 --- a/Common/Data/Excel/SupportCardExcel.cs +++ b/Common/Data/Excel/SupportCardExcel.cs @@ -1,3 +1,5 @@ +using Newtonsoft.Json; + namespace MikuSB.Data.Excel; [ResourceEntity("support_card.json")] @@ -8,6 +10,18 @@ public class SupportCardExcel : ExcelResource public uint Particular { get; set; } public uint Level { get; set; } public uint Icon { get; set; } + public uint ProvideExp { get; set; } + [JsonProperty("LevelLimitID")] public int LevelLimitId { get; set; } + + public uint MaxLevel => LevelLimitId switch + { + 1007 => 10, + 1008 => 13, + 1009 => 16, + _ => 10 + }; + + public ulong TemplateId => GameResourceTemplateId.FromGdpl(Genre, Detail, Particular, Level); public override uint GetId() => Icon; diff --git a/Common/Database/Inventory/InventoryData.cs b/Common/Database/Inventory/InventoryData.cs index c1ab3d1..495e18d 100644 --- a/Common/Database/Inventory/InventoryData.cs +++ b/Common/Database/Inventory/InventoryData.cs @@ -26,24 +26,29 @@ public class BaseGameItemInfo public uint ItemCount { get; set; } public ItemTypeEnum ItemType { get; set; } public ItemFlagEnum Flag { get; set; } = ItemFlagEnum.FLAG_READED; + public uint Level { get; set; } + public uint Exp { get; set; } public virtual Item ToProto() { - return new Item + var proto = new Item { Id = UniqueId, Template = TemplateId, Count = ItemCount, Flag = (uint)Flag }; + if (Level > 0 || Exp > 0) + proto.Enhance = new Enhance { Level = Level, Exp = Exp }; + return proto; } } public abstract class GrowableItemInfo : BaseGameItemInfo { public bool IsLocked { get; set; } - public uint Level { get; set; } - public uint Exp { get; set; } + public new uint Level { get; set; } + public new uint Exp { get; set; } public uint Break { get; set; } public uint EquipAvatarId { get; set; } } diff --git a/GameServer/Server/CallGS/Handlers/Girl/SupporterCard_Equip.cs b/GameServer/Server/CallGS/Handlers/SupporterCard/SupporterCard_Equip.cs similarity index 97% rename from GameServer/Server/CallGS/Handlers/Girl/SupporterCard_Equip.cs rename to GameServer/Server/CallGS/Handlers/SupporterCard/SupporterCard_Equip.cs index b608e4e..25277d1 100644 --- a/GameServer/Server/CallGS/Handlers/Girl/SupporterCard_Equip.cs +++ b/GameServer/Server/CallGS/Handlers/SupporterCard/SupporterCard_Equip.cs @@ -3,7 +3,7 @@ using MikuSB.Proto; using System.Text.Json; using System.Text.Json.Serialization; -namespace MikuSB.GameServer.Server.CallGS.Handlers.Girl; +namespace MikuSB.GameServer.Server.CallGS.Handlers.SupporterCard; [CallGSApi("SupporterCard_Equip")] public class SupporterCard_Equip : ICallGSHandler diff --git a/GameServer/Server/CallGS/Handlers/SupporterCard/SupporterCard_Upgrade.cs b/GameServer/Server/CallGS/Handlers/SupporterCard/SupporterCard_Upgrade.cs new file mode 100644 index 0000000..805ffda --- /dev/null +++ b/GameServer/Server/CallGS/Handlers/SupporterCard/SupporterCard_Upgrade.cs @@ -0,0 +1,119 @@ +using MikuSB.Data; +using MikuSB.Database; +using MikuSB.Proto; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace MikuSB.GameServer.Server.CallGS.Handlers.SupporterCard; + +[CallGSApi("SupporterCard_Upgrade")] +public class SupporterCard_Upgrade : ICallGSHandler +{ + public async Task Handle(Connection connection, string param, ushort seqNo) + { + var player = connection.Player!; + var req = JsonSerializer.Deserialize(param); + if (req == null || req.SupportCardUid == 0 || req.Materials == null || req.Materials.Count == 0) + { + await CallGSRouter.SendScript(connection, "Logistics_Upgrade", "{}"); + return; + } + + var supportCard = player.InventoryManager.InventoryData.Items.GetValueOrDefault((uint)req.SupportCardUid); + if (supportCard == null) + { + await CallGSRouter.SendScript(connection, "Logistics_Upgrade", "{}"); + return; + } + + var supportCardExcel = GameData.SupportCardData.FirstOrDefault(x => x.TemplateId == supportCard.TemplateId); + var maxLevel = supportCardExcel?.MaxLevel ?? 10; + + // Validate all materials exist with sufficient count + foreach (var mat in req.Materials) + { + var item = player.InventoryManager.InventoryData.Items.GetValueOrDefault((uint)mat.Id); + if (item == null || item.ItemCount < mat.Num) + { + await CallGSRouter.SendScript(connection, "Logistics_Upgrade", "{}"); + return; + } + } + + // Consume materials and accumulate exp + var syncItems = new List(); + uint gainedExp = 0; + + foreach (var mat in req.Materials) + { + var item = player.InventoryManager.InventoryData.Items[(uint)mat.Id]; + + // Look up ProvideExp: check SupportCardData first, then SuppliesData + uint provideExp = 0; + var scExcel = GameData.SupportCardData.FirstOrDefault(x => x.TemplateId == item.TemplateId); + if (scExcel != null) + provideExp = scExcel.ProvideExp; + else if (GameData.SuppliesData.TryGetValue((uint)item.TemplateId, out var supExcel)) + provideExp = supExcel.ProvideExp; + gainedExp += provideExp * (uint)mat.Num; + + item.ItemCount -= (uint)mat.Num; + var proto = item.ToProto(); + if (item.ItemCount == 0) + { + player.InventoryManager.InventoryData.Items.Remove(item.UniqueId); + proto.Count = 0; + } + syncItems.Add(proto); + } + + // Apply exp and level up + supportCard.Exp += gainedExp; + while (supportCard.Level < maxLevel) + { + var expNeeded = GetExpNeeded(supportCard.Level + 1); + if (expNeeded == 0 || supportCard.Exp < expNeeded) break; + supportCard.Exp -= expNeeded; + supportCard.Level++; + } + if (supportCard.Level >= maxLevel) + { + supportCard.Exp = 0; + supportCard.Level = maxLevel; + } + + syncItems.Add(supportCard.ToProto()); + + DatabaseHelper.SaveDatabaseType(player.InventoryManager.InventoryData); + + var sync = new NtfSyncPlayer(); + sync.Items.AddRange(syncItems); + + await CallGSRouter.SendScript(connection, "Logistics_Upgrade", "{}", sync); + } + + private static uint GetExpNeeded(uint level) + { + if (GameData.UpgradeExpData.TryGetValue((int)level, out var row)) + return row.SusNeedExp; + return 0; + } +} + +internal sealed class SupporterCardUpgradeParam +{ + [JsonPropertyName("Id")] + public int SupportCardUid { get; set; } + + [JsonPropertyName("tbMaterials")] + public List Materials { get; set; } = []; +} + +internal sealed class UpgradeMaterial +{ + [JsonPropertyName("Id")] + public int Id { get; set; } + + [JsonPropertyName("Num")] + public uint Num { get; set; } +}