Project_WL/Assets/WL/Equip/WLEquipData.cs

268 lines
10 KiB
C#

// ─────────────────────────────────────────────────────────────────────────────
// WLEquipData.cs — FR(FirstRising) 기존 장비 시스템의 데이터 모델 이식 (#821 · 2026-10-08)
//
// 원본 = FR `Assets/Scripts/GameHub/JsonCommon.cs` (ItemJson · ItemLevelJson · ItemComposeJson ·
// ItemOptionJson · ItemDropGroup/Package · RawItem) 를 **필드 이름 그대로** 옮겼다 — FR 의 JSON
// 테이블(`Resources/WL/FR/*.json`)을 수정 없이 Newtonsoft 로 읽기 위해서다.
//
// PD 지시: 탕탕특공대식 — 본 아이템 1 + 같은 등급 재료 2(표 RequiredItemCount) → 등급 업 ·
// 등급마다 옵션 개방(ItemOptionTable) · 강화석+골드로 레벨업(Item_*.json) · 강등.
// 능력치 본체는 힘민지(ActorStatInfo) 그대로 쓰고, FR eAbility 는 WLEquipSettings.abilityMap 으로 대응한다.
// ─────────────────────────────────────────────────────────────────────────────
using System;
using System.Collections.Generic;
namespace WL.Equip
{
/// <summary>FR eAbility — 값(순서)이 JSON 의 정수와 일치해야 한다. BT47 이후 항목은 옮기지 않았다(PD 제외).</summary>
public enum eFRAbility
{
None,
ItemRange, // 1 아이템 획득 범위 %
Health, // 2 체력 %
RecoveryHealth, // 3 초당 체력 회복 %
Speed, // 4 이동 속도 %
Defence, // 5 모든 피해 감소 %
Attack, // 6 공격력 %
IncreaseDrop, // 7 경험치·골드·드랍율 %
Rolling, // 8 구르기
ProjectileSpeed, // 9 투사체 속도 %
SkillRange, // 10 스킬 범위 %
SkillDuration, // 11 스킬 지속 %
Cooltime, // 12 쿨타임 감소 %
AttackDefence, // 13 공격력+방어력 %
Passive, // 14 패시브 효과 %
Critical, // 15 치명타 확률 %
CriticalDamage, // 16 치명타 피해 %
Revive, // 17 부활 횟수
HeartRecover, // 18 하트 회복 %
SpeedValue, // 19 이동 속도 값
Excellent, // 20 액설런트 확률
ExcellentDamage, // 21 액설런트 피해
Max,
}
public enum eFRItemGrade { None = -1, Normal, Magic, Rare, Elite, Epic, Legend, Max }
public enum eFREquipmentType { None = 0, Weapon, Necklace, Glove, Armor, Belt, Shose, Max }
public enum eFRItemType { None = 0, Equipment, Buff, LevelUpScroll, EnchantScroll, Goods, Normal, RewardPoint, Max }
public enum eFRDropType { All = 0, Random = 1, Max }
[Serializable]
public class ItemJson
{
public int Index;
public string Item_name;
public string Desc;
public byte IsEquip;
public byte IsStack;
public int ItemCategory;
public eFRItemType ItemType;
public int WeaponType;
public eFREquipmentType EquipmentType;
public eFRItemGrade ItemGrade;
public int ItemClass;
public int ItemDropGroup_ID;
public int GradeLv;
public int GroupNo;
public int ItemMaxLv;
public int ItemLvAbilityID;
public int SkillIndex;
public int CostumeIndex;
// FR 의 `Equipments`(프리팹 이름)는 FR 전용이라 읽지 않는다.
public bool IsEquipment { get { return IsEquip == 1 && ItemType == eFRItemType.Equipment; } }
}
[Serializable]
public class ItemLevelInfo
{
public int Index;
public eFRItemGrade Grade;
public int GradeLv;
public int Level;
public int AttackAbility;
public int DefenceAbility;
public int HealthAbility;
public int ItemKeyRequired;
public int ItemCountRequired;
public int MoneyKeyRequired;
public int MoneyCountRequired;
}
[Serializable]
public class ItemLevelJson
{
public int Index;
public List<ItemLevelInfo> LevelInfos = new List<ItemLevelInfo>();
public ItemLevelJson(int index) { Index = index; }
public ItemLevelInfo FindLevelInfo(int level) { return LevelInfos.Find(i => i.Level == level); }
}
[Serializable]
public class ItemComposeJson
{
public int Index;
public int SameGroupNo;
public eFRItemGrade ItemGrade;
public eFRItemGrade ResultGrade;
public int RequiredGradeLevel;
public int ResultGradeLevel;
public int RequiredItemCount;
}
/// <summary>ItemOptionTable.json 의 한 행(엑셀 셀 병합 → 첫 행만 Index).</summary>
[Serializable]
public class ItemOptionReader
{
public int Index;
public string Desc;
public eFRItemGrade ItemGrade;
public string Ability;
public string AbilityValue;
public string ConditionalAbility;
public string ConditionValue0;
public string ConditionValue1;
public string ConditionValue2;
}
[Serializable]
public class ItemOptionAbility
{
public eFRAbility Ability;
public int AbilityValue;
public ItemOptionAbility(eFRAbility a, int v) { Ability = a; AbilityValue = v; }
}
[Serializable]
public class ConditionalItemOptionAbility
{
public int Ability; // FR eConditionalItemOptionAbility — WL 에서는 「미적용」(표시만)
public int ConditionValue0, ConditionValue1, ConditionValue2;
}
[Serializable]
public class ItemOptionElement
{
public eFRItemGrade ItemGrade;
public List<ItemOptionAbility> Abilities = new List<ItemOptionAbility>();
public List<ConditionalItemOptionAbility> ConditionalAbilities = new List<ConditionalItemOptionAbility>();
public ItemOptionElement(ItemOptionReader r)
{
ItemGrade = r.ItemGrade;
if (!string.IsNullOrEmpty(r.Ability))
{
var a = r.Ability.Split('\n');
var v = (r.AbilityValue ?? "").Split('\n');
for (int i = 0; i < a.Length; i++)
{
int ai, vi;
if (!int.TryParse(a[i].Trim(), out ai)) continue;
vi = i < v.Length && int.TryParse(v[i].Trim(), out vi) ? vi : 0;
Abilities.Add(new ItemOptionAbility((eFRAbility)ai, vi));
}
}
if (!string.IsNullOrEmpty(r.ConditionalAbility))
{
var a = r.ConditionalAbility.Split('\n');
var c0 = string.IsNullOrEmpty(r.ConditionValue0) ? null : r.ConditionValue0.Split('\n');
var c1 = string.IsNullOrEmpty(r.ConditionValue1) ? null : r.ConditionValue1.Split('\n');
var c2 = string.IsNullOrEmpty(r.ConditionValue2) ? null : r.ConditionValue2.Split('\n');
for (int i = 0; i < a.Length; i++)
{
var ca = new ConditionalItemOptionAbility();
int t;
if (int.TryParse(a[i].Trim(), out t)) ca.Ability = t;
if (c0 != null && i < c0.Length && int.TryParse(c0[i].Trim(), out t)) ca.ConditionValue0 = t;
if (c1 != null && i < c1.Length && int.TryParse(c1[i].Trim(), out t)) ca.ConditionValue1 = t;
if (c2 != null && i < c2.Length && int.TryParse(c2[i].Trim(), out t)) ca.ConditionValue2 = t;
ConditionalAbilities.Add(ca);
}
}
}
}
[Serializable]
public class ItemOptionJson
{
public int Index; // = ItemJson.GroupNo
public string Desc;
public List<ItemOptionElement> ItemOptions = new List<ItemOptionElement>();
public ItemOptionJson(int index, string desc) { Index = index; Desc = desc; }
}
[Serializable]
public class ItemDropGroupInfo
{
public int Index;
public string Name;
public eFRDropType DropType;
public int Rate; // 10000 분율
public int Package_ID;
}
[Serializable]
public class ItemDropGroupJson
{
public int Index;
public List<ItemDropGroupInfo> ItemDropGroupInfos = new List<ItemDropGroupInfo>();
public ItemDropGroupJson(int index) { Index = index; }
}
[Serializable]
public class ItemDropPackageInfo
{
public int Index;
public string Name;
public int Item_ID;
public int MinCount;
public int MaxCount;
public int Rate;
}
[Serializable]
public class ItemDropPackageJson
{
public int Index;
public int TotalRate;
public List<ItemDropPackageInfo> ItemDropPackageInfos = new List<ItemDropPackageInfo>();
public ItemDropPackageJson(int index) { Index = index; }
}
/// <summary>보유 아이템 1건(FR RawItem). `_id` 는 세이브 안 고유 번호.</summary>
[Serializable]
public class RawItem
{
public int index;
public int level;
public int count;
public int _id;
public RawItem() { }
public RawItem(int index, int level, int count, int id) { this.index = index; this.level = level; this.count = count; _id = id; }
}
/// <summary>RawItem + 표 행.</summary>
public class Item
{
public RawItem rawItem;
public ItemJson itemJson;
public Item(RawItem r, ItemJson j) { rawItem = r; itemJson = j; }
}
/// <summary>세이브 파일 본문(JSON).</summary>
[Serializable]
public class WLEquipSaveData
{
public int version = 2;
public int nextId = 1;
public long gold; // 섬(IslandManager)이 없을 때만 쓰는 예비 골드
public List<RawItem> items = new List<RawItem>();
public List<int> equipItems = new List<int>(); // 장착 중인 _id
// 장비 상자(PD 2026-10-09) — 열쇠 · 누적 개봉(에픽 확정 주기 기준) · 마지막 S급 뒤 개봉 수(천장 기준)
public int keys;
public int boxDraws;
public int sinceS;
}
}