WL #976 PD 지시 5건 — ① 활 공속 0.7 이 다른 무기에 남던 것(WLWeaponAttackPattern 무기를 바꿀 때 이미 덮인 값을 새 기준으로 잡음 → 같은 PC 면 기준 유지 · 실측 활 0.77 → 해머 1.10 → 한손검 1.10 → 활 0.77 → 한손검 1.10) ② 해머 기본 공격 이펙트 절반(WLImpactFx 피격 1.0 → 0.5 · 휘두르기 1~3타 1.0 → 0.5 · 1타 지면 충격 0.18 → 0.09 · 같은 Play 비교 이펙트 하나 크기 약 0.5 배) ③ 활 기본 스킬 멀티샷 = 기본 화살 Projectile_10402 · 간격 0.2 s · 다발마다 6발(다시 당기기 interval × drawFraction 0.8 · 실측 6발 × 3 · 간격 0.23 · 0.20 s) ④ 비수 기본 무자비한 일격 모으기 1.0 → 0.5 s(원본 Skill_BrutalSlash 대기 줄 훅 1줄 → 새 WLSkillTiming.json · 실측 멈춤 0.51~0.52 s) · 마젠타 = 프리팹 Multiple Slashes 층 시작색 (0.85,0,1) → 같은 프리팹 파랑 (0.30,0.55,1)(실측 분홍 픽셀 3841 → 1~5) ⑤ 맹약(오브) 주력 시전 동작 = 지팡이 3타 내뻗기(StaffCast3 서브클립 WL 사본 WL_OrbMainCast.anim · 투사체 이벤트 → SkillEvent · pcanim_mage casting_end 속도 0.1225 · 스킬 이벤트 약 0.08 s 즉시)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
깃 관리자 2026-10-24 01:28:09 +09:00
parent 29a45e22d9
commit bb37626e34
14 changed files with 6171 additions and 17 deletions

View File

@ -2169,7 +2169,7 @@ AnimatorStateTransition:
serializedVersion: 3
m_TransitionDuration: 0.25
m_TransitionOffset: 0
m_ExitTime: 0.90625
m_ExitTime: 0.9
m_HasExitTime: 1
m_HasFixedDuration: 1
m_InterruptionSource: 0
@ -2493,7 +2493,7 @@ AnimatorState:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: casting_end
m_Speed: 1
m_Speed: 0.1225
m_CycleOffset: 0
m_Transitions:
- {fileID: 811731208389968518}
@ -2506,7 +2506,7 @@ AnimatorState:
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: a9b647a73aef2fb4a83c157be5e4867c, type: 3}
m_Motion: {fileID: 7400000, guid: 9608e81974b7f3e4a85c201446c40a5c, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:

View File

@ -76,6 +76,16 @@ PrefabInstance:
propertyPath: m_IsActive
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1208275532420764258, guid: 8a02c4042c68dd244abad8cf394dab42,
type: 3}
propertyPath: InitialModule.startColor.maxColor.g
value: 0.55
objectReference: {fileID: 0}
- target: {fileID: 1208275532420764258, guid: 8a02c4042c68dd244abad8cf394dab42,
type: 3}
propertyPath: InitialModule.startColor.maxColor.r
value: 0.3
objectReference: {fileID: 0}
- target: {fileID: 6424247364373830703, guid: 8a02c4042c68dd244abad8cf394dab42,
type: 3}
propertyPath: m_LocalPosition.x

View File

@ -81,7 +81,7 @@ public class Skill_BrutalSlash : ProjectileBase
var shooterpos = m_ProjecTileData.shooter.Get_position();
gos_effect[0].transform.position = new Vector3(shooterpos.x, 0f, shooterpos.z);
m_ProjecTileData.shooter.m_animation.speed = 0f;
yield return new WaitForSeconds(1.0f);
yield return new WaitForSeconds(WL.Combat.Weapon.WLSkillTiming.Seconds(this, "charge", 1.0f)); // WL #976 훅(1줄) — 모으기(애니메이션 멈춤) 시간 = WLSkillTiming.json(비수 기본 0.5 s · 규칙 없으면 원본 1.0 s)
m_ProjecTileData.shooter.m_animation.speed = 1f;
DSUtil.InActivateGameObjects(gos_effect, 1);
m_sacc.Set(m_ProjecTileData);

View File

@ -29,7 +29,8 @@
10502
],
"prefab": "WL_Hit_Hammer",
"scale": 1.0,
"scale": 0.5,
"_note_976": "#976 PD 「해머 기본 공격 이펙트 크기를 절반으로」 — 피격 1.0 → 0.5 · 휘두르기 WL_Impact_Swing_Orange 1~3타 1.0 → 0.5 · 1타 지면 충격 WL_Impact_Explosion 0.18 → 0.09(10502 수호자의 철퇴 · lineup 밖도 같은 규칙)",
"fit": 1.4,
"offsetCompensate": true
},
@ -197,7 +198,7 @@
1
],
"prefab": "WL_Impact_Swing_Orange",
"scale": 1.0,
"scale": 0.5,
"euler": [
0,
0,
@ -218,7 +219,7 @@
2
],
"prefab": "WL_Impact_Swing_Orange",
"scale": 1.0,
"scale": 0.5,
"euler": [
0,
0,
@ -239,7 +240,7 @@
3
],
"prefab": "WL_Impact_Swing_Orange",
"scale": 1.0,
"scale": 0.5,
"euler": [
0,
0,
@ -378,7 +379,7 @@
],
"stage": 1,
"prefab": "WL_Impact_Explosion",
"scale": 0.18,
"scale": 0.09,
"forward": 0.0,
"tipContact": true,
"contactHeight": 0.15,

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: aef4c9968cd508c41a13c550830088ad
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9608e81974b7f3e4a85c201446c40a5c
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -45,10 +45,12 @@
"holdMaxSeconds": 3.0,
"multi": {
"enabled": 1,
"projectile": "Projectile_ArcherSkill2Arrow",
"projectile": "Projectile_10402",
"volleys": 3,
"interval": 0.5,
"arrows": 10,
"interval": 0.2,
"arrows": 6,
"drawFraction": 0.8,
"note_976": "#976 PD 「활 기본 공격이 투사체 형태로 발사되어야 하는데 투사체처럼 보이지 않아. 기본 활 투사체와 동일한 투사체를 발사하도록 변경하고, 연속 공격 간격을 0.2초로 줄여줘 (발사하는 투사체 수량도 6발로 줄여줘)」 — PM 해석: 활 기본 스킬(멀티샷 Q) · 화살 Projectile_ArcherSkill2Arrow(주력 속사 금빛 줄기) → Projectile_10402(기본 공격 화살 · 겉모습 WLProjectileVisual 그대로) · 간격 0.5 → 0.2 s · 다발마다 10 → 6발(3회 그대로) · 다시 당기기 = 0.2 × 0.8 = 0.16 s(원래 당김 0.23 s 보다 빨리)",
"fanDegrees": 60,
"rangeMul": 1.0,
"pierce": 0,

View File

@ -0,0 +1,12 @@
{
"enabled": 1,
"rules": [
{
"skill": "Skill_BrutalSlash",
"classId": 10202,
"key": "charge",
"seconds": 0.5,
"note": "#976 PD 「비수 기본 스킬 모으기 시간을 절반으로 줄이고」 — 원본 Skill_BrutalSlash.Co_Update 모으기(발밑 이펙트 + 캐릭터 애니메이션 멈춤) 1.0 → 0.5 s · 비수(직업 10202) 기본 스킬 무자비한 일격 703106"
}
]
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 76f6b7026785dbd419f19d836be39055
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -78,6 +78,7 @@ namespace WL.Combat.Weapon
public float rangeMul = 1f; // 나는 거리 = 기본 공격 사정거리(흰 원) × 이 값 · 0 = 투사체 원래 수명
public int pierce = 0; // 1 = 관통
public int mark = 0; // 1 = 과녁 표시(주력처럼)
public float drawFraction = 0.8f; // #976 다시 당기는 시간 상한 = interval × 이 값(간격이 당김 동작 0.23 s 보다 짧으면 그만큼 빨리 당긴다)
public string note = "";
}
@ -228,10 +229,13 @@ namespace WL.Combat.Weapon
float lastFire = -99f;
float shotSp = c.shotSpeed; // 발 재생 속도(애니메이터 속도를 직접 씀 = 기본 공격 공속 배율과 무관 · #975 실측 활 컨트롤러 재생 배수 파라미터 없음)
float drawDur = Mathf.Max(0f, (releaseN - c.fromNormalized) * ClipLen(an, c.shotClip) / Mathf.Max(0.1f, c.shotSpeed)); // 다시 당겨 놓기까지(초 · 어림 — 실제 놓는 순간은 아래에서 interval 에 맞춤)
// #976 간격(0.2 s)이 당김 동작보다 짧으면 다시 당기기를 interval × drawFraction 안에 끝나게 빨리 재생
float mDraw = _multi && mc.drawFraction > 0f ? Mathf.Min(drawDur, mc.interval * mc.drawFraction) : drawDur;
float mSp = mDraw > 1e-3f && drawDur > 1e-3f ? c.shotSpeed * drawDur / mDraw : c.shotSpeed;
for (int i = 0; i < n; i++)
{
if (_multi && i > 0) // #975 앞 다발을 놓은 뒤 자세를 이어 재생하다가 interval − 당기는 시간(− 몇 프레임 여유 · 첫 Play 실측 0.54 s = 2 프레임 늦음)에 다시 당긴다
while (Time.time < lastFire + mc.interval - drawDur - 3f * Time.smoothDeltaTime)
while (Time.time < lastFire + mc.interval - mDraw - 3f * Time.smoothDeltaTime)
{
if (Broken()) { End(false); yield break; }
an.speed = an.GetCurrentAnimatorStateInfo(0).normalizedTime < c.endNormalized ? shotSp : 0f; // 다음 상태로 넘어가지 않게(공격 2타 전이 0.98)
@ -239,12 +243,13 @@ namespace WL.Combat.Weapon
}
Face();
float startN = i == 0 ? c.drawNormalized : c.fromNormalized, s0 = Time.time;
an.Play(c.shotState, 0, startN); an.speed = Mathf.Max(0.1f, shotSp);
float spNow = _multi && i > 0 ? mSp : shotSp; // #976 멀티샷 다시 당기기 = mSp
an.Play(c.shotState, 0, startN); an.speed = Mathf.Max(0.1f, spNow);
yield return null;
while (an.GetCurrentAnimatorStateInfo(0).normalizedTime < releaseN && Time.time - s0 < 1f)
{
if (Broken()) { End(false); yield break; }
if (an.speed != shotSp) an.speed = shotSp;
if (an.speed != spNow) an.speed = spNow;
if (!an.GetCurrentAnimatorStateInfo(0).IsName(c.shotState)) an.Play(c.shotState, 0, startN);
yield return null;
}

View File

@ -0,0 +1,74 @@
// ─────────────────────────────────────────────────────────────────────────────
// WLSkillTiming.cs — 원본 스킬 코드에 박힌 대기 시간(초)을 스킬 · 직업별로 바꾼다 (#976 · 2026-10-24)
//
// PD 원문: 「비수 기본 스킬 모으기 시간을 절반으로 줄이고, 마젠타 색상을 정상화 해줘.」
// ■ 원본 Skill_BrutalSlash.Co_Update = 0.1 초 뒤 발밑 모으기 이펙트 + 캐릭터 애니메이션 멈춤 1.0 초(모으기) → 베기 이펙트 · 판정
// → 원본 대기 줄을 훅 1줄 `WaitForSeconds(WLSkillTiming.Seconds(this, "charge", 1.0f))` 로 바꿔 규칙 값(없으면 원본 값 그대로)
// ■ 값 = Resources/WL/WLSkillTiming.json (C45) · rules[{skill(원본 스킬 클래스 이름), classId(0 = 모든 직업 · 직업 맞는 행 먼저), key, seconds}] · 끄기 = enabled 0
// 🔴 Debug.LogError 금지(원본 팝업).
// ─────────────────────────────────────────────────────────────────────────────
using UnityEngine;
namespace WL.Combat.Weapon
{
[System.Serializable]
public class WLSkillTimingRule
{
public string skill = "", key = "";
public int classId;
public float seconds = -1f;
public string note = "";
}
[System.Serializable]
public class WLSkillTimingJson
{
public int enabled = 1;
public WLSkillTimingRule[] rules = new WLSkillTimingRule[0];
}
public static class WLSkillTiming
{
public const string ResourcesPath = "WL/WLSkillTiming";
public static int Used;
public static string LastLog = "";
static WLSkillTimingJson s_cfg;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] static void Reset() { s_cfg = null; }
static WLSkillTimingJson Cfg
{
get
{
if (s_cfg != null) return s_cfg;
s_cfg = new WLSkillTimingJson();
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;
}
}
/// <summary>원본 스킬 대기 시간 — 규칙(스킬 클래스 이름 · 시전자 직업 · 키)이 있으면 그 값, 없으면 원본 값(def).</summary>
public static float Seconds(ProjectileBase pb, string key, float def)
{
try
{
var c = Cfg; if (c.enabled == 0 || pb == null || c.rules == null) return def;
var pd = pb.Get_ProjectTileData();
int cls = pd != null && !DSUtil.CheckNull(pd.shooter) ? pd.shooter.Get_ID() : 0;
string sk = pb.GetType().Name; WLSkillTimingRule any = null;
foreach (var r in c.rules)
{
if (r == null || r.skill != sk || r.key != key || r.seconds < 0f) continue;
if (r.classId == cls) { any = r; break; }
if (r.classId == 0 && any == null) any = r;
}
if (any == null) return def;
Used++; LastLog = sk + " " + key + " " + def.ToString("0.##") + " → " + any.seconds.ToString("0.##") + " s(직업 " + cls + ")";
return any.seconds;
}
catch (System.Exception ex) { LastLog = "실패 — " + ex.Message; return def; }
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2c7548fdbb1ae4145bd7f4db88e15d1c

View File

@ -82,11 +82,14 @@ namespace WL.Combat.Weapon
bool pcChanged = !ReferenceEquals(pc, _pc);
if (wid != _weapon || pcChanged)
{
// #976 PD 「활 공격 속도만 늦추라고 했는데 다른 무기의 공격 속도도 같이 느려진 것 같아」 — 무기를 바꿀 때 기준을 버리고 지금 값(활 × 0.7 이 덮인 값)을 새 기준으로 잡아
// 다른 무기에 0.7 배가 남았다 → 같은 PC 면 기준(_baseSpd)을 유지(재계산으로 값이 바뀌었으면 ApplySpeed 가 그 값을 새 기준으로)
bool keepBase = !pcChanged && _baseSpd > 0f && _lastSetSpd > 0f;
_pc = pc; _weapon = wid; CurrentWeapon = wid;
_steps = wid > 0 ? WLWeaponAttackTable.Steps(wid) : null;
var f = _steps != null && _steps.Count > 0 ? _steps[0] : null;
_mult = f != null && f.attackSpeedMult > 0f ? f.attackSpeedMult : 1f;
_baseSpd = -1f; _lastSetSpd = -1f;
if (!keepBase) { _baseSpd = -1f; _lastSetSpd = -1f; }
// 원거리 계열 = 표 사거리로 탐색·추적 거리 덮기(근접은 에셋 값 그대로)
bool ranged = f != null && (f.family == "Bow" || f.family == "Staff");
float r = ranged ? f.rangeM + cfg.rangedRangeMargin : cfg.meleeSearchRange;
@ -107,7 +110,7 @@ namespace WL.Combat.Weapon
/// <summary>FinalAttackSpeed = 기준 × 배율. 재계산(Reset)으로 값이 바뀌면 그 값을 새 기준으로 삼아 다시 덮는다.</summary>
void ApplySpeed(PCActor pc)
{
if (_steps == null) return;
if (_steps == null && _baseSpd < 0f) return; // #976 표에 없는 무기 = 배율 1 · 앞 무기 배율을 덮었으면 기준으로 되돌린다
ActorStatInfo info; try { info = pc.Get_StatInfo(); } catch { return; }
if (info == null) return;
float cur = (float)info.Get_Stat(eStat.FinalAttackSpeed);