2026-10-18 15:09:05 +00:00
// ─────────────────────────────────────────────────────────────────────────────
// WLJumpSlam.cs — 점프 내려찍기 타이밍: 점프 중(최고점 무렵)에 내려찍기 동작으로 넘어가 착지 순간에 지면을 찍게 (#909 · 2026-10-17)
/ /
// PD 원문: 「망치 주력 스킬 사용시 점프 최고점에서 내려찍기 모션 상태로 지면을 찍도록 해줘. (지금은 점프가 끝난 후 지면에서 내려치는 모션이 나오고 있어서 어색해)」
// ■ 원본 = 점프 이동은 Actor.Co_JumpAttack(높이 1 · landAt 초) · 동작은 컨트롤러 jump(Armed-Jump-Flip) → 끝 무렵 jumpattack(Mace-Attack-R2 · SkillEvent = 타격)
// 으로 넘어가 내려치기 타격이 착지 뒤에 나왔다.
// ■ 처리 — 스킬 시작(CombatEvents.SkillCast)부터 slamAt 초에 slamState 로 바로 넘기고, 그 클립의 SkillEvent(타격) 시각이 정확히 landAt 초(착지)에 오도록
// 애니메이터 속도를 맞춘다(타격 이벤트 시각은 클립에서 읽음). 착지 뒤 속도 1 로 되돌림.
// ■ 값 = Resources/WL/WLJumpSlam.json (C45) · 끄기 = enabled 0 → 원본 동작 · 원본 수정 0줄
2026-10-31 06:53:50 +00:00
// ■ #998 (2026-10-30) PD 「창 기본 스킬은 회전하며 점프하는게 아니라 제자리에서 점프했다가 내려치기만」 · 「창 기본 스킬 점프하며 내려치는 동안 짧게 기가 모이는 연출을 발생한 후 내리쳐」
// · 「대검 기본 스킬 = 점프하는 동안 몸을 회전하며 검기로 몸을 세로 방향으로 최대 3회전 하며 공격하고 내려치는 공격(회전하는 검기는 기본 궤적 검기)」
// — 규칙 classId(직업 행 먼저) · ownJump 1 = 원본 점프 이동(Co_JumpAttack · 대상 쪽 · 앞구르기 클립 jump)을 Actor 훅 1줄(OwnJump)로 끄고 제자리 점프:
// 오름 rise(내려찍기 클립을 처음부터 타격 시각 × holdAt 까지 = 무기를 든 자세) → 멈춤 hang(자세 고정 · hangFx) → 내림 fall(타격 시각이 착지에 오게 속도) · 높이 height
// spins = 오름 + 멈춤 동안 엉덩이 뼈를 몸 중심 · 오른쪽 축으로 세로 회전하는 바퀴 수 · spinFx = 바퀴마다 몸 중심에 띄우는 검기(PC 를 따라감)
2026-10-18 15:09:05 +00:00
// 🔴 Debug.LogError 금지(원본 팝업).
// ─────────────────────────────────────────────────────────────────────────────
using UnityEngine ;
using WL.Combat.Core ;
namespace WL.Combat.Weapon
{
[System.Serializable]
public class WLJumpSlamRule
{
public string skill = "" ; // eEffect 이름(원본 스킬 클래스)
public string slamState = "" ; // 내려찍기 상태 이름
public string slamClip = "" ; // 그 상태의 클립 이름(타격 SkillEvent 시각을 읽는다)
public float slamAt = 0.3f ; // 스킬 시작 뒤 내려찍기로 넘어가는 시각(초)
public float landAt = 0.8f ; // 착지 시각(초) = 원본 Co_JumpAttack 지속 시간
public float crossFade = 0.08f ; // 넘어가는 시간(초)
2026-10-31 06:53:50 +00:00
public int classId ; // #998 0 = 모든 직업 · > 0 = 이 직업만(직업이 맞는 행 먼저)
public int ownJump ; // #998 1 = 제자리 점프(아래 값) · 0 = 원본 점프 이동 + slamAt · landAt
public float height = 1f , rise = 0.3f , hang = 0.25f , fall = 0.2f ; // #998 높이(m) · 오름 · 멈춤 · 내림(초)
public float holdAt = 0.5f ; // #998 멈춤 자세 = 내려찍기 클립 타격 시각의 이 비율 자리
public WLStaffEarthFx hangFx = new WLStaffEarthFx ( ) ; // #998 멈춤 동안 모으기 이펙트(시전자 기준 · follow 1 = 따라감)
public int spins ; // #998 세로 회전 바퀴 수(0 = 안 돎)
public WLStaffEarthFx spinFx = new WLStaffEarthFx ( ) ; // #998 바퀴마다 몸 중심에 띄우는 검기(PC 를 따라감 · euler = 정면 기준)
// #998 PD 「대검 기본 스킬은 회전하는 동안 제자리에 있는게 아니라 1.5m 가량 전진하며 낙하까지 · 회전하는 동안 상승(↗)과 낙하(↘)하며 회전이 멈출 타이밍에 맞춰 내려치는 동작이 이어지도록」
// arc 1 = 높이가 착지까지 한 포물선(오름 · 멈춤 · 내림 구분 없이 ↗↘ · 회전은 rise + hang 동안 = 내려가는 중에 멈추고 바로 내림 fall 동안 내려치기) · forward = 착지까지 정면으로 가는 거리(m)
public int arc ;
public float forward ;
// #1000 PD 「대검 기본 스킬 … 마지막 내려칠 때는 기본 공격 마지막타와 동일하게 내려치기동작과 이펙트로」 — landFx = 착지(타격) 순간 PC 정면 기준 offset 자리에 띄우는 지면 이펙트(기본 4타 지면 충격과 같은 프리팹)
public WLStaffEarthFx landFx = new WLStaffEarthFx ( ) ;
public WLStaffEarthFx landTrace = new WLStaffEarthFx ( ) ; // #1006 PD 「대검 기본 스킬 사용 후 지면에 충격 흔적이 남도록 (해머 공격에 사용 된 지면 충격 효과를 참고)」 — landFx 와 같은 순간 · 같은 기준(PC 정면 offset)에 남기는 흔적
public float impactTime ; // #1001 0 보다 크면 내려찍기 타격 시각(클립 초)을 클립 SkillEvent 대신 이 값으로(대검 = SkillEvent 를 점프 시작으로 옮겨 회전 연타 판정을 WLStaffEarth 가 맡음 · 내려치기 동작 시각은 4타 그대로 0.80)
// #1008 PD 「해머 주력 스킬 시전 시 해머를 내려치기 전 딜레이를 추가하고, 딜레이 시간 동안 해머가 빛나게 해줘. (해머 각성 스킬의 50% 정도의 딜레이 및 빛나는 연출)」 —
// hangGlow > 0 = 멈춤(hang) 동안 무기 흰 빛 0 → hangGlow(해머 각성과 같은 덧그림 WLWeaponGlowFx) · 내림 동안 유지 · 착지(타격)부터 glowFade 초에 꺼짐
public float hangGlow ;
public float [ ] glowColor = { 1.6f , 1.6f , 1.6f } ;
public float glowFill = 0.35f , glowRim = 2.5f , glowFade = 0.25f ;
public string glowMaterial = "WL/Fx/WL_Mat_WeaponGlow" ;
2026-10-18 15:09:05 +00:00
}
[System.Serializable] public class WLJumpSlamJson { public int enabled ; public WLJumpSlamRule [ ] rules = new WLJumpSlamRule [ 0 ] ; public string note = "" ; }
public static class WLJumpSlam
{
public const string ResourcesPath = "WL/WLJumpSlam" ;
public static int Slams , Missing , Errors ; public static string LastLog = "" ;
static WLJumpSlamJson s_cfg ;
static WLJumpSlamJson Cfg
{
get
{
if ( s_cfg ! = null ) return s_cfg ;
s_cfg = new WLJumpSlamJson ( ) ;
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 ;
}
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
static void Boot ( )
{
s_cfg = null ;
CombatEvents . SkillCast . Remove ( OnCast ) ;
if ( Cfg . enabled ! = 0 ) CombatEvents . SkillCast . Add ( OnCast ) ;
}
static void OnCast ( in SkillCastEvent e )
{
try
{
var pc = e . actor as PCActor ;
if ( pc = = null | | ! pc . IsMainPC ( ) | | e . skill = = null | | Cfg . rules = = null ) return ;
2026-10-31 06:53:50 +00:00
var r = Find ( pc , e . skill . e_Skill . ToString ( ) ) ; if ( r = = null ) return ;
var run = pc . GetComponent < WLJumpSlamRunner > ( ) ; if ( run = = null ) run = pc . gameObject . AddComponent < WLJumpSlamRunner > ( ) ;
run . Begin ( pc , r ) ;
2026-10-18 15:09:05 +00:00
}
catch ( System . Exception ex ) { Errors + + ; LastLog = "시작 실패 — " + ex . Message ; }
}
2026-10-31 06:53:50 +00:00
/// <summary>#998 직업이 맞는 행 먼저 · 없으면 classId 0 행.</summary>
static WLJumpSlamRule Find ( PCActor pc , string skill )
{
WLJumpSlamRule any = null ; int cls = pc . Get_ID ( ) ;
foreach ( var r in Cfg . rules )
{
if ( r = = null | | r . skill ! = skill ) continue ;
if ( r . classId = = cls ) return r ;
if ( r . classId = = 0 & & any = = null ) any = r ;
}
return any ;
}
/// <summary>#998 Actor.Play_Skill 훅(1줄) — 이번 시전을 제자리 점프 러너가 맡았으면 true(원본 점프 이동 Co_JumpAttack 을 건너뜀). SkillCast 이벤트(Begin)가 먼저 불린다.</summary>
public static bool OwnJump ( Actor a )
{
try { var pc = a as PCActor ; if ( pc = = null | | Cfg . enabled = = 0 ) return false ; var run = pc . GetComponent < WLJumpSlamRunner > ( ) ; return run ! = null & & run . OwnActive ; }
catch ( System . Exception ex ) { Errors + + ; LastLog = "OwnJump 실패 — " + ex . Message ; return false ; }
}
public static int OwnJumps , SpinFxShown , HangFxShown , LandFxShown , LandTraces , Glows ; public static float LastSpinDeg , LastPeak , LastGlow ;
2026-10-18 15:09:05 +00:00
/// <summary>클립의 첫 SkillEvent 시각(초) · 없으면 -1.</summary>
internal static float ImpactTime ( Animator an , string clipName )
{
if ( an = = null | | an . runtimeAnimatorController = = null | | string . IsNullOrEmpty ( clipName ) ) return - 1f ;
foreach ( var c in an . runtimeAnimatorController . animationClips )
{
if ( c = = null | | c . name ! = clipName ) continue ;
foreach ( var ev in c . events ) if ( ev . functionName = = "SkillEvent" ) return ev . time ;
}
return - 1f ;
}
}
public sealed class WLJumpSlamRunner : MonoBehaviour
{
PCActor _pc ; WLJumpSlamRule _r ; float _t0 , _impact ; bool _on , _slammed ;
2026-10-31 06:53:50 +00:00
// #998 제자리 점프
bool _own , _started , _hung , _set , _landFx ; float _hold , _y0 , _peak , _lastAng ; int _spun ; Transform _bone ; Vector3 _pivotLocal , _setPos , _start , _fwd ; Quaternion _setRot ;
// #1008 멈춤 동안 무기 흰 빛
readonly WLWeaponGlowFx _glow = new WLWeaponGlowFx ( ) ; WLJumpSlamRule _glowRule ; float _glowFadeAt = - 1f ; Color _glowCol = Color . white ;
public bool OwnActive { get { return _on & & _own ; } }
void GlowSet ( float g ) { if ( _glowRule = = null ) return ; _glow . Set ( g , _glowCol , _glowRule . glowFill , _glowRule . glowRim ) ; WLJumpSlam . LastGlow = g ; }
void GlowFade ( ) { if ( _glow . Active & & _glowFadeAt < 0f ) _glowFadeAt = Time . time ; }
/// <summary>#1008 착지 뒤 흰 빛 끄기 — 시전이 끝난 뒤(_on 꺼짐)에도 돈다.</summary>
void GlowTick ( )
{
if ( _glowFadeAt < 0f | | _glowRule = = null ) return ;
float k = 1f - Mathf . Clamp01 ( ( Time . time - _glowFadeAt ) / Mathf . Max ( 0.01f , _glowRule . glowFade ) ) ;
if ( k < = 0f ) { _glow . End ( ) ; _glowFadeAt = - 1f ; return ; }
GlowSet ( _glowRule . hangGlow * k ) ;
}
2026-10-18 15:09:05 +00:00
public void Begin ( PCActor pc , WLJumpSlamRule r )
{
2026-10-31 06:53:50 +00:00
if ( _on & & _own ) Restore ( ) ;
_glow . End ( ) ; _glowFadeAt = - 1f ; _glowRule = null ; // #1008
2026-10-18 15:09:05 +00:00
_pc = pc ; _r = r ; _t0 = Time . time ; _slammed = false ;
2026-10-31 06:53:50 +00:00
_impact = r . impactTime > 0f ? r . impactTime : WLJumpSlam . ImpactTime ( pc . m_animation , r . slamClip ) ;
2026-10-18 15:09:05 +00:00
_on = _impact > 0f ;
2026-10-31 06:53:50 +00:00
_own = _on & & r . ownJump ! = 0 ; _started = _hung = _set = _landFx = false ; _spun = 0 ; _lastAng = 0f ; _bone = null ;
if ( ! _on ) { WLJumpSlam . Missing + + ; WLJumpSlam . LastLog = "타격 이벤트 없음 " + r . slamClip ; return ; }
if ( ! _own ) return ;
_hold = _impact * Mathf . Clamp01 ( r . holdAt ) ; _y0 = pc . transform . position . y ; _peak = 0f ; _start = pc . transform . position ; _fwd = pc . transform . forward ;
if ( OptionInfo . Ins ! = null ) OptionInfo . Ins . Set_PCMove ( pc , false ) ; // 원본 Co_JumpAttack 과 같게(조작 끔 · 착지에 되돌림)
if ( r . spins > 0 )
{
_bone = SpinBone ( pc ) ;
_pivotLocal = pc . transform . InverseTransformPoint ( WL . Combat . Impact . WLImpactFx . BodyCenter ( pc ) ) ;
}
WLJumpSlam . OwnJumps + + ;
}
/// <summary>#956 과 같은 뼈 — Humanoid Hips · 없으면 루트 직계 중 이름이 Root 로 시작하는 것(이 PC = Root_M).</summary>
static Transform SpinBone ( PCActor pc )
{
var an = pc . m_animation ; Transform b = an ! = null & & an . isHuman ? an . GetBoneTransform ( HumanBodyBones . Hips ) : null ;
if ( b = = null ) foreach ( Transform c in pc . transform ) if ( c . name . StartsWith ( "Root" ) ) { b = c ; break ; }
return b ;
2026-10-18 15:09:05 +00:00
}
void Update ( )
{
2026-10-31 06:53:50 +00:00
GlowTick ( ) ; // #1008
2026-10-18 15:09:05 +00:00
if ( ! _on ) return ;
var an = _pc ! = null ? _pc . m_animation : null ;
if ( an = = null | | _pc . IsDead ( ) | | _pc . Get_CurAnim ( ) ! = eAnim . Skill ) { End ( an ) ; return ; }
float t = Time . time - _t0 ;
2026-10-31 06:53:50 +00:00
if ( _own ) { OwnTick ( an , t ) ; return ; }
2026-10-18 15:09:05 +00:00
if ( ! _slammed & & t > = _r . slamAt )
{
_slammed = true ;
float remain = Mathf . Max ( 0.05f , _r . landAt - t ) ;
an . CrossFadeInFixedTime ( _r . slamState , Mathf . Max ( 0f , _r . crossFade ) , 0 , 0f ) ;
an . speed = Mathf . Clamp ( _impact / remain , 0.3f , 3f ) ;
WLJumpSlam . Slams + + ;
WLJumpSlam . LastLog = "내려찍기 " + _r . slamState + " · " + t . ToString ( "0.00" ) + " s · 속도 " + an . speed . ToString ( "0.00" ) + " · 타격 예정 " + _r . landAt . ToString ( "0.00" ) + " s" ;
}
if ( _slammed & & t > = _r . landAt + 0.05f ) End ( an ) ;
}
2026-10-31 06:53:50 +00:00
/// <summary>#998 제자리 점프 — 오름(무기 드는 자세까지 감기) → 멈춤(자세 고정 · 모으기) → 내림(타격 = 착지) · 높이는 매 프레임 직접.</summary>
void OwnTick ( Animator an , float t )
{
var r = _r ; float rise = Mathf . Max ( 0.05f , r . rise ) , hang = Mathf . Max ( 0f , r . hang ) , fall = Mathf . Max ( 0.05f , r . fall ) , land = rise + hang + fall ;
if ( ! _started ) // 첫 프레임 — Play_Skill 이 시전 이벤트 뒤에 스킬 동작(jump)을 틀므로 여기서 내려찍기로 넘긴다
{
_started = true ;
_start = _pc . transform . position ; _fwd = _pc . transform . forward ; _fwd . y = 0f ; if ( _fwd . sqrMagnitude < 1e-4f ) _fwd = Vector3 . forward ; _fwd . Normalize ( ) ; // Play_Skill 이 대상 쪽으로 돌린 뒤
an . CrossFadeInFixedTime ( r . slamState , Mathf . Max ( 0f , r . crossFade ) , 0 , 0f ) ;
an . speed = Mathf . Clamp ( _hold / rise , 0.05f , 3f ) ;
WLJumpSlam . Slams + + ;
WLJumpSlam . LastLog = "제자리 점프 " + r . slamState + " · 높이 " + r . height . ToString ( "0.00" ) + " · 오름 " + rise . ToString ( "0.00" ) + " · 멈춤 " + hang . ToString ( "0.00" ) + " · 내림 " + fall . ToString ( "0.00" ) + " · 회전 " + r . spins + " · 타격 예정 " + land . ToString ( "0.00" ) + " s" ;
}
if ( ! _hung & & t > = rise )
{
_hung = true ; an . speed = 0f ;
if ( hang > 0f & & r . hangFx ! = null & & ! string . IsNullOrEmpty ( r . hangFx . prefab ) )
{
var go = WLStaffEarth . SpawnAt ( r . hangFx , _pc , _pc . Get_position ( ) , _pc . transform . forward , hang ) ;
if ( go ! = null ) { if ( r . hangFx . follow ! = 0 ) go . transform . SetParent ( _pc . transform , true ) ; WLJumpSlam . HangFxShown + + ; }
}
if ( r . hangGlow > 0f ) // #1008 무기 흰 빛 덧그림(무기 소켓 = 끝이 가장 먼 소켓)
{
Transform sk ; Vector3 tl ;
if ( WL . Combat . Impact . WLImpactRunner . SocketTip ( _pc , out sk , out tl ) & & _glow . Begin ( sk , r . glowMaterial ) > 0 )
{
_glowRule = r ; WLJumpSlam . Glows + + ;
var gc = r . glowColor ; _glowCol = gc ! = null & & gc . Length > = 3 ? new Color ( gc [ 0 ] , gc [ 1 ] , gc [ 2 ] , 1f ) : Color . white ;
}
}
}
if ( _glowRule ! = null & & _glowFadeAt < 0f & & t > = rise ) GlowSet ( r . hangGlow * Mathf . Clamp01 ( ( t - rise ) / Mathf . Max ( 0.01f , hang ) ) ) ; // #1008 멈춤 동안 0 → hangGlow · 내림 동안 유지
if ( ! _slammed & & t > = rise + hang )
{
_slammed = true ; an . speed = Mathf . Clamp ( ( _impact - _hold ) / fall , 0.3f , 4f ) ;
WLJumpSlam . LastLog + = " · 내림 속도 " + an . speed . ToString ( "0.00" ) ;
}
float y ;
if ( r . arc ! = 0 ) y = r . height * Mathf . Sin ( Mathf . Clamp01 ( t / land ) * Mathf . PI ) ;
else if ( t < rise ) y = r . height * Mathf . Sin ( t / rise * Mathf . PI * 0.5f ) ;
else if ( t < rise + hang ) y = r . height ;
else { float k = Mathf . Clamp01 ( ( t - rise - hang ) / fall ) ; y = r . height * ( 1f - k * k ) ; }
var p = _pc . transform . position ; p . y = _y0 + y ;
if ( r . forward ! = 0f ) { var h = _start + _fwd * ( r . forward * Mathf . Clamp01 ( t / land ) ) ; p . x = h . x ; p . z = h . z ; }
_pc . transform . position = p ; if ( y > _peak ) { _peak = y ; WLJumpSlam . LastPeak = y ; }
if ( ! _landFx & & t > = land )
{
_landFx = true ; var g = new Vector3 ( p . x , _y0 , p . z ) ;
if ( r . landFx ! = null & & ! string . IsNullOrEmpty ( r . landFx . prefab ) & & WLStaffEarth . SpawnAt ( r . landFx , _pc , g , _pc . transform . forward , 0f ) ! = null ) WLJumpSlam . LandFxShown + + ;
if ( r . landTrace ! = null & & WLStaffEarth . SpawnAt ( r . landTrace , _pc , g , _pc . transform . forward , 0f ) ! = null ) WLJumpSlam . LandTraces + + ; // #1006
GlowFade ( ) ; // #1008 타격부터 흰 빛 꺼짐
}
if ( t > = land + 0.05f ) End ( an ) ;
}
/// <summary>#998 세로 회전 — 애니메이터가 이번 프레임 자세를 쓴 뒤 엉덩이 뼈(아래 무기 포함)를 몸 중심 · 오른쪽 축으로 돌린다(+ = 머리가 앞으로) · 바퀴마다 검기 1개.</summary>
void LateUpdate ( )
{
if ( ! _on | | ! _own | | _r . spins < = 0 | | _pc = = null ) return ;
float dur = Mathf . Max ( 0.05f , _r . rise + _r . hang ) , t = Time . time - _t0 ; if ( t > dur + 0.1f ) return ;
float ang = 360f * _r . spins * Mathf . SmoothStep ( 0f , 1f , Mathf . Clamp01 ( t / dur ) ) ;
var root = _pc . transform ; Vector3 pivot = root . TransformPoint ( _pivotLocal ) ;
if ( _bone ! = null )
{
bool rewritten = ! _set | | Quaternion . Angle ( _bone . rotation , _setRot ) > 0.01f | | ( _bone . position - _setPos ) . sqrMagnitude > 1e-8f ; // 애니메이터가 안 쓴 프레임이면 차이만
float d = rewritten ? ang : ang - _lastAng ;
if ( Mathf . Abs ( d ) > 0.001f ) _bone . RotateAround ( pivot , root . right , d ) ;
_setRot = _bone . rotation ; _setPos = _bone . position ; _set = true ; WLJumpSlam . LastSpinDeg = ang ;
}
_lastAng = ang ;
if ( _spun < _r . spins & & ang > = 360f * _spun & & _r . spinFx ! = null & & ! string . IsNullOrEmpty ( _r . spinFx . prefab ) )
{
_spun + + ;
var go = WLStaffEarth . SpawnAt ( _r . spinFx , _pc , pivot , root . forward , 0f ) ;
if ( go ! = null ) { go . transform . SetParent ( root , true ) ; WLJumpSlam . SpinFxShown + + ; }
}
}
/// <summary>#998 끊김(구르기 · 사망 · 상태 바뀜) 때 발 높이 · 조작을 되돌린다.</summary>
void Restore ( )
{
if ( _pc = = null ) return ;
var p = _pc . transform . position ; p . y = _y0 ;
var agent = _pc . GetComponent < UnityEngine . AI . NavMeshAgent > ( ) ; UnityEngine . AI . NavMeshHit hit ; // 앞으로 간 경우 에이전트 자리도 맞춘다(원본 Co_JumpAttack 끝의 Snap_toNavMesh 와 같게)
if ( agent ! = null & & agent . enabled & & UnityEngine . AI . NavMesh . SamplePosition ( p , out hit , 1f , UnityEngine . AI . NavMesh . AllAreas ) ) agent . Warp ( hit . position ) ; else _pc . transform . position = p ;
WLJumpSlam . LastLog + = " · 착지 이동 " + Vector3 . Distance ( new Vector3 ( _start . x , 0f , _start . z ) , new Vector3 ( _pc . transform . position . x , 0f , _pc . transform . position . z ) ) . ToString ( "0.00" ) + " m" ;
if ( OptionInfo . Ins ! = null ) OptionInfo . Ins . Set_PCMove ( _pc , true ) ;
}
2026-10-18 15:09:05 +00:00
void End ( Animator an )
{
2026-10-31 06:53:50 +00:00
if ( _on & & ( _slammed | | _own ) & & an ! = null ) an . speed = 1f ;
if ( _on & & _own ) Restore ( ) ;
GlowFade ( ) ; // #1008 끊겨도 흰 빛은 서서히
2026-10-18 15:09:05 +00:00
_on = false ;
}
2026-10-31 06:53:50 +00:00
void OnDisable ( ) { if ( _on & & _own ) Restore ( ) ; _on = false ; _glow . End ( ) ; _glowFadeAt = - 1f ; }
2026-10-18 15:09:05 +00:00
}
}