Files
EpinelPS/EpinelPS/LobbyServer/Inventory/equipment/LockOption.cs
fxz2018 206fa429ee feat: implement equipment awakening system with interception updates (#57)
- Implement comprehensive equipment awakening system with multiple new endpoints:
  * Awakening.cs: Handle equipment awakening process
  * ChangeOption.cs: Change equipment awakening options
  * GetAwakeningDetail.cs: Get detailed awakening information
  * LockOption.cs: Lock awakening options (with Disposable option)
  * ResetOption.cs: Reset awakening options
  * UpgradeOption.cs: Upgrade awakening options

- Enhance interception system:
  * Simplify GetInterceptData to use fixed normal group ID (1)
  * Update InterceptionHelper to support type 1 in addition to type 0
  * Modify GetInterceptData to use simplified special ID calculation

- Implement new inventory system features:
  * Replace ClearAllEquipment with AllClearEquipment
  * Enhance GetInventoryData to properly handle HarmonyCubes and Awakenings
  * Update WearEquipmentList for improved equipment management

- Update data models and game data:
  * Modify GetConditionReward to handle valueMax == 0 cases
  * Update EquipmentAwakeningData model with proper default values
  * Update ResetableData with DailyCounselCount as dictionary instead of struct field

- Additional improvements:
  * Create GameAssemblyProcessor utility
  * Enhance level infinite controller
  * Update server selector UI
  * Organize protocol message documentation
2025-10-07 21:30:27 -04:00

137 lines
5.0 KiB
C#

using EpinelPS.Database;
using EpinelPS.Utils;
using EpinelPS.Data;
namespace EpinelPS.LobbyServer.Inventory
{
[PacketPath("/inventory/equipment/lockoption")]
public class LockOption : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
ReqAwakeningLockOption req = await ReadData<ReqAwakeningLockOption>();
User user = GetUser();
ResAwakeningLockOption response = new ResAwakeningLockOption();
EquipmentAwakeningData? awakening = user.EquipmentAwakenings.FirstOrDefault(x => x.Isn == req.Isn);
if (awakening == null)
{
await WriteDataAsync(response);
return;
}
int slot = 0;
if (awakening.Option.Option1Id == req.OptionId)
slot = 1;
else if (awakening.Option.Option2Id == req.OptionId)
slot = 2;
else if (awakening.Option.Option3Id == req.OptionId)
slot = 3;
(int materialId, int materialCost) = GetMaterialInfoForAwakening(awakening.Option);
ItemData? material = user.Items.FirstOrDefault(x => x.ItemType == materialId);
if (material == null || material.Count < materialCost)
{
await WriteDataAsync(response);
return;
}
UpdateLockStatus(awakening.Option, slot, req.IsLocked);
if (req.IsLocked)
{
if (!EquipmentUtils.DeductMaterials(material, materialCost, user, response.Items))
{
await WriteDataAsync(response);
return;
}
}
JsonDb.Save();
await WriteDataAsync(response);
}
private static int CalculateMaterialCost(NetEquipmentAwakeningOption option)
{
int lockedOptionCount = 0;
int disposableLockOptionCount = 0;
// Count already permanently locked options (not disposable locks)
if (option.Option1Id != 0 && option.Option1Lock && !option.IsOption1DisposableLock)
lockedOptionCount++;
if (option.Option2Id != 0 && option.Option2Lock && !option.IsOption2DisposableLock)
lockedOptionCount++;
if (option.Option3Id != 0 && option.Option3Lock && !option.IsOption3DisposableLock)
lockedOptionCount++;
if (option.Option1Id != 0 && option.Option1Lock && option.IsOption1DisposableLock)
disposableLockOptionCount++;
if (option.Option2Id != 0 && option.Option2Lock && option.IsOption2DisposableLock)
disposableLockOptionCount++;
if (option.Option3Id != 0 && option.Option3Lock && option.IsOption3DisposableLock)
disposableLockOptionCount++;
return GetPermanentLockCostId(lockedOptionCount,disposableLockOptionCount);
}
private static int GetPermanentLockCostId(int lockedOptionCount,int disposableLockOptionCount)
{
// For permanent locks, use cost_group_id 100
EquipmentOptionCostRecord? costRecord = GameData.Instance.EquipmentOptionCostTable.Values
.FirstOrDefault(x => x.CostGroupId == 100 && x.CostLevel == lockedOptionCount && x.DisposableFixCostLevel == disposableLockOptionCount);
int costId = costRecord?.CostId ?? 101001;
return costId;
}
private static void UpdateLockStatus(NetEquipmentAwakeningOption option, int slot, bool isLocked)
{
switch (slot)
{
case 1:
option.Option1Lock = isLocked;
if (isLocked)
{
option.IsOption1DisposableLock = false;
}
break;
case 2:
option.Option2Lock = isLocked;
if (isLocked)
{
option.IsOption2DisposableLock = false;
}
break;
case 3:
option.Option3Lock = isLocked;
if (isLocked)
{
option.IsOption3DisposableLock = false;
}
break;
}
}
private static (int materialId, int materialCost) GetMaterialInfoForAwakening(NetEquipmentAwakeningOption option)
{
int costId = CalculateMaterialCost(option);
return GetMaterialInfo(costId);
}
private static (int materialId, int materialCost) GetMaterialInfo(int costId)
{
if (GameData.Instance.costTable.TryGetValue(costId, out CostRecord? costRecord) &&
costRecord?.Costs != null &&
costRecord.Costs.Count > 0)
{
return (costRecord.Costs[0].ItemId, costRecord.Costs[0].ItemValue);
}
return (7080001, 2); // Default material ID and cost
}
}
}