305 lines
19 KiB
C#
305 lines
19 KiB
C#
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|||
|
|
// WLSkillTestHarness.cs — 독립 스킬 테스트 씬(WLSkillTest) · 캐릭터 + 스킬 시스템만 따로 세운 하네스 (PD #947 재지시 · 2026-10-20)
|
|||
|
|
//
|
|||
|
|
// PD 원문: 「이 프로젝트를 기반으로 만들라는 의미가 아니라, 스킬 애니메이션 및 연출을 위해 캐릭터 및 스킬 시스템만 별도로 구축해서
|
|||
|
|
// 테스트 목적으로 쓸 씬을 구축해달라는 뜻」
|
|||
|
|
//
|
|||
|
|
// ■ 방식 = 원본 개발자의 StatTest 하네스(MainToStatTest)와 같은 줄기: **로그인 0 · HUD(NewGameUI) 0 · 섬·로비 0 · Addressables 부트 0**.
|
|||
|
|
// 씬에 직접 둔 것만으로 돈다 — 테이블 프리팹 · ActorInfo · InGameInfo(이펙트·투사체 풀) · ProjectileInfo · 원본 Main Camera · 치비 PC 프리팹 · 더미 몹 프리팹 · 평지.
|
|||
|
|
// 순서: 평지 NavMesh 베이크 → 테이블 로딩 대기 → 오프라인 ServerData(신규 유저 꼴 · 자동 전투 1) → PC.Set(직업 = 낀 WL 무기) → 더미 Set(무적 · 제자리) → 카메라 리그 → ready.
|
|||
|
|
// ■ 원본 코드와의 접점 = StatTest 전용 분기 13곳을 `WLTestScene.Active`(StatTest 또는 WLSkillTest)로 넓힌 것뿐(HUD·포털·서버 일시정지·대상 목록 분기 · 전부 #if UNITY_EDITOR 안).
|
|||
|
|
// 이동·넉백·소환 AI 분기(Actor 1665·1710·2198 · MobActor 75 · SummonActor 60 · WizardActor 53·61)는 StatTest 전용으로 남겨 **실제 게임 동작**을 유지한다.
|
|||
|
|
// ■ 이 클래스가 MainToStatTest 를 상속하는 이유 = 원본 분기가 `MainToStatTest.Ins.actors[1]`(대상)·`Set_Dmglabel`(피해 글자)를 부른다 → 같은 자리를 채워 준다.
|
|||
|
|
// ■ 키: WASD/방향키 이동 · Space 기본 공격 1타 · Q 주력 · E 각성 · 숫자 등급(기존 훅) · [ ] 무기 바꾸기 · R 더미 제자리 · T 슬로 모션 · P 일시정지
|
|||
|
|
// ■ 값 = Resources/WL/WLSkillTest.json (C45) · 상태 파일 = Library/WLSkillTest_status.txt(외부 스크립트는 Play 중 eval 대신 이 파일) · 🔴 Debug.LogError 금지(원본 ErrorLogHook 팝업)
|
|||
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|||
|
|
using System.Collections;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using Unity.AI.Navigation;
|
|||
|
|
using UnityEngine;
|
|||
|
|
using UnityEngine.SceneManagement;
|
|||
|
|
using WL.Combat.Weapon;
|
|||
|
|
using WL.Equip;
|
|||
|
|
using WL.Island;
|
|||
|
|
using WL.IslandMob;
|
|||
|
|
|
|||
|
|
namespace WL.SkillTest
|
|||
|
|
{
|
|||
|
|
/// <summary>원본 코드의 StatTest 전용 분기가 이 씬에서도 서도록 넓힌 판정(에디터 전용 분기 안에서만 쓰인다).</summary>
|
|||
|
|
public static class WLTestScene
|
|||
|
|
{
|
|||
|
|
public const string Name = "WLSkillTest";
|
|||
|
|
public static bool Active { get { var n = SceneManager.GetActiveScene().name; return n == Name || n == "StatTest"; } }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[System.Serializable]
|
|||
|
|
public class WLSkillTestJson
|
|||
|
|
{
|
|||
|
|
public string note = "";
|
|||
|
|
public int baseClassId = 10101; // 낀 WL 무기가 없을 때 PC 직업(묵광 검+방패)
|
|||
|
|
public int autoBattle = 1; // 1 = 섬처럼 자동 전투(대상 있으면 기본 공격 콤보)
|
|||
|
|
public float[] spawnPos = { 0f, 0f, 0f };
|
|||
|
|
public int cameraRig = 1; // 1 = 섬 구도 카메라 리그(WLDungeonCameraRig)
|
|||
|
|
public int dummyMobId = 0; // 0 = WLIslandMobSettings.hitTestDummyMobId (몬스터 표 행 · 능력치)
|
|||
|
|
public float[] dummyOffset = { 0f, 0f, 0f }; // 전부 0 = WLIslandMobSettings.hitTestDummyOffset
|
|||
|
|
public int dummyStill = 1; // 1 = 더미 제자리
|
|||
|
|
public int moveKeys = 1;
|
|||
|
|
public string attackKey = "Space";
|
|||
|
|
public string weaponPrevKey = "LeftBracket";
|
|||
|
|
public string weaponNextKey = "RightBracket";
|
|||
|
|
public string dummyResetKey = "R";
|
|||
|
|
public string slowKey = "T";
|
|||
|
|
public float slowScale = 0.2f;
|
|||
|
|
public string pauseKey = "P";
|
|||
|
|
public int label = 1;
|
|||
|
|
public float labelFontScale = 0.018f;
|
|||
|
|
public float groundSize = 100f;
|
|||
|
|
public float[] groundColor = { 0.45f, 0.62f, 0.35f };
|
|||
|
|
public float[] skyColor = { 0.55f, 0.75f, 0.95f };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public sealed class WLSkillTestHarness : MainToStatTest
|
|||
|
|
{
|
|||
|
|
public const string ResourcesPath = "WL/WLSkillTest";
|
|||
|
|
|
|||
|
|
[Header("씬 빌더가 채운다")]
|
|||
|
|
public Actor pcActor; // 치비 PC 프리팹 인스턴스(씬에 직접)
|
|||
|
|
public MobActor dummyActor; // 더미 몹 프리팹 인스턴스(씬에 직접)
|
|||
|
|
|
|||
|
|
public static string Stage = "none", LastLog = "";
|
|||
|
|
public static bool Ready;
|
|||
|
|
public static Actor Dummy;
|
|||
|
|
public static readonly List<string> Laps = new List<string>();
|
|||
|
|
public static readonly List<string> Hangs = new List<string>();
|
|||
|
|
public static float T0;
|
|||
|
|
|
|||
|
|
static WLSkillTestJson s_cfg;
|
|||
|
|
float _lastRt;
|
|||
|
|
bool _moving, _slow;
|
|||
|
|
KeyCode _kAttack = KeyCode.Space, _kPrev = KeyCode.LeftBracket, _kNext = KeyCode.RightBracket, _kReset = KeyCode.R, _kSlow = KeyCode.T, _kPause = KeyCode.P;
|
|||
|
|
string _msg = "";
|
|||
|
|
GUIStyle _style;
|
|||
|
|
|
|||
|
|
public static WLSkillTestJson Cfg
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
if (s_cfg != null) return s_cfg;
|
|||
|
|
s_cfg = new WLSkillTestJson();
|
|||
|
|
var ta = Resources.Load<TextAsset>(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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static string StatusPath { get { return System.IO.Path.GetFullPath(System.IO.Path.Combine(Application.dataPath, "../Library/WLSkillTest_status.txt")); } }
|
|||
|
|
static Vector3 V3(float[] a) { return a != null && a.Length >= 3 ? new Vector3(a[0], a[1], a[2]) : Vector3.zero; }
|
|||
|
|
static KeyCode Key(string s, KeyCode d) { KeyCode k; return !string.IsNullOrEmpty(s) && System.Enum.TryParse(s, true, out k) ? k : d; }
|
|||
|
|
static void WriteStatus() { try { System.IO.File.WriteAllText(StatusPath, Describe()); } catch { } }
|
|||
|
|
static void Lap(string name) { Stage = name; Laps.Add(name + " " + (Time.realtimeSinceStartup - T0).ToString("F1") + "s"); WriteStatus(); }
|
|||
|
|
|
|||
|
|
// MainToStatTest.Awake 는 go_tables 를 복제한다 — 여기선 테이블이 씬에 직접 있으므로 싱글턴 자리만 잡는다
|
|||
|
|
protected override void Awake()
|
|||
|
|
{
|
|||
|
|
Ins = this; isIns = true;
|
|||
|
|
T0 = Time.realtimeSinceStartup;
|
|||
|
|
Laps.Clear(); Hangs.Clear(); Ready = false; Dummy = null; s_cfg = null; LastLog = "";
|
|||
|
|
var cfg = Cfg;
|
|||
|
|
_kAttack = Key(cfg.attackKey, KeyCode.Space); _kPrev = Key(cfg.weaponPrevKey, KeyCode.LeftBracket); _kNext = Key(cfg.weaponNextKey, KeyCode.RightBracket);
|
|||
|
|
_kReset = Key(cfg.dummyResetKey, KeyCode.R); _kSlow = Key(cfg.slowKey, KeyCode.T); _kPause = Key(cfg.pauseKey, KeyCode.P);
|
|||
|
|
if (actors == null || actors.Length < 2) actors = new Actor[] { pcActor, dummyActor };
|
|||
|
|
Lap("awake");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
IEnumerator Start()
|
|||
|
|
{
|
|||
|
|
var cfg = Cfg;
|
|||
|
|
BakeGround(); ApplySky(cfg);
|
|||
|
|
Lap("navmesh");
|
|||
|
|
|
|||
|
|
while (TableChecker.Ins == null || !TableChecker.Ins.CheckAllLoad()) yield return null;
|
|||
|
|
Lap("tables");
|
|||
|
|
|
|||
|
|
if (pcActor == null || dummyActor == null) { Stage = "refs-missing"; LastLog = "pcActor/dummyActor 참조 없음 — Build Scene 다시"; WriteStatus(); yield break; }
|
|||
|
|
|
|||
|
|
// 오프라인 서버 데이터(신규 유저 꼴 · 테이블 로딩 뒤에만 생성 가능) + 자동 전투
|
|||
|
|
var sdata = new ServerData();
|
|||
|
|
try { if (cfg.autoBattle != 0) sdata.Add_Common(eCommon.Auto, 1); } catch (System.Exception ex) { LastLog = "Auto 설정 실패 " + ex.Message; }
|
|||
|
|
|
|||
|
|
// PC — 직업 = 낀 WL 무기(없으면 baseClassId). 원본 Set 안에서 WL 무기 적용기·스타터 킷이 돈다(섬과 같은 경로)
|
|||
|
|
int cls = ResolveClass(cfg);
|
|||
|
|
pcActor.transform.position = NavPos(V3(cfg.spawnPos));
|
|||
|
|
pcActor.Set(false, null, sdata, cls, true);
|
|||
|
|
ActorInfo.Ins.Add_Actor(pcActor, eRole.PC, 0, pcActor.name);
|
|||
|
|
Lap("pc " + cls);
|
|||
|
|
|
|||
|
|
// 더미 — 몬스터 표 행으로 능력치 · 무적(WLTrailTest 체력 되채움) · 제자리
|
|||
|
|
var ms = WLIslandMobSettings.Instance;
|
|||
|
|
int mobId = cfg.dummyMobId > 0 ? cfg.dummyMobId : (ms != null ? ms.hitTestDummyMobId : 101);
|
|||
|
|
var data = table_monsterlist.Ins.Get_Data_orNull(mobId);
|
|||
|
|
if (data == null) { Stage = "mob-row-none"; LastLog = "몬스터 표 없음 " + mobId; WriteStatus(); yield break; }
|
|||
|
|
ActorInfo.Ins.Add_Actor(dummyActor, eRole.Mob, 1, dummyActor.name);
|
|||
|
|
dummyActor.Set(true, null, null, 1, false);
|
|||
|
|
dummyActor.Set(data, DummyPos(cfg, ms), null, 0);
|
|||
|
|
if (cfg.dummyStill != 0) dummyActor.Stop(true);
|
|||
|
|
WLTrailTest.Adopt(dummyActor); Dummy = dummyActor;
|
|||
|
|
if (dummyActor.GetComponent<WLTrailTestDummy>() == null) dummyActor.gameObject.AddComponent<WLTrailTestDummy>().Begin(dummyActor);
|
|||
|
|
Lap("dummy " + mobId);
|
|||
|
|
|
|||
|
|
// 카메라 — 섬 구도 리그 + 원본 RealCamera 대상
|
|||
|
|
var icfg = WLIslandSettings.Instance;
|
|||
|
|
if (icfg != null && cfg.cameraRig != 0 && Object.FindFirstObjectByType<WLDungeonCameraRig>() == null) WLDungeonCameraRig.Create(icfg, gameObject.scene);
|
|||
|
|
var rc = MyValue.m_RealCamera;
|
|||
|
|
if (rc != null) rc.Set_Target(pcActor.transform, icfg != null ? WLDungeonCameraRig.SolvedYaw(icfg) : 0f);
|
|||
|
|
yield return null;
|
|||
|
|
|
|||
|
|
pcActor.Stop(false);
|
|||
|
|
pcActor.Change_Target(false, dummyActor);
|
|||
|
|
Ready = true;
|
|||
|
|
Lap("ready");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void OnDestroy() { try { if (System.IO.File.Exists(StatusPath)) System.IO.File.Delete(StatusPath); } catch { } Time.timeScale = 1f; }
|
|||
|
|
|
|||
|
|
// ─────────────────────────────────────────────────────────────────
|
|||
|
|
static int ResolveClass(WLSkillTestJson cfg)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (WLInventory.EnsureLoaded())
|
|||
|
|
{
|
|||
|
|
var w = WLInventory.EquippedInSlot(eFREquipmentType.Weapon);
|
|||
|
|
if (w != null && w.itemJson != null) { int c = WLWeaponAttackTable.ClassIdFor(w.itemJson.GroupNo); if (c > 0) return c; }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (System.Exception ex) { LastLog = "직업 판정 실패 " + ex.Message; }
|
|||
|
|
return cfg.baseClassId > 0 ? cfg.baseClassId : 10101;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static Vector3 NavPos(Vector3 want)
|
|||
|
|
{
|
|||
|
|
UnityEngine.AI.NavMeshHit hit;
|
|||
|
|
return UnityEngine.AI.NavMesh.SamplePosition(want, out hit, 5f, UnityEngine.AI.NavMesh.AllAreas) ? hit.position : want;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static Vector3 DummyPos(WLSkillTestJson cfg, WLIslandMobSettings ms)
|
|||
|
|
{
|
|||
|
|
Vector3 off = V3(cfg.dummyOffset); if (off == Vector3.zero && ms != null) off = ms.hitTestDummyOffset;
|
|||
|
|
var pc = MyValue.MyPC;
|
|||
|
|
Vector3 basePos = pc != null ? pc.Get_position() : V3(cfg.spawnPos);
|
|||
|
|
Quaternion rot = pc != null ? Quaternion.Euler(0f, pc.transform.eulerAngles.y, 0f) : Quaternion.identity;
|
|||
|
|
return NavPos(basePos + rot * off);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static void ApplySky(WLSkillTestJson cfg)
|
|||
|
|
{
|
|||
|
|
var cam = Camera.main;
|
|||
|
|
if (cam == null || cfg.skyColor == null || cfg.skyColor.Length < 3) return;
|
|||
|
|
if (RenderSettings.skybox == null) { cam.clearFlags = CameraClearFlags.SolidColor; cam.backgroundColor = new Color(cfg.skyColor[0], cfg.skyColor[1], cfg.skyColor[2]); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void BakeGround()
|
|||
|
|
{
|
|||
|
|
var surf = Object.FindFirstObjectByType<NavMeshSurface>();
|
|||
|
|
if (surf == null) { var ground = GameObject.Find("Ground"); if (ground == null) return; surf = ground.AddComponent<NavMeshSurface>(); }
|
|||
|
|
surf.useGeometry = UnityEngine.AI.NavMeshCollectGeometry.PhysicsColliders;
|
|||
|
|
surf.BuildNavMesh();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>더미를 PC 앞 기본 자리로(R 키 · 프로브).</summary>
|
|||
|
|
public static string ResetDummy()
|
|||
|
|
{
|
|||
|
|
var d = Dummy; if (d == null || MyValue.MyPC == null) return "PC/더미 없음";
|
|||
|
|
var pos = DummyPos(Cfg, WLIslandMobSettings.Instance);
|
|||
|
|
d.Stop(true); d.Set_Warp(pos);
|
|||
|
|
return "더미 " + pos.ToString("F1");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>낀 무기를 인벤토리 무기 목록에서 앞뒤로(dir ±1).</summary>
|
|||
|
|
public static string CycleWeapon(int dir)
|
|||
|
|
{
|
|||
|
|
if (!WLInventory.EnsureLoaded()) return "인벤토리 미로드";
|
|||
|
|
var cur = WLInventory.EquippedInSlot(eFREquipmentType.Weapon);
|
|||
|
|
var ids = new List<int>(); var names = new List<string>(); int curIdx = -1;
|
|||
|
|
foreach (var it in WLInventory.SortedItems())
|
|||
|
|
{
|
|||
|
|
if (it == null || it.itemJson == null || !it.itemJson.IsEquipment || it.itemJson.EquipmentType != eFREquipmentType.Weapon) continue;
|
|||
|
|
if (cur != null && ReferenceEquals(it, cur)) curIdx = ids.Count;
|
|||
|
|
ids.Add(it.rawItem._id); names.Add(it.itemJson.Item_name + "(" + it.itemJson.GroupNo + ")");
|
|||
|
|
}
|
|||
|
|
if (ids.Count == 0) return "무기 없음";
|
|||
|
|
int next = curIdx < 0 ? 0 : (curIdx + dir + ids.Count) % ids.Count;
|
|||
|
|
bool ok = WLInventory.Equip(ids[next]);
|
|||
|
|
return (ok ? "장착 " : "실패 ") + names[next] + " " + (next + 1) + "/" + ids.Count + (ok ? "" : " · " + WLInventory.LastMessage);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static string Describe()
|
|||
|
|
{
|
|||
|
|
var pc = MyValue.MyPC; string w = "-";
|
|||
|
|
if (WLInventory.Loaded) { var cur = WLInventory.EquippedInSlot(eFREquipmentType.Weapon); if (cur != null && cur.itemJson != null) w = cur.itemJson.Item_name + "(" + cur.itemJson.GroupNo + ")"; }
|
|||
|
|
return "stage=" + Stage + " ready=" + Ready + " pc=" + (pc != null ? pc.name + pc.Get_position().ToString("F1") : "-") + " weapon=" + w +
|
|||
|
|
" dummy=" + (Dummy != null ? Dummy.name + Dummy.Get_position().ToString("F1") + " hp " + Dummy.Get_HP().ToString("F0") : "-") +
|
|||
|
|
" laps=[" + string.Join(" · ", Laps.ToArray()) + "] hangs=[" + string.Join(" ", Hangs.ToArray()) + "] " + LastLog;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ─────────────────────────────────────────────────────────────────
|
|||
|
|
void LateUpdate()
|
|||
|
|
{
|
|||
|
|
float now = Time.realtimeSinceStartup;
|
|||
|
|
if (_lastRt > 0f && now - _lastRt > 0.5f && Hangs.Count < 40) Hangs.Add((now - T0).ToString("F1") + "@" + (now - _lastRt).ToString("F1") + "s");
|
|||
|
|
_lastRt = now;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void Update()
|
|||
|
|
{
|
|||
|
|
if (!Ready) return;
|
|||
|
|
var pc = MyValue.MyPC as PCActor;
|
|||
|
|
if (pc == null) return;
|
|||
|
|
var cfg = Cfg;
|
|||
|
|
|
|||
|
|
if (cfg.moveKeys != 0)
|
|||
|
|
{
|
|||
|
|
float h = (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow) ? 1f : 0f) - (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow) ? 1f : 0f);
|
|||
|
|
float v = (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow) ? 1f : 0f) - (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow) ? 1f : 0f);
|
|||
|
|
if (h != 0f || v != 0f)
|
|||
|
|
{
|
|||
|
|
if (!_moving) { pc.Set_AutoBraking(false); pc.Set_JoystickStatus(1); _moving = true; }
|
|||
|
|
var cam = Camera.main;
|
|||
|
|
Vector3 fwd = cam != null ? Vector3.ProjectOnPlane(cam.transform.forward, Vector3.up) : Vector3.forward;
|
|||
|
|
if (fwd.sqrMagnitude < 1e-4f) fwd = Vector3.forward;
|
|||
|
|
fwd.Normalize();
|
|||
|
|
pc.Run_byJoystick((fwd * v + Vector3.Cross(Vector3.up, fwd) * h).normalized);
|
|||
|
|
}
|
|||
|
|
else if (_moving) { pc.Set_JoystickStatus(0); pc.Set_AutoBraking(true); _moving = false; }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (Input.GetKeyDown(_kAttack)) { if (Dummy != null) pc.Change_Target(false, Dummy); pc.Play_Attack(0, 1f); _msg = "기본 공격"; }
|
|||
|
|
if (Input.GetKeyDown(_kPrev)) _msg = CycleWeapon(-1);
|
|||
|
|
if (Input.GetKeyDown(_kNext)) _msg = CycleWeapon(+1);
|
|||
|
|
if (Input.GetKeyDown(_kReset)) _msg = ResetDummy();
|
|||
|
|
if (Input.GetKeyDown(_kSlow)) { _slow = !_slow; Time.timeScale = _slow ? Mathf.Clamp(cfg.slowScale, 0.05f, 1f) : 1f; _msg = _slow ? "슬로 모션 ×" + Time.timeScale : "정상 속도"; }
|
|||
|
|
#if UNITY_EDITOR
|
|||
|
|
if (Input.GetKeyDown(_kPause)) UnityEditor.EditorApplication.isPaused = !UnityEditor.EditorApplication.isPaused;
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void OnGUI()
|
|||
|
|
{
|
|||
|
|
if (Cfg.label == 0) return;
|
|||
|
|
if (_style == null) { _style = new GUIStyle(GUI.skin.label); _style.alignment = TextAnchor.UpperLeft; _style.wordWrap = true; }
|
|||
|
|
_style.fontSize = Mathf.Max(10, Mathf.RoundToInt(Screen.height * Cfg.labelFontScale));
|
|||
|
|
_style.normal.textColor = Ready ? Color.white : new Color(1f, 0.9f, 0.5f);
|
|||
|
|
string w = "-";
|
|||
|
|
if (WLInventory.Loaded) { var cur = WLInventory.EquippedInSlot(eFREquipmentType.Weapon); if (cur != null && cur.itemJson != null) w = cur.itemJson.Item_name + "(" + cur.itemJson.GroupNo + ")"; }
|
|||
|
|
string s = "WL 스킬 테스트 · " + Stage + (Ready ? "" : " …") +
|
|||
|
|
"\n무기 " + w + " 더미 HP " + (Dummy != null ? Dummy.Get_HP().ToString("F0") : "-") + (_slow ? " [슬로 ×" + Time.timeScale + "]" : "") +
|
|||
|
|
"\nWASD 이동 · Space 공격 · Q 주력 · E 각성 · 숫자 등급 · [ ] 무기 · R 더미 · T 슬로 · P 일시정지" +
|
|||
|
|
(string.IsNullOrEmpty(_msg) ? "" : "\n" + _msg) + (Ready ? "\n" + string.Join(" · ", Laps.ToArray()) : "");
|
|||
|
|
var r = new Rect(Screen.width * 0.01f, Screen.height * 0.01f, Screen.width * 0.6f, Screen.height * 0.3f);
|
|||
|
|
GUI.color = new Color(0f, 0f, 0f, 0.6f); GUI.Label(new Rect(r.x + 1, r.y + 1, r.width, r.height), s, _style);
|
|||
|
|
GUI.color = Color.white; GUI.Label(r, s, _style);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|