// ───────────────────────────────────────────────────────────────────────────── // WLStarterKit.cs — 🔴 임시 테스트 장비 지급 (PD 2026-10-10 · PD 지시 시 삭제) // // PD 원문: 「기본 시작 무기는 검으로 하고, 인벤토리에 테스트 편의를 위해 임시로 각 무기 타입 별로 1개씩 // 가지고 있도록 해줘(추후 내가 지시하면 삭제할 임시 작업)」 // // ■ 동작 — WLWeaponClassApplier.TryApply 가 인벤토리를 읽을 수 있을 때, 세이브 객체가 바뀔 때마다(로드·초기화) 1회: // ① Resources/WL/WLStarterKit.json 의 grantGroups(계열별 기본 무기 그룹 6종)마다 같은 그룹 아이템이 없으면 1개 지급 // (등급 0부터 올라가며 표에 있는 첫 등급 · 있는 계열은 건너뜀 = 중복 0) // 🔴 2026-10-11: WLEquipSettings.resetSaveEveryStart=1 이라 Play 마다 세이브가 비워진다 → 매 Play 다시 보장(전역 1회 표식 폐기) // ② 무기를 아무것도 안 끼고 있으면 equipGroup(검 1435 묵광)을 장착 → 직업 전환기가 검 직업(10101)으로 바꾼다 // ③ #894(2026-10-17) PD 「무기 시너지를 시험할 수 있게 장갑·신발(펜릴 기사단 포함)을 시작 지급」 — synergyPartners 1 이면 // 무기 시너지 조건 장비(파츠 스킬 표 syn_key · req_key)를 1개씩 지급(없는 것만) · 장갑 · 신발 칸이 비어 있으면 표 순서의 첫 것을 장착 // #895 무기 시너지는 무기와 무관(장착 장비 조건만) → 무기 목록이 아니라 무기 시너지 정의 전부에서 조건 장비를 뽑는다 // #920(2026-10-18) PD 「장갑과 부츠 스킬을 변경할 예정이므로 게임 시작 시 장착하지 않은 상태로 시작」 — equipPartners 0 = 지급(인벤토리)만 · 장착 안 함 // ■ 끄기 = WLWeaponSettings.starterKit 0 · 완전 삭제 = 이 파일 + json + 설정 필드 + TryApply 한 줄. // 🔴 Debug.LogError 금지(원본 ErrorLogHook 이 팝업을 띄운다). // ───────────────────────────────────────────────────────────────────────────── using System.Collections.Generic; using UnityEngine; using WL.Equip; namespace WL.Combat.Weapon { [System.Serializable] public class WLStarterKitJson { public int version = 1; public int equipGroup = 1435; public int[] grantGroups = new int[0]; public int synergyPartners = 0; // #894 1 = grantGroups 무기의 시너지 짝 장비(장갑 · 신발) 지급 + 시작 무기의 짝 장착 public int equipPartners = 1; // #920 PD 「장갑과 부츠 스킬을 변경할 예정이므로 게임 시작 시 장착하지 않은 상태로 시작」 — 0 = 짝 장비는 지급만(인벤토리) · 장착 안 함 public string note = ""; } public static class WLStarterKit { public const string ResourcesPath = "WL/WLStarterKit"; public const string PrefsKeyPrefix = "WL_StarterKit_v"; public static int Granted, Equipped, Runs; public static string LastLog = ""; static object s_lastData; // 마지막으로 처리한 세이브 객체 — 세이브가 다시 로드/초기화되면(새 객체) 다시 보장한다 /// 검증용 — 다음 Ensure 가 세이브를 다시 훑게 한다(호환용 · 표식은 더 이상 쓰지 않는다). public static void ResetPrefs() { PlayerPrefs.DeleteKey(PrefsKeyPrefix + "1"); s_lastData = null; } /// /// 🔴 2026-10-11 PD 「테스트 가능하게 종류별로 하나씩 추가해달라고 했잖아」 — 전역 PlayerPrefs 「1회 지급」 표식은 버린다. /// WLEquipSettings.resetSaveEveryStart=1 이라 **Play 마다 인벤토리 세이브가 비워지는데** 표식은 남아 두 번째 Play 부터 지급이 건너뛰어졌다(PD 인벤토리 비어 있음). /// 이제는 세이브가 로드/초기화될 때마다 「계열별 1개가 있는지」를 보장한다(없는 것만 지급 · 중복 0). /// public static void Ensure(WLWeaponSettings cfg) { if (cfg == null || cfg.starterKit == 0) return; if (!WLInventory.EnsureLoaded()) return; if (ReferenceEquals(s_lastData, WLInventory.Data)) return; // 이 세이브 객체는 이미 보장했다 var ta = Resources.Load(ResourcesPath); if (ta == null) { s_lastData = WLInventory.Data; LastLog = "표 없음 " + ResourcesPath; return; } WLStarterKitJson j = null; try { j = JsonUtility.FromJson(ta.text); } catch (System.Exception ex) { LastLog = "표 파싱 실패 — " + ex.Message; } if (j == null) { s_lastData = WLInventory.Data; return; } s_lastData = WLInventory.Data; Runs++; int granted = 0; var sb = new System.Text.StringBuilder(); if (j.grantGroups != null) { for (int i = 0; i < j.grantGroups.Length; i++) { int g = j.grantGroups[i]; if (FindGroup(g) != null) { sb.Append(g).Append("(있음) "); continue; } var json = FirstTableItem(g); if (json == null) { sb.Append(g).Append("(표 없음) "); continue; } WLInventory.AddItem(json.Index, 1, 1); granted++; sb.Append(g).Append('→').Append(json.Item_name).Append(' '); } } // ③ #894 무기 시너지 조건 장비(장갑 · 신발) — #895 무기 시너지는 무기와 무관(장착 장비 조건만) → 모든 무기 시너지의 조건 장비를 1개씩 int partners = 0; var partnerGroups = j.synergyPartners != 0 ? PartnerGroups() : new List(); if (j.synergyPartners != 0) foreach (int pg in partnerGroups) { if (FindGroup(pg) != null) { sb.Append("짝 ").Append(pg).Append("(있음) "); continue; } var json = FirstTableItem(pg); if (json == null) { sb.Append("짝 ").Append(pg).Append("(표 없음) "); continue; } WLInventory.AddItem(json.Index, 1, 1); partners++; sb.Append("짝 ").Append(pg).Append('→').Append(json.Item_name).Append(' '); } int equipped = 0; if (WLInventory.EquippedInSlot(eFREquipmentType.Weapon) == null) { var it = FindGroup(j.equipGroup); if (it != null && WLInventory.Equip(it.rawItem._id)) { equipped = 1; sb.Append("· 검 장착 ").Append(it.itemJson.Item_name); } else sb.Append("· 검 그룹 ").Append(j.equipGroup).Append(" 없음 "); } // 조건 장비는 그 칸(장갑 · 신발)이 비어 있으면 표 순서의 첫 것을 낀다(#895 = 펜릴 기사단 신발 · 장갑 → 숫자 5 한 번으로 검기 발사체 · 원한의 맹독) int partnerEquipped = 0; if (j.synergyPartners != 0 && j.equipPartners != 0) foreach (int pg in partnerGroups) { var p = FindGroup(pg); if (p == null || p.itemJson == null || WLInventory.EquippedInSlot(p.itemJson.EquipmentType) != null) continue; if (WLInventory.Equip(p.rawItem._id)) { partnerEquipped++; sb.Append("· 짝 장착 ").Append(p.itemJson.Item_name).Append(' '); } } if (granted > 0 || partners > 0 || equipped > 0 || partnerEquipped > 0) WLInventory.Commit("WL 임시 시작 장비 — " + granted + "종 지급" + (partners > 0 ? " · 시너지 짝 " + partners + "종" : "") + (equipped > 0 ? " · 검 장착" : "") + (partnerEquipped > 0 ? " · 짝 장착" : "")); Granted = granted; Equipped = equipped; PartnersGranted = partners; PartnersEquipped = partnerEquipped; LastLog = "지급 " + granted + "종 · 짝 " + partners + "종" + (equipped > 0 ? " · 검 장착" : "") + (partnerEquipped > 0 ? " · 짝 장착 " + partnerEquipped : "") + " · " + sb; if (cfg.verboseLog != 0 && (granted > 0 || partners > 0 || equipped > 0 || partnerEquipped > 0)) Debug.Log("[WL-833] 임시 시작 장비: " + LastLog); } public static int PartnersGranted, PartnersEquipped; /// 그 그룹의 표 아이템 중 가장 낮은 등급 하나(등급 0부터 · 기본 단계). static ItemJson FirstTableItem(int group) { ItemJson json = null; for (int gr = 0; gr < 7 && json == null; gr++) { try { json = WLEquipTables.FindGroupItem(group, (eFRItemGrade)gr, 0); } catch (System.Exception) { json = null; } } return json; } /// /// #894 · #895 — 모든 무기 시너지의 조건 장비 그룹(중복 없음 · 파츠 스킬 표 순서). 무기 시너지 정의 → syn_key [+ req_key] → 그 스킬을 주는 장비 그룹 중 표에 있는 첫 그룹. /// 값은 전부 파츠 스킬 표(WLPartSkillDefs.csv · 그룹 연결) — 이 파일에 아이템 번호 0개(C45). /// public static List PartnerGroups() { var result = new List(); if (!WL.PartSkill.WLPartSkillData.Enabled) return result; foreach (var d in WL.PartSkill.WLPartSkillData.Defs) { if (d == null || d.kind != WL.PartSkill.WLPartKind.WeaponSyn) continue; AddFirstGroup(result, d.synKey); AddFirstGroup(result, d.reqKey); } return result; } static void AddFirstGroup(List result, string key) { if (string.IsNullOrEmpty(key)) return; foreach (int pg in WL.PartSkill.WLPartSkillData.GroupsOf(key)) { if (FirstTableItem(pg) == null) continue; if (!result.Contains(pg)) result.Add(pg); return; } } static Item FindGroup(int group) { var items = WLInventory.SortedItems(); if (items == null) return null; for (int i = 0; i < items.Count; i++) { var it = items[i]; if (it != null && it.itemJson != null && it.itemJson.GroupNo == group) return it; } return null; } } }