// ───────────────────────────────────────────────────────────────────────────── // 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 { /// FR eAbility — 값(순서)이 JSON 의 정수와 일치해야 한다. BT47 이후 항목은 옮기지 않았다(PD 제외). 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 LevelInfos = new List(); 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; } /// ItemOptionTable.json 의 한 행(엑셀 셀 병합 → 첫 행만 Index). [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 Abilities = new List(); public List ConditionalAbilities = new List(); 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 ItemOptions = new List(); 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 ItemDropGroupInfos = new List(); 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 ItemDropPackageInfos = new List(); public ItemDropPackageJson(int index) { Index = index; } } /// 보유 아이템 1건(FR RawItem). `_id` 는 세이브 안 고유 번호. [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; } } /// RawItem + 표 행. public class Item { public RawItem rawItem; public ItemJson itemJson; public Item(RawItem r, ItemJson j) { rawItem = r; itemJson = j; } } /// 세이브 파일 본문(JSON). [Serializable] public class WLEquipSaveData { public int version = 2; public int nextId = 1; public long gold; // 섬(IslandManager)이 없을 때만 쓰는 예비 골드 public List items = new List(); public List equipItems = new List(); // 장착 중인 _id // 장비 상자(PD 2026-10-09) — 열쇠 · 누적 개봉(에픽 확정 주기 기준) · 마지막 S급 뒤 개봉 수(천장 기준) public int keys; public int boxDraws; public int sinceS; } }