// ───────────────────────────────────────────────────────────────────────────── // WLWeaponGradeCheat.cs — 🔴 임시 테스트 치트: 숫자 키로 낀 무기 등급 바꾸기 (PD #886 · 2026-10-17 · PD 지시 시 삭제) // // PD 원문: 「이후 스킬은 내가 하나씩 보면서 테스트 할 수 있도록 각 무기 타입별로 배치하고, // 숫자 버튼 입력에 따라 무기 등급을 바꿀 수 있게 치트 기능을 제공해줘.」 // // ■ 동작 — 숫자 키 1~7(키패드 포함 · 등급 표 단계 수까지) = 지금 낀 장비(#894 PD 「숫자 키가 낀 장비 전체 등급을 바꾸게」 = 무기 · 장갑 · 신발 등 모든 칸)를 // 칸마다 같은 그룹의 그 등급(기본 단계) 아이템으로 바꿔 낀다. // 인벤토리에 그 아이템이 있으면 그것을, 없으면 같은 레벨로 1개 지급 → WLInventory.Equip(저장 · 통지) // → 무기 기술 슬롯(WLWeaponSkillSlots) · 파츠 스킬(WLPartSkillState)이 장착 변경으로 다시 붙는다. 화면 위쪽에 결과 한 줄. // ■ 무기 타입별 시험 무기 = WLStarterKit.json grantGroups(무기 기술이 있는 무기 전부 + 창) — 이 파일은 등급만 바꾼다. // ■ 값 = Resources/WL/WLWeaponGradeCheat.json · 끄기 = enabled 0(오브젝트 0) · 완전 삭제 = 이 파일 + json // 🔴 Debug.LogError 금지(원본 ErrorLogHook 이 팝업을 띄운다). // ───────────────────────────────────────────────────────────────────────────── using System.Collections.Generic; using UnityEngine; using WL.Equip; namespace WL.Combat.Weapon { [System.Serializable] public class WLWeaponGradeCheatJson { public int enabled = 0; public float messageSeconds = 2.5f; public float messageFontScale = 0.028f; public float messageTopRatio = 0.12f; public string note = ""; } public static class WLWeaponGradeCheat { public const string ResourcesPath = "WL/WLWeaponGradeCheat"; public static int Applied, Failed; public static string LastLog = ""; internal static string Message = ""; internal static float MessageUntil; static WLWeaponGradeCheatJson s_cfg; static WLWeaponGradeCheatRunner s_runner; internal static WLWeaponGradeCheatJson Cfg { get { if (s_cfg != null) return s_cfg; s_cfg = new WLWeaponGradeCheatJson(); var ta = Resources.Load(ResourcesPath); if (ta == null) { LastLog = "설정 없음 " + ResourcesPath; return s_cfg; } try { JsonUtility.FromJsonOverwrite(ta.text, s_cfg); } catch (System.Exception ex) { LastLog = "설정 파싱 실패 — " + ex.Message; } return s_cfg; } } [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)] static void Boot() { s_cfg = null; if (Cfg.enabled == 0 || !DSUtil.CheckNull(s_runner)) return; // 꺼져 있으면 오브젝트 0 var go = new GameObject("[WL886] WeaponGradeCheat"); go.hideFlags = HideFlags.HideAndDontSave; s_runner = go.AddComponent(); } /// 낀 장비 전체를 칸마다 같은 그룹의 tier 등급(기본 단계) 아이템으로 바꿔 낀다 · 결과 문장을 화면에 띄운다. public static string Apply(int tier) { var r = ApplyInner(tier); LastLog = r; Message = r; MessageUntil = Time.unscaledTime + Cfg.messageSeconds; return r; } public static int LastChanged, LastSame, LastMissing; static string ApplyInner(int tier) { if (!WLInventory.EnsureLoaded()) { Failed++; return "인벤토리 없음"; } var step = WLEquipGrades.BaseStepOfTier(tier); if (step == null) { Failed++; return "등급 " + tier + " 없음(표 " + WLEquipGrades.MaxTier + "단계)"; } // #894 — 먼저 낀 장비를 모아 두고 바꾼다(바꾸는 동안 칸 내용이 바뀐다) var cur = new List(); for (int t = (int)eFREquipmentType.Weapon; t < (int)eFREquipmentType.Max; t++) { var e = WLInventory.EquippedInSlot((eFREquipmentType)t); if (e != null && e.itemJson != null) cur.Add(e); } if (cur.Count == 0) { Failed++; return "낀 장비 없음"; } int changed = 0, same = 0, missing = 0; var fail = new System.Text.StringBuilder(); foreach (var c in cur) { int r = SwapToStep(c, step); if (r == 1) changed++; else if (r == 0) same++; else { missing++; fail.Append(' ').Append(c.itemJson.Item_name).Append(r == -1 ? "(그 등급 없음)" : "(장착 실패)"); } } LastChanged = changed; LastSame = same; LastMissing = missing; if (changed > 0) Applied++; if (missing > 0) Failed++; return "낀 장비 " + cur.Count + "개 → " + WLEquipGrades.TierLabel(tier, false) + " (숫자 " + tier + ") · 바꿈 " + changed + (same > 0 ? " · 이미 " + same : "") + (missing > 0 ? " · 못 바꿈" + fail : ""); } /// 그 장비를 같은 그룹의 step 아이템으로 바꿔 낀다. 1 바꿈 · 0 이미 그 등급 · -1 표에 없음 · -2 장착 실패. static int SwapToStep(Item cur, WLGradeFrMap step) { int g = cur.itemJson.GroupNo; ItemJson found = null; foreach (var j in WLEquipTables.Items) if (j != null && j.IsEquipment && j.GroupNo == g && (int)j.ItemGrade == step.frGrade && j.GradeLv == step.gradeLv) { found = j; break; } if (found == null) return -1; if (found.Index == cur.itemJson.Index) return 0; Item it = null; foreach (var x in WLInventory.SortedItems()) if (x.itemJson.Index == found.Index) { it = x; break; } if (it == null) { var gained = new List(); WLInventory.AddItem(found.Index, Mathf.Max(1, cur.rawItem.level), 1, gained); it = gained.Count > 0 ? gained[gained.Count - 1] : null; } return it != null && WLInventory.Equip(it.rawItem._id) ? 1 : -2; } } /// 숫자 키 읽기 · 결과 한 줄 표시. 숨김 GameObject 1개. internal sealed class WLWeaponGradeCheatRunner : MonoBehaviour { static readonly KeyCode[] s_alpha = { KeyCode.Alpha1, KeyCode.Alpha2, KeyCode.Alpha3, KeyCode.Alpha4, KeyCode.Alpha5, KeyCode.Alpha6, KeyCode.Alpha7, KeyCode.Alpha8, KeyCode.Alpha9 }; static readonly KeyCode[] s_pad = { KeyCode.Keypad1, KeyCode.Keypad2, KeyCode.Keypad3, KeyCode.Keypad4, KeyCode.Keypad5, KeyCode.Keypad6, KeyCode.Keypad7, KeyCode.Keypad8, KeyCode.Keypad9 }; GUIStyle _style; void Update() { if (!Input.anyKeyDown) return; int max = Mathf.Min(s_alpha.Length, WLEquipGrades.MaxTier); for (int i = 0; i < max; i++) if (Input.GetKeyDown(s_alpha[i]) || Input.GetKeyDown(s_pad[i])) { WLWeaponGradeCheat.Apply(i + 1); break; } } void OnGUI() { var msg = WLWeaponGradeCheat.Message; if (string.IsNullOrEmpty(msg) || Time.unscaledTime > WLWeaponGradeCheat.MessageUntil) return; var c = WLWeaponGradeCheat.Cfg; if (_style == null) _style = new GUIStyle(GUI.skin.label) { alignment = TextAnchor.MiddleCenter, fontStyle = FontStyle.Bold }; _style.fontSize = Mathf.Max(14, Mathf.RoundToInt(Screen.height * c.messageFontScale)); var r = new Rect(0f, Screen.height * c.messageTopRatio, Screen.width, _style.fontSize * 2f); var keep = GUI.color; GUI.color = new Color(0f, 0f, 0f, 0.75f); GUI.Label(new Rect(r.x + 2f, r.y + 2f, r.width, r.height), msg, _style); GUI.color = Color.yellow; GUI.Label(r, msg, _style); GUI.color = keep; } } }