WL #986 PD 지시 4건 — ① 비수 기본 = 모으기 끝 수리검이 나오는 순간 시전자 한 바퀴(0.35 s · 360°) + NamuFX Simple Stylized Slash vol2 Slash_Aoe_A 사본 WL_Fx_DaggerSpinSlash(flash 층 검정 수명 색 키 2개 뺌) ② 수리검마다 꼬리(TrailRenderer · SlashTrailSettings 가산 재질 · 비수 무기 궤적 색 · 0.25 s) · 경로 호 다시 숨김(실측 12/12 꼬리 · 궤적 호 0) ③ PD 정정 = 오브 기본 번개를 Cartoon Skill Collection Vol2 FX_Cartoon Thunder 사본 WL_Fx_OrbThunder(0.6 배)로(3타 번개는 그대로) ④ 지팡이 기본(무기 표 1071 칸 3 = 원본 눈보라 703304 그릇 · Skill_Blizzard.Set 훅 1줄 · WLStaffLaser) = 시전 뒤 3타 손 내지른 자세 유지 + 전방 FX_Dragonfire 사본 레이저(0.24 배 ≈ 8 m) 3 s · 0.5 s 다단(실측 6) · 맞을 때마다 0.2 m 밀침 · 가상패드 방향으로 몸만 회전(입력 168 프레임 · 123 → 95°) · 레이저 중 구르기 = 즉시 취소(0.82 s) · 피격 = WL_Impact_Hit_Orange · 리컴파일 오류 0 · Play 3회 콘솔 오류 0

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
깃 관리자 2026-10-26 01:51:40 +09:00
parent 945aafa843
commit 9c2b810508
16 changed files with 132153 additions and 12 deletions

View File

@ -17,6 +17,7 @@ public class Skill_Blizzard : ProjectileBase
_data.eStartPos = eProjectileStartPos.Custom;
_data.v3_StartPos = _data.target.Get_position();
base.Set(_data);
if (WL.Combat.Weapon.WLStaffLaser.Take(this)) return; // WL #986 훅(1줄) — 지팡이 기본: 손 내지른 자세 + 전방 레이저 3 초 · 0.5 초 다단 · 0.2 m 밀침 · 방향 전환 · 구르기 취소(WLStaffLaser.json) · 원본 눈보라 건너뜀
m_LifeTime = lifeTime + (IsStep(1) ? Get_AwakenData(1, 1) : 0f);
transform.eulerAngles = Vector3.zero;
StartCoroutine(Co_Update());

View File

@ -119,6 +119,17 @@
"offsetCompensate": true,
"_note_985": "#985 PD 「오브 기본 스킬 이펙트가 … 지면의 바닥 충격파 이미지는 기존 이펙트와 달라서 이질감이 커」 — Play 캡처: 오브 기본(운석 소환 직업 맞춤 복사본) 번개가 맞힌 대상 몸에 아래 행 WL_Hit_StaffSkill(검은 연기 · 검은 돌)이 떠 번개와 따로 노는 어두운 폭발 → 오브 기본만 번개 피격(MasterStylizedFX Lightnings/LightingHit 사본 · 흰 별 + 전기 줄기) · 오브 다른 스킬 · 마법책 · 지팡이는 그대로"
},
{
"classIds": [
10302
],
"skills": [ "Skill_Blizzard" ],
"prefab": "WL_Impact_Hit_Orange",
"scale": 1.0,
"fit": 1.4,
"offsetCompensate": true,
"_note_986": "#986 지팡이 기본 화염 광선(원본 눈보라 그릇 · WLStaffLaser) 다단 명중 = 주황 피격(아래 공통 행 WL_Hit_StaffSkill 검은 연기 · 돌 대신 · K-WL-134)"
},
{
"classIds": [
10301,

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a545672316f920b418d0fb37943c1610
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: bff3de8d936abfd4d8539e6da28bd0d4
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7eadab099d86ae1438f221315ef8ccc8
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -13,7 +13,7 @@
"riderScale": 0.4,
"rimFraction": 1.0,
"maxSeconds": 2.5,
"hidePath": 0,
"hidePath": 1,
"minHeight": 0.6,
"mode": "scatter",
"scatterCount": 12,
@ -31,7 +31,7 @@
"scatterJitter": 25.0,
"scatterRise": 0.2,
"scatterShrinkFrom": 0.75,
"pathFollow": 1,
"pathFollow": 0,
"pathRate": 30.0,
"pathSizeMin": 0.5,
"pathSizeMax": 1.0,
@ -47,6 +47,19 @@
"hitShake": 0.05,
"hitShakeSeconds": 0.06,
"spinMul": 1.8,
"trail": 1,
"trailSeconds": 0.25,
"trailWidth": 0.3,
"trailWidthEnd": 0.0,
"trailAlpha": 0.9,
"trailClass": 0,
"spinSeconds": 0.35,
"spinDir": 1.0,
"spinFx": "WL/Fx/WL_Fx_DaggerSpinSlash",
"spinFxScale": 1.0,
"spinFxLife": 1.2,
"spinFxY": 0.6,
"note_986": "#986 PD 「비수 기본 스킬 사용 시 캐릭터가 기모으기 포즈 후 투사체 이펙트가 발생될 때 한바퀴 회전하는 모션이 발생되게 해줘. (회전하며 비수를 날리는 컨셉) → 이때 캐릭터에게 \"Simple Stylized Slash Pack 2\" 에셋의 Slash_Aoe_A-Paused를 재생시켜줘.」 + 「비수 기본 스킬 사용 시 궤적이 의미 없이 어지럽게 보이는데, 비수가 날아가는 나선형 궤적으로 표현되도록 해줘. 의미 없는 궤적은 숨기고 실제 비수가 날아가는 궤적만 꼬리처럼 표현하도록 하라는 의미」 — 모으기가 끝나 수리검이 나오는 순간 시전자가 0.35 s 동안 한 바퀴(360° · 가속 · 감속 · 끝나면 처음 방향) + 발 위 0.6 m 에 NamuFX Simple Stylized Slash vol2 Slash_Aoe_A 사본 WL_Fx_DaggerSpinSlash(1.0 배) · 경로 호 다시 숨김(hidePath 1 · pathFollow 0) · 수리검마다 꼬리(TrailRenderer 0.25 s · 폭 0.3 → 0 · 재질 = SlashTrailSettings 가산 · 색 = 비수 10202 무기 궤적 가산색 · 수리검이 끝나도 꼬리가 사라질 때까지 마지막 자리 유지)(PM 값)",
"note_985": "#985 PD 「비수 기본 스킬 시전 시 비수가 너무 느리게 동작하는 것 같고, 갑자기 사라지는 느낌이야. (캐릭터 주위로 펴져나가야 해) 비수 위치를 고려해 궤적 연출을 다시 살리고 좀 더 화려하고 타격감을 느껴질 수 있게 연출해줘.」 — scatter 를 시전자 몸 둘레 0.4~0.9 m 에서 0.3 s 안에 12개가 나와 바깥으로 11 m/s(끝 0.35 배)로 퍼지며 꺾임 30 → 720°/s 로 끝에서 말려 들고 수명 0.45~0.6 s(이전 4 m/s · 0.55~0.85 s · 0.8~4 m 무작위 자리) · 제 축 회전 1.8 배 · 궤적 되살림 = 경로 호(Multiple Slashes)를 원래 무작위 자리 대신 날아가는 수리검 자리에서 수리검마다 초당 30개(크기 0.5~1.0 · hidePath 0 · pathFollow 1) · 75 % 에서 작아지기 시작할 때 그 자리 녹색 터짐(MasterStylizedFX PunchHitGreen 사본 WL_Fx_ShurikenEnd 0.25 배) · 지나가며 적 몸(반지름 + 0.6 m)에 닿으면 녹색 별 섬광(MasterStylizedFX ShurikensHit 사본 WL_Fx_ShurikenHit 0.12 배 · 수리검 · 적 쌍마다 1번 · 피해는 원본 그대로) + 카메라 흔들림 0.05 · 처음 퍼지는 순간 흔들림 0.08(PM 값)",
"note_983": "#983 PD 「비수 기본 스킬의 컨셉이 내가 원했던 모습이 아니야. 기존에 숨긴 궤적과 같이 수리검들이 화면을 불규칙하게 생성되어 날아가며 이때 나선형에 가깝게 회전하듯 사라지는 모습을 원했던거야.」 — mode scatter: 숨긴 경로 호(Multiple Slashes = 구 반지름 4 m 안 · 0.5 s 동안 초당 200 · 수명 0.2~0.75 s 실측)처럼 수리검 12개가 시전자 둘레 0.8~4.0 m · 발 위 0.6~2.0 m 무작위 자리(30° 구간마다 1개)에 0.5 s 동안 무작위 순서로 나타나 · 바깥쪽(± 40°)으로 4 m/s 로 날며 꺾임 90 → 1080°/s(제곱)로 커져 나선으로 말려 들어가고 · 속도 0.3 배까지 줄며 · 수명 0.55~0.85 s 의 35 % 부터 크기가 0 으로(나선 끝에서 사라짐) · 경로 호 숨김(hidePath 1) · 수리검 사본 · 70° 눕힘 그대로(PM 값 · 이전 방사형 = mode spiral)",
"spiralCount": 10,

View File

@ -2,7 +2,7 @@
"enabled": 1,
"castSkills": [
"Skill_Hurricane",
"Skill_MeteoStorm"
"Skill_MeteoStorm", "Skill_Blizzard"
],
"chargeFx": {
"prefab": "WL/Fx/WL_Fx_BowCharge",
@ -156,8 +156,8 @@
"classId": 10301,
"center": "target",
"fx": {
"prefab": "WL/Fx/WL_Fx_OrbLightning",
"scale": 0.45,
"prefab": "WL/Fx/WL_Fx_OrbThunder",
"scale": 0.6,
"bodyScale": 0,
"offset": [ 0, 0, 0 ],
"euler": [ 0, 0, 0 ],
@ -183,6 +183,7 @@
"meteorPattern": "line",
"meteorStart": 1.5,
"meteorStep": 1.8,
"_note_986": "#986 PD 정정 「오브 기본 스킬의 번개를 그냥 \"Game VFX - Cartoon Skill Collection Vol.2(URP)\"에셋의 \"FX_Cartoon_Thunder\"로 바꾸자」 — 번개 = FX_Cartoon Thunder 사본 WL_Fx_OrbThunder(흰 · 파란 만화풍 번개 + 섬광 + 전기 줄기 · 가산 · 루트 템플릿 층 끔) · 배율 0.6(PM 값) · 이전 MasterStylizedFX LightningExplosion 사본(WL_Fx_OrbLightning)은 3타 번개(popups)에만 남음",
"_note_983": "#983 PD 「오브 \"기본 스킬\" 시전 시 플레이어의 전방(공격 대상이 있는 방향)으로 번개 3발이 순차적으로 낙하하며 번개 피해가 전진하며 피해를 입히는 형태로 스킬을 구현해줘. (쾅, 쾅, 쾅! 0.3초 간격으로 전진 된 위치에 순차 낙하하는 번개)」 + 「오브에 사용 할 번개 이펙트는 \"Master Stylized FX\" 에셋의 번개 이펙트를 사용하면 되며, 스크린샷을 참고할 것.」 — 오브 기본(무기 표 1057 칸 3 = 운석 소환 703305 직업 맞춤 복사본 · 해머 기본과 같은 방식) · 이 행 = 직업 10301 만 · 시전 순간 시전자 자리에서 대상 쪽(없으면 정면) 직선 1.5 · 3.3 · 5.1 m 에 0.3 s 간격 번개 3발(meteorPattern line) · 각 번개 0.05 s 뒤 반경 1.6 m(+ 몸 반지름) 적마다 원본 운석 소환 피해(ProcessCollider · 번개마다 따로) · 기절 0 · 번개 = MasterStylizedFX NewExplosions/LightningExplosion 사본 WL_Fx_OrbLightning(위에서 꽂히는 파란 번개 + 파란 구 · 퍼지는 고리 = 바닥에 가려 돔 + 흰 별 + 사방 불꽃 = 스크린샷 · 편집 모드 대조표 Lightnings 5종 · GroundBlast · Explosions 중 선택 · 루트 템플릿 층 끔) · 배율 0.45(PM 값)"
}
],

View File

@ -0,0 +1,20 @@
{
"enabled": 1,
"skill": "Skill_Blizzard",
"classId": 10302,
"fx": "WL/Fx/WL_Fx_StaffLaser",
"fxScale": 0.24,
"fxOffset": [ 0.0, 0.55, 0.45 ],
"fxEuler": [ -90.0, 0.0, 0.0 ],
"seconds": 3.0,
"interval": 0.5,
"length": 8.0,
"width": 1.2,
"push": 0.2,
"holdState": "attack3",
"holdNormalized": 0.5,
"turnDegPerSec": 360.0,
"steerDeadzone": 0.2,
"fadeSeconds": 0.4,
"note": "#986 PD 「지팡이 기본 스킬 시전 시 마법 시전 연출 후 지팡이 기본 공격 3타와 동일하게 손을 내지르는 모션과 함께 \"RPG Game VFX Collection(URP)\" 에셋의 FX_Dragonfire 이펙트를 사용하게 해줘. 이 스킬은 전방 직선 방향으로 레이저 형태의 마법을 발사해 0.5초간격으로 다단히트 피해를 주며, 0.2m씩 적을 밀쳐낼 수 있으며 3초 동안 유지되고, 캐릭터가 방향을 변경할 경우 변경 된 방향으로 지속시간 동안 레이져 공격을 할 수 있어. (단, 구르기를 시도할 경우 마법이 즉시 취소)」 — 그릇 = 원본 Skill_Blizzard(703304 · 시전 skill3 1 s · 마법진 · 모으기 = WLStaffEarth castSkills) · 넘겨받으면 지팡이 3타 자세(attack3 = StaffCast3 · 왼손이 앞 0.4 m · 높이 0.6 m 로 내밀어진 자세 · 실측 967_bowhands)에서 애니메이터를 멈추고 손 앞(오른쪽 0 · 위 0.55 · 앞 0.45 m)에 FX_Dragonfire 사본 WL_Fx_StaffLaser(원본 빔 = 로컬 -Y 약 34 m → -90° 눕혀 정면 · 0.24 배 ≈ 8 m · 반복)를 정면으로 붙임 · 3 초 동안 0.5 초마다(첫 피해 = 켜지는 순간) 정면 8 m × 폭 1.2 m(+ 적 몸 반지름) 안 적에게 원본 투사체 피해 + 레이저 방향 0.2 m 밀침 · 가상패드 방향으로 몸만 360°/s 회전(레이저 중엔 원본 CanMove 가 막혀 조이스틱 이동이 안 불리므로 러너가 가상패드 입력(섬 SimpleInput 축 · 테스트 씬 FloatingJoystick · 방향키)을 직접 읽음 · 축 0.2 미만 무시) · 구르기 = 즉시 취소(레이저 끔 · 자세 · 이동 되돌림)(길이 · 폭 · 배율 · 회전 속도 = PM 값)"
}

View File

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

View File

@ -10,6 +10,7 @@ weapon_id,weapon_name,slot,skill_id,skill_name,skill_class,anim,next_anim,unlock
1029,바람쐐기,2,703406,화살 비,Skill_ArrowRain,archer_skill3,,7,18,0,10,7.0,Slow,WST:1003,Effect_Slow,5,M:skill_id;skill_name;skill_class;anim;next_anim;range_m;awaken2_extra;vfx;src_cool_ref;weapon_id;weapon_name;fr_ref,,,,
1071,현자의 지팡이,1,703306,번개 소용 돌이,Skill_Hurricane,casting,skill_cast2,5,7,0,5,2.4,Burn,WST:1006,Effect_Burn,5,M:skill_id;skill_name;skill_class;anim;next_anim;range_m;awaken2_extra;vfx;src_cool_ref;weapon_id;weapon_name;fr_ref,,,,
1071,현자의 지팡이,2,703305,운석 소환,Skill_MeteoStorm,casting,casting_end,7,18,0,10,8.0,Burn,WST:1006,Effect_Burn,5,M:skill_id;skill_name;skill_class;anim;next_anim;range_m;awaken2_extra;vfx;src_cool_ref;weapon_id;weapon_name;fr_ref,,,,
1071,현자의 지팡이,3,703304,화염 광선,Skill_Blizzard,skill3,skill3_end,3,18,0,8,8.0,Burn,WST:1006,Effect_Burn,5,PD#986 기본 스킬(마법 시전 뒤 3타 손 내지른 자세 + 전방 레이저 FX_Dragonfire 3 초 · 0.5 초 다단 · 0.2 m 밀침 · 방향 전환 · 구르기 취소 · 그릇 = 원본 눈보라 703304 + WLStaffLaser · 쿨 · 피해 = 지팡이 각성 값 그대로(해머 · 오브 기본 규칙) · 사거리 8 = 레이저 길이 · 이름 임시),,,,
1057,맹약,1,703303,에너지볼 난사,Skill_EnergyBall,casting,casting_end,5,7,0,10,3.6,Burn,WST:1005,Effect_Burn,5,M:skill_id;skill_name;skill_class;anim;next_anim;range_m;awaken2_extra;vfx;src_cool_ref;weapon_id;weapon_name;fr_ref,,,,
1057,맹약,2,703301,블랙홀,Skill_BlackHole,casting,casting_end,7,18,0,10,7.5,Burn,WST:1005,Effect_Burn,5,M:skill_id;skill_name;skill_class;anim;next_anim;range_m;awaken2_extra;vfx;src_cool_ref;weapon_id;weapon_name;fr_ref,,,,
1057,맹약,3,703305,전진 낙뢰,Skill_MeteoStorm,casting,casting_end,3,18,0,6,8.0,Burn,WST:1005,Effect_Burn,5,PD#983 기본 스킬(전방 = 대상 쪽 번개 3발 0.3 s 간격 전진 낙하 · 운석 소환 703305 직업 맞춤 복사본 + WLStaffEarth 10301 행(line · 번개 = MasterStylizedFX LightningExplosion 사본) · 쿨 · 피해 = 지팡이 각성 값 그대로(해머 기본 #975 와 같은 규칙) · 사거리 10 → 6 = 번개 줄 끝 5.1 m · 이름 임시),,,,

1 weapon_id weapon_name slot skill_id skill_name skill_class anim next_anim unlock_tier cool_s mp range_m dmg_ratio_base awaken2_extra fr_ref vfx src_cool_ref src wl_skill trigger dash_cast first_cast
10 1029 바람쐐기 2 703406 화살 비 Skill_ArrowRain archer_skill3 7 18 0 10 7.0 Slow WST:1003 Effect_Slow 5 M:skill_id;skill_name;skill_class;anim;next_anim;range_m;awaken2_extra;vfx;src_cool_ref;weapon_id;weapon_name;fr_ref
11 1071 현자의 지팡이 1 703306 번개 소용 돌이 Skill_Hurricane casting skill_cast2 5 7 0 5 2.4 Burn WST:1006 Effect_Burn 5 M:skill_id;skill_name;skill_class;anim;next_anim;range_m;awaken2_extra;vfx;src_cool_ref;weapon_id;weapon_name;fr_ref
12 1071 현자의 지팡이 2 703305 운석 소환 Skill_MeteoStorm casting casting_end 7 18 0 10 8.0 Burn WST:1006 Effect_Burn 5 M:skill_id;skill_name;skill_class;anim;next_anim;range_m;awaken2_extra;vfx;src_cool_ref;weapon_id;weapon_name;fr_ref
13 1071 현자의 지팡이 3 703304 화염 광선 Skill_Blizzard skill3 skill3_end 3 18 0 8 8.0 Burn WST:1006 Effect_Burn 5 PD#986 기본 스킬(마법 시전 뒤 3타 손 내지른 자세 + 전방 레이저 FX_Dragonfire 3 초 · 0.5 초 다단 · 0.2 m 밀침 · 방향 전환 · 구르기 취소 · 그릇 = 원본 눈보라 703304 + WLStaffLaser · 쿨 · 피해 = 지팡이 각성 값 그대로(해머 · 오브 기본 규칙) · 사거리 8 = 레이저 길이 · 이름 임시)
14 1057 맹약 1 703303 에너지볼 난사 Skill_EnergyBall casting casting_end 5 7 0 10 3.6 Burn WST:1005 Effect_Burn 5 M:skill_id;skill_name;skill_class;anim;next_anim;range_m;awaken2_extra;vfx;src_cool_ref;weapon_id;weapon_name;fr_ref
15 1057 맹약 2 703301 블랙홀 Skill_BlackHole casting casting_end 7 18 0 10 7.5 Burn WST:1005 Effect_Burn 5 M:skill_id;skill_name;skill_class;anim;next_anim;range_m;awaken2_extra;vfx;src_cool_ref;weapon_id;weapon_name;fr_ref
16 1057 맹약 3 703305 전진 낙뢰 Skill_MeteoStorm casting casting_end 3 18 0 6 8.0 Burn WST:1005 Effect_Burn 5 PD#983 기본 스킬(전방 = 대상 쪽 번개 3발 0.3 s 간격 전진 낙하 · 운석 소환 703305 직업 맞춤 복사본 + WLStaffEarth 10301 행(line · 번개 = MasterStylizedFX LightningExplosion 사본) · 쿨 · 피해 = 지팡이 각성 값 그대로(해머 기본 #975 와 같은 규칙) · 사거리 10 → 6 = 번개 줄 끝 5.1 m · 이름 임시)

View File

@ -66,6 +66,15 @@ namespace WL.Combat.Weapon
public float releaseShake = 0f, releaseShakeSeconds = 0.15f; // 수리검이 처음 나오는 순간 카메라 흔들림(진폭 · 0 = 없음 · 주파수 · 축 = WLHitFeelSettings)
public float hitShake = 0f, hitShakeSeconds = 0.08f; // 명중 섬광마다 카메라 흔들림
public float spinMul = 1f; // 수리검 제 축 회전(사본 AutoRotate) 배율
// #986 PD 「궤적이 의미 없이 어지럽게 보이는데, 비수가 날아가는 나선형 궤적으로 표현되도록 … 의미 없는 궤적은 숨기고 실제 비수가 날아가는 궤적만 꼬리처럼」
// trail 1 = 수리검마다 꼬리(TrailRenderer · 재질 = SlashTrailSettings.materialAdditive · 색 = 그 직업 무기 궤적 가산색 · 끝나도 꼬리가 다 사라질 때까지 수리검 자리 유지)
public int trail = 0;
public float trailSeconds = 0.22f, trailWidth = 0.3f, trailWidthEnd = 0f, trailAlpha = 0.9f;
public int trailClass = 0; // 색을 가져올 직업(0 = 시전자 직업)
// #986 PD 「캐릭터가 기모으기 포즈 후 투사체 이펙트가 발생될 때 한바퀴 회전하는 모션 … 이때 캐릭터에게 Simple Stylized Slash Pack 2 의 Slash_Aoe_A 재생」
public float spinSeconds = 0f, spinDir = 1f; // 시전자가 한 바퀴(360°) 도는 시간(0 = 없음) · 방향(1 = 위에서 볼 때 시계)
public string spinFx = ""; // 도는 순간 시전자 자리에 재생할 이펙트(Resources)
public float spinFxScale = 1f, spinFxLife = 1.2f, spinFxY = 0.6f;
public string note = "";
}
@ -75,9 +84,9 @@ namespace WL.Combat.Weapon
public static int Begun, MaxShown; public static string LastLog = "";
public static float MinY = float.MaxValue, MaxY = float.MinValue; // #979 측정용 — 수리검 높이(시전자 발 기준) 최소 · 최대
public static int Scattered; public static float MinR = float.MaxValue, MaxR; // #983 측정용 — scatter 로 나타난 수 · 나타난 자리 반지름 최소 · 최대
public static int PathEmitted, EndBursts, HitBursts, Shakes; public static float MaxReach; // #985 측정용 — 수리검 자리에서 뿜은 호 · 끝 터짐 · 명중 섬광 · 흔들림 · 시전자에서 가장 먼 거리
public static int PathEmitted, EndBursts, HitBursts, Shakes, Spins, SpinFxShown, Trails; public static float MaxReach; // #986 Spins · SpinFxShown · Trails(꼬리 붙인 수리검) // #985 측정용 — 수리검 자리에서 뿜은 호 · 끝 터짐 · 명중 섬광 · 흔들림 · 시전자에서 가장 먼 거리
static WLShurikenRiderJson s_cfg;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] static void Reset() { s_cfg = null; MinY = float.MaxValue; MaxY = float.MinValue; Scattered = 0; MinR = float.MaxValue; MaxR = 0f; PathEmitted = EndBursts = HitBursts = Shakes = 0; MaxReach = 0f; }
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] static void Reset() { s_cfg = null; MinY = float.MaxValue; MaxY = float.MinValue; Scattered = 0; MinR = float.MaxValue; MaxR = 0f; PathEmitted = EndBursts = HitBursts = Shakes = Spins = SpinFxShown = Trails = 0; MaxReach = 0f; }
internal static WLShurikenRiderJson Cfg
{
@ -118,6 +127,7 @@ namespace WL.Combat.Weapon
readonly List<GameObject> _riders = new List<GameObject>(); readonly Dictionary<uint, int> _bySeed = new Dictionary<uint, int>();
float _t0, _rim = 0.5f, _ground; bool _on; Transform _center; Actor _shooter;
bool _pathEmOff, _pathEmWas, _shook; float[] _emitAcc; bool[] _endDone; HashSet<long> _hitPairs = new HashSet<long>();
bool _spinning; float _spinT0, _spinYaw0; // #986 시전자 한 바퀴
public void Begin(ParticleSystem ps, WLShurikenRiderJson c, float ground, Transform center, Actor shooter)
{
@ -131,9 +141,15 @@ namespace WL.Combat.Weapon
_rim = m != null ? Mathf.Max(m.bounds.extents.x, m.bounds.extents.y) : 0.5f; // 호 메시 반지름(입자 크기 1 기준)
var p = Resources.Load<GameObject>(c.prefab);
int need = c.mode == "spiral" ? Mathf.Max(c.maxRiders, c.spiralCount) : c.mode == "scatter" ? Mathf.Max(c.maxRiders, c.scatterCount) : c.maxRiders;
if (c.spinSeconds > 0f && shooter != null) // #986 시전자 한 바퀴 + 회전 베기 이펙트
{
_spinning = true; _spinT0 = Time.time; _spinYaw0 = shooter.transform.eulerAngles.y; WLShurikenRider.Spins++;
if (Burst(c.spinFx, shooter.Get_position() + Vector3.up * c.spinFxY, c.spinFxScale, c.spinFxLife, shooter.transform.rotation)) WLShurikenRider.SpinFxShown++;
}
while (p != null && _riders.Count < need)
{
var g = Instantiate(p); g.SetActive(false); _riders.Add(g);
if (c.trail != 0) AddTrail(g, c);
if (!Mathf.Approximately(c.spinMul, 1f)) // #985 제 축 회전(사본의 팩 AutoRotate.RotateAngle) 배율 — 만들 때 1번
foreach (var mb in g.GetComponentsInChildren<MonoBehaviour>(true))
{
@ -168,6 +184,7 @@ namespace WL.Combat.Weapon
void LateUpdate()
{
if (_spinning) SpinTick();
if (!_on) return;
if (_ps == null || !_ps.gameObject.activeInHierarchy || Time.time - _t0 > _c.maxSeconds) { Stop(); return; }
if (_c.mode == "spiral") { Spiral(); return; }
@ -235,11 +252,18 @@ namespace WL.Combat.Weapon
if (!_sc[i].on)
{
float a = _sc[i].ang * Mathf.Deg2Rad; var dir = new Vector3(Mathf.Cos(a), 0f, Mathf.Sin(a));
_sc[i].pos = c0 + dir * _sc[i].r + Vector3.up * _sc[i].h; _sc[i].y0 = _sc[i].pos.y; _sc[i].head = _sc[i].ang + _sc[i].jit; _sc[i].on = true; g.SetActive(true);
_sc[i].pos = c0 + dir * _sc[i].r + Vector3.up * _sc[i].h; _sc[i].y0 = _sc[i].pos.y; _sc[i].head = _sc[i].ang + _sc[i].jit; _sc[i].on = true;
g.transform.position = _sc[i].pos; g.SetActive(true);
var tr0 = g.GetComponent<TrailRenderer>(); if (tr0 != null) { tr0.Clear(); tr0.emitting = true; } // #986 꼬리는 나타난 자리부터
WLShurikenRider.Scattered++; WLShurikenRider.MaxR = Mathf.Max(WLShurikenRider.MaxR, _sc[i].r); WLShurikenRider.MinR = Mathf.Min(WLShurikenRider.MinR, _sc[i].r);
}
float u = Mathf.Clamp01(ti / _sc[i].life);
if (ti > _sc[i].life) { _sc[i].done = true; g.SetActive(false); continue; }
if (ti > _sc[i].life)
{
var tr1 = g.GetComponent<TrailRenderer>(); // #986 꼬리가 다 사라질 때까지 마지막 자리에 크기 0 으로 남김(갑자기 끊기지 않게)
if (tr1 != null && ti < _sc[i].life + _c.trailSeconds) { if (tr1.emitting) { tr1.emitting = false; g.transform.localScale = Vector3.zero; } continue; }
_sc[i].done = true; g.SetActive(false); continue;
}
float turn = Mathf.Lerp(_c.scatterTurnStart, _c.scatterTurnEnd, u * u), spd = _c.scatterSpeed * Mathf.Lerp(1f, _c.scatterSpeedEnd, u);
_sc[i].head += _c.spiralDir * turn * dt; // 각도 증가 = 위에서 볼 때 반시계(spiral 과 같은 규칙)
float h = _sc[i].head * Mathf.Deg2Rad; var vel = new Vector3(Mathf.Cos(h), 0f, Mathf.Sin(h)) * spd;
@ -292,16 +316,41 @@ namespace WL.Combat.Weapon
}
static readonly Dictionary<string, GameObject> s_fx = new Dictionary<string, GameObject>();
static bool Burst(string path, Vector3 pos, float scale, float life)
static bool Burst(string path, Vector3 pos, float scale, float life) { return Burst(path, pos, scale, life, Quaternion.identity); }
static bool Burst(string path, Vector3 pos, float scale, float life, Quaternion rot)
{
if (string.IsNullOrEmpty(path)) return false; GameObject p;
if (!s_fx.TryGetValue(path, out p) || p == null) { p = Resources.Load<GameObject>(path); s_fx[path] = p; }
if (p == null) { WLShurikenRider.LastLog = "이펙트 없음 " + path; return false; }
var g = Instantiate(p, pos, Quaternion.identity); g.transform.localScale = p.transform.localScale * scale;
var g = Instantiate(p, pos, rot); g.transform.localScale = p.transform.localScale * scale;
foreach (var ps in g.GetComponentsInChildren<ParticleSystem>(true)) { var m = ps.main; m.scalingMode = ParticleSystemScalingMode.Hierarchy; }
Destroy(g, Mathf.Max(0.2f, life)); return true;
}
// #986 시전자 한 바퀴 — 처음 방향에서 spinDir × 360° 를 spinSeconds 동안(가속 · 감속) · 끝나면 처음 방향 그대로
void SpinTick()
{
if (_shooter == null || _c == null) { _spinning = false; return; }
float u = (Time.time - _spinT0) / Mathf.Max(0.05f, _c.spinSeconds);
if (u >= 1f) { _spinning = false; _shooter.transform.rotation = Quaternion.Euler(0f, _spinYaw0, 0f); return; }
_shooter.transform.rotation = Quaternion.Euler(0f, _spinYaw0 + _c.spinDir * 360f * Mathf.SmoothStep(0f, 1f, u), 0f);
}
// #986 꼬리 — 무기 궤적 가산 재질 · 그 직업 궤적 가산색(밝기 1 로 맞춤) · 투명도 trailAlpha → 0 · 폭 trailWidth → trailWidthEnd
void AddTrail(GameObject g, WLShurikenRiderJson c)
{
var st = WL.Combat.SlashTrailSettings.Instance; var mat = st != null ? st.materialAdditive : null;
if (mat == null) { WLShurikenRider.LastLog = "꼬리 재질 없음(SlashTrailSettings.materialAdditive)"; return; }
int cls = c.trailClass > 0 ? c.trailClass : (_shooter != null ? _shooter.Get_ID() : 0);
var o = st.FindOverride(cls); var col = o != null ? o.colorAdditive : Color.white;
float mx = Mathf.Max(1f, Mathf.Max(col.r, Mathf.Max(col.g, col.b))); col = new Color(col.r / mx, col.g / mx, col.b / mx, 1f);
var tr = g.GetComponent<TrailRenderer>(); if (tr == null) tr = g.AddComponent<TrailRenderer>();
tr.sharedMaterial = mat; tr.time = c.trailSeconds; tr.startWidth = c.trailWidth; tr.endWidth = c.trailWidthEnd; tr.minVertexDistance = 0.04f;
var gr = new Gradient(); gr.SetKeys(new[] { new GradientColorKey(col, 0f), new GradientColorKey(col, 1f) }, new[] { new GradientAlphaKey(c.trailAlpha, 0f), new GradientAlphaKey(0f, 1f) });
tr.colorGradient = gr; tr.emitting = false; tr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; tr.receiveShadows = false; tr.alignment = LineAlignment.View;
WLShurikenRider.Trails++;
}
static void Shake(float amp, float seconds)
{
var st = WL.Feel.WLHitFeel.Settings; var sh = WL.Feel.WLHitFeel.GetShaker(true); if (st == null || sh == null) return;
@ -321,7 +370,7 @@ namespace WL.Combat.Weapon
int FreeSlot() { for (int i = 0; i < _riders.Count; i++) if (!_bySeed.ContainsValue(i)) return i; return -1; }
ParticleSystemRenderer _pathRenderer;
void Stop() { _on = false; _bySeed.Clear(); _sc = null; if (_pathEmOff) { _pathEmOff = false; if (_ps != null) { var em = _ps.emission; em.enabled = _pathEmWas; } } if (_pathRenderer != null) { _pathRenderer.enabled = true; _pathRenderer = null; } foreach (var g in _riders) if (g != null) g.SetActive(false); WLShurikenRider.LastLog = "끝 · 최대 동시 " + WLShurikenRider.MaxShown; }
void Stop() { _on = false; _bySeed.Clear(); _sc = null; if (_spinning && _shooter != null) { _shooter.transform.rotation = Quaternion.Euler(0f, _spinYaw0, 0f); _spinning = false; } if (_pathEmOff) { _pathEmOff = false; if (_ps != null) { var em = _ps.emission; em.enabled = _pathEmWas; } } if (_pathRenderer != null) { _pathRenderer.enabled = true; _pathRenderer = null; } foreach (var g in _riders) if (g != null) g.SetActive(false); WLShurikenRider.LastLog = "끝 · 최대 동시 " + WLShurikenRider.MaxShown; }
void OnDisable() { Stop(); }
void OnDestroy() { foreach (var g in _riders) if (g != null) Destroy(g); }
}

View File

@ -0,0 +1,204 @@
// ─────────────────────────────────────────────────────────────────────────────
// WLStaffLaser.cs — 현자의 지팡이(10302) 기본 스킬: 전방 직선 레이저(화염 광선) 3 초 유지 · 0.5 초 간격 다단 피해 · 맞을 때마다 0.2 m 밀침 (#986 · 2026-10-26)
//
// PD 원문: 「지팡이 기본 스킬 시전 시 마법 시전 연출 후 지팡이 기본 공격 3타와 동일하게 손을 내지르는 모션과 함께 "RPG Game VFX Collection(URP)" 에셋의
// FX_Dragonfire 이펙트를 사용하게 해줘. 이 스킬은 전방 직선 방향으로 레이저 형태의 마법을 발사해 0.5초간격으로 다단히트 피해를 주며, 0.2m씩 적을
// 밀쳐낼 수 있으며 3초 동안 유지되고, 캐릭터가 방향을 변경할 경우 변경 된 방향으로 지속시간 동안 레이져 공격을 할 수 있어. (단, 구르기를 시도할 경우 마법이 즉시 취소)」
// ■ 그릇 = 원본 Skill_Blizzard(703304 · 시전 skill3 1 s · 지팡이 표 칸 3) — 원본 Set() 훅 1줄(Take)이 원본 눈보라 진행을 건너뛰고 넘겨받는다
// ■ 진행: 이동 막음 + 스킬 상태 → 다음 프레임 3타 자세(holdState · holdNormalized)로 애니메이터 멈춤(다른 상태로 바뀌면 다시 세움) → 손 앞(fxOffset)에 레이저(fx · 반복)를
// 시전자 정면으로 매 프레임 붙임 → interval 마다 정면 직선(length × width + 몸 반지름) 안 적에게 원본 투사체 피해(ProcessCollider) + 레이저 방향으로 push m 밀침 → seconds 뒤 끝
// ■ 방향 전환: 레이저 중엔 원본 CanMove() 가 막혀 조이스틱 이동(Run_byJoystick)이 안 불린다 → 러너가 매 프레임 가상패드 입력(섬 SimpleInput 축 · 테스트 씬 원본 FloatingJoystick · 편집기 방향키)을
// 카메라 정면 기준 방향으로 바꿔 몸만 turnDegPerSec 로 돌린다(이동 없음 · 레이저가 따라감)
// ■ 구르기 = 즉시 취소(시전자 상태가 Dodge 가 되면 레이저를 끄고 애니메이터 · 이동을 되돌린다)
// ■ 값 = Resources/WL/WLStaffLaser.json (C45) · enabled 0 = 원본 눈보라 그대로
// 🔴 Debug.LogError 금지(원본 팝업).
// ─────────────────────────────────────────────────────────────────────────────
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace WL.Combat.Weapon
{
[System.Serializable]
public class WLStaffLaserJson
{
public int enabled = 0;
public string skill = "Skill_Blizzard"; // 넘겨받을 원본 스킬 클래스 이름
public int classId = 10302; // 시전자 직업(0 = 모두)
public string fx = "WL/Fx/WL_Fx_StaffLaser"; // 레이저 이펙트(Resources · 원본 빔 축 = 로컬 -Y)
public float fxScale = 0.24f;
public float[] fxOffset = { 0f, 0.55f, 0.45f }; // 시전자 정면 기준 (오른쪽, 위, 앞) m — 내민 손 앞
public float[] fxEuler = { -90f, 0f, 0f }; // 시전자 정면 기준 회전(빔 -Y → 정면 +Z)
public float seconds = 3f, interval = 0.5f; // 유지 · 다단 간격(s) — 첫 피해는 레이저가 켜지는 순간
public float length = 8f, width = 1.2f; // 피해 직선(m · 시전자 발에서 정면 · 폭 = 전체 · 적 몸 반지름 더함)
public float push = 0.2f; // 맞을 때마다 레이저 방향 밀침(m)
public string holdState = "attack3"; // 손 내지른 자세(애니메이터 상태 · 지팡이 3타)
public float holdNormalized = 0.5f;
public float turnDegPerSec = 360f; // 가상패드 방향으로 도는 속도
public float steerDeadzone = 0.2f; // 가상패드 축 크기가 이보다 작으면 돌지 않음
public float fadeSeconds = 0.4f; // 끝 · 취소 때 방출을 멈추고 지우기까지
public string note = "";
}
public static class WLStaffLaser
{
public const string ResourcesPath = "WL/WLStaffLaser";
public static int Takes, Ticks, Hits, Pushes, Cancels, Turns, Reasserts, Ends; public static string LastLog = "";
static WLStaffLaserJson s_cfg; static WLStaffLaserRunner s_runner;
internal static PCActor Active; internal static WLStaffLaserJson ActiveCfg;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] static void Reset() { s_cfg = null; Active = null; ActiveCfg = null; }
internal static WLStaffLaserJson Cfg
{
get
{
if (s_cfg != null) return s_cfg;
s_cfg = new WLStaffLaserJson();
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>원본 Skill_Blizzard.Set 훅 — 규칙에 맞으면 레이저로 넘겨받는다(true = 원본 진행 건너뜀).</summary>
public static bool Take(ProjectileBase pb)
{
try
{
var c = Cfg; if (c.enabled == 0 || pb == null || pb.GetType().Name != c.skill) return false;
var pd = pb.Get_ProjectTileData(); var pc = pd != null ? pd.shooter as PCActor : null; if (pc == null) return false;
if (c.classId > 0 && pc.Get_ID() != c.classId) return false;
if (s_runner == null) { var go = new GameObject("[WL986] StaffLaser"); go.hideFlags = HideFlags.HideInHierarchy; Object.DontDestroyOnLoad(go); s_runner = go.AddComponent<WLStaffLaserRunner>(); }
s_runner.Begin(pb, pd, pc, c); Takes++;
return true;
}
catch (System.Exception ex) { LastLog = "넘겨받기 실패 — " + ex.Message; return false; }
}
/// <summary>레이저 중 그 방향으로 몸만 돌린다(러너가 가상패드 축을 읽어 부름).</summary>
public static bool Steer(PCActor pc, Vector3 dir)
{
if (Active == null || !ReferenceEquals(pc, Active) || ActiveCfg == null) return false;
dir.y = 0f; if (dir.sqrMagnitude < 1e-4f) return true;
var want = Quaternion.LookRotation(dir.normalized);
pc.transform.rotation = Quaternion.RotateTowards(pc.transform.rotation, want, ActiveCfg.turnDegPerSec * Time.deltaTime); Turns++;
return true;
}
}
internal sealed class WLStaffLaserRunner : MonoBehaviour
{
public void Begin(ProjectileBase pb, ProjectileData pd, PCActor pc, WLStaffLaserJson c) { StopAllCoroutines(); StartCoroutine(Run(pb, pd, pc, c)); }
static Vector3 V(float[] a) { return a != null && a.Length >= 3 ? new Vector3(a[0], a[1], a[2]) : Vector3.zero; }
IEnumerator Run(ProjectileBase pb, ProjectileData pd, PCActor pc, WLStaffLaserJson c)
{
// 원본 겉모습 · 판정 상자 · Update 끔(끝나면 되돌림 · 풀 재사용)
var ren = new List<Renderer>(); foreach (var x in pb.GetComponentsInChildren<Renderer>(true)) if (x.enabled) { x.enabled = false; ren.Add(x); }
var col = new List<Collider>(); foreach (var x in pb.GetComponentsInChildren<Collider>(true)) if (x.enabled) { x.enabled = false; col.Add(x); }
bool wasEnabled = pb.enabled; pb.enabled = false;
if (OptionInfo.Ins != null) OptionInfo.Ins.Set_PCMove(pc, false);
pc.Set_CurAnim(eAnim.Skill);
WLStaffLaser.Active = pc; WLStaffLaser.ActiveCfg = c;
yield return null; // 원본 시전 코루틴이 같은 프레임에 다음 동작을 틀 수 있어 한 프레임 뒤에 자세를 세운다
var an = pc.m_animation; float sp0 = an != null && an.speed > 0f ? an.speed : 1f;
Hold(an, c);
GameObject fx = null; var p = !string.IsNullOrEmpty(c.fx) ? Resources.Load<GameObject>(c.fx) : null;
if (p != null)
{
fx = Instantiate(p);
foreach (var ps in fx.GetComponentsInChildren<ParticleSystem>(true)) { var m = ps.main; m.scalingMode = ParticleSystemScalingMode.Hierarchy; m.loop = true; }
fx.transform.localScale = Vector3.one * c.fxScale; Place(fx, pc, c);
}
else WLStaffLaser.LastLog = "레이저 이펙트 없음 " + c.fx;
float t = 0f, next = 0f; bool canceled = false; int hits0 = WLStaffLaser.Hits;
while (t < c.seconds)
{
if (pc == null || pc.IsDead()) { canceled = true; break; }
if (pc.Get_CurAnim() == eAnim.Dodge) { canceled = true; WLStaffLaser.Cancels++; break; } // PD 「구르기를 시도할 경우 마법이 즉시 취소」
if (pc.Get_CurAnim() < eAnim.Skill) pc.Set_CurAnim(eAnim.Skill);
if (an != null && (!an.GetCurrentAnimatorStateInfo(0).IsName(c.holdState) || an.IsInTransition(0))) { Hold(an, c); WLStaffLaser.Reasserts++; }
else if (an != null && an.speed != 0f) an.speed = 0f;
SteerInput(pc, c);
if (fx != null) Place(fx, pc, c);
if (t >= next) { next += Mathf.Max(0.05f, c.interval); WLStaffLaser.Ticks++; Tick(pb, pc, c); }
yield return null; t += Time.deltaTime;
}
// 끝 · 취소 — 레이저 방출을 멈추고 흐려지게 · 애니메이터 · 이동 · 스킬 상태 되돌림 · 원본 투사체 끔
if (fx != null) { foreach (var ps in fx.GetComponentsInChildren<ParticleSystem>(true)) ps.Stop(true, ParticleSystemStopBehavior.StopEmitting); Destroy(fx, Mathf.Max(0.05f, c.fadeSeconds)); }
if (an != null && an.speed == 0f) an.speed = sp0;
WLStaffLaser.Active = null; WLStaffLaser.ActiveCfg = null;
if (OptionInfo.Ins != null && pc != null) OptionInfo.Ins.Set_PCMove(pc, true);
if (!canceled && pc != null && !pc.IsDead()) pc.Play_Idle();
if (pb != null) { pb.enabled = wasEnabled; WLStaffEarth.OffOriginal(pb); }
foreach (var x in ren) if (x != null) x.enabled = true;
foreach (var x in col) if (x != null) x.enabled = true;
WLStaffLaser.Ends++;
WLStaffLaser.LastLog = (canceled ? "취소 " : "끝 ") + t.ToString("F2") + " s · 다단 " + WLStaffLaser.Ticks + " · 이번 명중 " + (WLStaffLaser.Hits - hits0) + " · 밀침 " + WLStaffLaser.Pushes + " · 회전 입력 " + WLStaffLaser.Turns + " · 자세 다시 세움 " + WLStaffLaser.Reasserts;
}
// 가상패드 축(SimpleInput) → 카메라 정면 기준 수평 방향 → Steer(몸만 회전)
static void SteerInput(PCActor pc, WLStaffLaserJson c)
{
var a = PadAxis(); float h = a.x, v = a.y;
if (h * h + v * v < c.steerDeadzone * c.steerDeadzone) return;
var cam = Camera.main; var fwd = cam != null ? cam.transform.forward : Vector3.forward; fwd.y = 0f; if (fwd.sqrMagnitude < 1e-4f) fwd = Vector3.forward; fwd.Normalize();
WLStaffLaser.Steer(pc, fwd * v + Vector3.Cross(Vector3.up, fwd) * h);
}
// 가상패드 입력 — 섬 = SimpleInput 축(WLIslandAvatar) · 테스트 씬 = 원본 가상패드(Joystick Pack FloatingJoystick · global::Joystick.Direction) · 편집기 방향키 — 먼저 잡히는 것
static global::Joystick s_joy; static float s_joyFind;
static Vector2 PadAxis()
{
var a = Vector2.zero;
try { a = new Vector2(SimpleInput.GetAxis("Horizontal"), SimpleInput.GetAxis("Vertical")); } catch { }
if (a.sqrMagnitude < 1e-4f)
{
if (s_joy == null && Time.unscaledTime >= s_joyFind) { s_joy = Object.FindAnyObjectByType<global::Joystick>(); s_joyFind = Time.unscaledTime + 1f; }
if (s_joy != null && s_joy.isActiveAndEnabled) a = s_joy.Direction;
}
if (a.sqrMagnitude < 1e-4f) a = new Vector2((Input.GetKey(KeyCode.RightArrow) ? 1f : 0f) - (Input.GetKey(KeyCode.LeftArrow) ? 1f : 0f), (Input.GetKey(KeyCode.UpArrow) ? 1f : 0f) - (Input.GetKey(KeyCode.DownArrow) ? 1f : 0f));
return a;
}
static void Hold(Animator an, WLStaffLaserJson c)
{
if (an == null) return;
an.speed = 0f; an.Play(c.holdState, 0, Mathf.Clamp01(c.holdNormalized)); an.Update(0f);
}
static void Place(GameObject fx, PCActor pc, WLStaffLaserJson c)
{
var f = pc.transform.forward; f.y = 0f; if (f.sqrMagnitude < 1e-4f) f = Vector3.forward; var basis = Quaternion.LookRotation(f.normalized);
fx.transform.SetPositionAndRotation(pc.transform.position + basis * V(c.fxOffset), basis * Quaternion.Euler(V(c.fxEuler)));
}
// 정면 직선(시전자 발에서 length · 폭 width + 적 몸 반지름) 안 적 — 원본 투사체 피해 + 레이저 방향 밀침
static void Tick(ProjectileBase pb, PCActor pc, WLStaffLaserJson c)
{
var info = ActorInfo.Ins; if (info == null || pb == null) return;
var o = pc.Get_position(); var f = pc.transform.forward; f.y = 0f; if (f.sqrMagnitude < 1e-4f) return; f.Normalize();
var list = info.Get_EnemyActors(pc.IsEnemy(), o, c.length + 3f); if (list == null) return;
try
{
for (int k = 0; k < list.Count; k++)
{
var a = list[k]; if (a == null || a.IsDead()) continue;
var v = a.Get_position() - o; v.y = 0f; float along = Vector3.Dot(v, f), side = Mathf.Abs(Vector3.Cross(f, v).y), br = WL.Combat.WLCombatMotionSettings.BodyRadius(a);
if (along < -br || along > c.length + br || side > c.width * 0.5f + br) continue;
var cl = a.GetComponent<Collider>(); if (cl == null || !cl.enabled) continue;
if (!pb.ProcessCollider(cl, false)) continue; WLStaffLaser.Hits++;
if (c.push > 0f)
{
var d = f * c.push; var ag = a.GetComponent<UnityEngine.AI.NavMeshAgent>();
if (ag != null && ag.enabled && ag.isOnNavMesh) ag.Move(d); else a.transform.position += d;
WLStaffLaser.Pushes++;
}
}
}
finally { info.Release_Actors(list); }
}
}
}

View File

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