Implemented a level-up for SupporterCards.

This commit is contained in:
Kei-Luna
2026-04-28 16:12:02 +09:00
parent 5d0f587fb9
commit ccdfbee828
4 changed files with 142 additions and 4 deletions

View File

@@ -1,3 +1,5 @@
using Newtonsoft.Json;
namespace MikuSB.Data.Excel; namespace MikuSB.Data.Excel;
[ResourceEntity("support_card.json")] [ResourceEntity("support_card.json")]
@@ -8,6 +10,18 @@ public class SupportCardExcel : ExcelResource
public uint Particular { get; set; } public uint Particular { get; set; }
public uint Level { get; set; } public uint Level { get; set; }
public uint Icon { 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; public override uint GetId() => Icon;

View File

@@ -26,24 +26,29 @@ public class BaseGameItemInfo
public uint ItemCount { get; set; } public uint ItemCount { get; set; }
public ItemTypeEnum ItemType { get; set; } public ItemTypeEnum ItemType { get; set; }
public ItemFlagEnum Flag { get; set; } = ItemFlagEnum.FLAG_READED; public ItemFlagEnum Flag { get; set; } = ItemFlagEnum.FLAG_READED;
public uint Level { get; set; }
public uint Exp { get; set; }
public virtual Item ToProto() public virtual Item ToProto()
{ {
return new Item var proto = new Item
{ {
Id = UniqueId, Id = UniqueId,
Template = TemplateId, Template = TemplateId,
Count = ItemCount, Count = ItemCount,
Flag = (uint)Flag Flag = (uint)Flag
}; };
if (Level > 0 || Exp > 0)
proto.Enhance = new Enhance { Level = Level, Exp = Exp };
return proto;
} }
} }
public abstract class GrowableItemInfo : BaseGameItemInfo public abstract class GrowableItemInfo : BaseGameItemInfo
{ {
public bool IsLocked { get; set; } public bool IsLocked { get; set; }
public uint Level { get; set; } public new uint Level { get; set; }
public uint Exp { get; set; } public new uint Exp { get; set; }
public uint Break { get; set; } public uint Break { get; set; }
public uint EquipAvatarId { get; set; } public uint EquipAvatarId { get; set; }
} }

View File

@@ -3,7 +3,7 @@ using MikuSB.Proto;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace MikuSB.GameServer.Server.CallGS.Handlers.Girl; namespace MikuSB.GameServer.Server.CallGS.Handlers.SupporterCard;
[CallGSApi("SupporterCard_Equip")] [CallGSApi("SupporterCard_Equip")]
public class SupporterCard_Equip : ICallGSHandler public class SupporterCard_Equip : ICallGSHandler

View File

@@ -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<SupporterCardUpgradeParam>(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<Item>();
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<UpgradeMaterial> Materials { get; set; } = [];
}
internal sealed class UpgradeMaterial
{
[JsonPropertyName("Id")]
public int Id { get; set; }
[JsonPropertyName("Num")]
public uint Num { get; set; }
}