using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using Colosseum.Abnormalities;
using Colosseum.AI;
using Colosseum.Skills;
using Colosseum.Skills.Effects;
namespace Colosseum.Editor
{
///
/// 드로그 기획/패턴 문서를 기준으로 스킬/이펙트/패턴 플레이스홀더 자산을 재구성합니다.
/// 애니메이션이 아직 확정되지 않은 단계에서도 BT와 데이터 연결을 먼저 맞추는 용도입니다.
///
public static class RebuildDrogCombatAssets
{
private const string AnimationsFolder = "Assets/_Game/Animations";
private const string SkillsFolder = "Assets/_Game/Data/Skills";
private const string PatternsFolder = "Assets/_Game/Data/Patterns";
private const string EffectsFolder = "Assets/_Game/Data/Skills/Effects";
private const string ExecutionTelegraphAbnormalityPath = "Assets/_Game/Data/Abnormalities/Data_Abnormality_Drog_집행준비.asset";
private const string LightCombo01BSourcePath = "Assets/External/Animations/AnimationSwordCombat/Animations/Sidekick/Attack/LightCombo01/A_MOD_SWD_Attack_LightCombo01B_RM_Neut.fbx";
private const string HeavyCombo01BSourcePath = "Assets/External/Animations/AnimationSwordCombat/Animations/Sidekick/Attack/HeavyCombo01/A_MOD_SWD_Attack_HeavyCombo01B_RM_Neut.fbx";
private const string HeavyCombo01CSourcePath = "Assets/External/Animations/AnimationSwordCombat/Animations/Sidekick/Attack/HeavyCombo01/A_MOD_SWD_Attack_HeavyCombo01C_RM_Neut.fbx";
private const string ZweihanderAttack013SourcePath = "Assets/External/Animations/Knight_Zweihander_Animset/Animation/Attack/Root/Zweihander_Attack01_3_Root.FBX";
private const string PunchLSourcePath = "Assets/External/Animations/Mixamo/펀치L.fbx";
private const string PunchRSourcePath = "Assets/External/Animations/Mixamo/펀치R.fbx";
private const string KickRSourcePath = "Assets/External/Animations/Mixamo/킥R.fbx";
[MenuItem("Tools/Colosseum/Rebuild Drog Combat Assets")]
private static void Rebuild()
{
try
{
EnsureFolder("Assets/_Game");
EnsureFolder("Assets/_Game/Animations");
EnsureFolder("Assets/_Game/Data");
EnsureFolder("Assets/_Game/Data/Skills");
EnsureFolder("Assets/_Game/Data/Patterns");
EnsureFolder("Assets/_Game/Data/Skills/Effects");
DeleteLegacyComboAssets();
AbnormalityData executionTelegraph = AssetDatabase.LoadAssetAtPath(ExecutionTelegraphAbnormalityPath);
if (executionTelegraph == null)
{
Debug.LogError($"[DrogCombatAssets] 집행 전조 이상상태를 찾을 수 없습니다: {ExecutionTelegraphAbnormalityPath}");
return;
}
AnimationClip comboBasic1Hit1Clip0 = EnsureClipFromSource($"{AnimationsFolder}/Anim_Drog_콤보-기본기1_1_0.anim", $"{AnimationsFolder}/Anim_Drog_평타1R_0.anim");
AnimationClip comboBasic1Hit1Clip1 = EnsureClipFromSource($"{AnimationsFolder}/Anim_Drog_콤보-기본기1_1_1.anim", $"{AnimationsFolder}/Anim_Drog_평타1R_1.anim");
AnimationClip comboBasic1Hit2Clip = EnsureClipFromSource($"{AnimationsFolder}/Anim_Drog_콤보-기본기1_2_0.anim", LightCombo01BSourcePath, "A_MOD_SWD_Attack_LightCombo01B_RM_Neut");
SetSingleOnEffectEvent(comboBasic1Hit1Clip0, -1f);
SetSingleOnEffectEvent(comboBasic1Hit1Clip1, 0.30f);
SetSingleOnEffectEvent(comboBasic1Hit2Clip, 0.28f);
AnimationClip comboBasic2Hit1Clip0 = EnsureClipFromSource($"{AnimationsFolder}/Anim_Drog_콤보-기본기2_1_0.anim", $"{AnimationsFolder}/Anim_Drog_평타2R_0.anim");
AnimationClip comboBasic2Hit1Clip1 = EnsureClipFromSource($"{AnimationsFolder}/Anim_Drog_콤보-기본기2_1_1.anim", $"{AnimationsFolder}/Anim_Drog_평타2R_1.anim");
AnimationClip comboBasic2Hit1Clip2 = EnsureClipFromSource($"{AnimationsFolder}/Anim_Drog_콤보-기본기2_1_2.anim", $"{AnimationsFolder}/Anim_Drog_평타2R_2.anim");
AnimationClip comboBasic2Hit2Clip = EnsureClipFromSource($"{AnimationsFolder}/Anim_Drog_콤보-기본기2_2_0.anim", HeavyCombo01CSourcePath, "A_MOD_SWD_Attack_HeavyCombo01C_RM_Neut");
AnimationClip comboBasic3Hit1Clip = EnsureClipFromSource($"{AnimationsFolder}/Anim_Drog_콤보-기본기3_1_0.anim", PunchLSourcePath, "mixamo.com");
AnimationClip comboBasic3Hit2Clip = EnsureClipFromSource($"{AnimationsFolder}/Anim_Drog_콤보-기본기3_2_0.anim", PunchRSourcePath, "mixamo.com");
AnimationClip comboBasic3Hit3Clip = EnsureClipFromSource($"{AnimationsFolder}/Anim_Drog_콤보-기본기3_3_0.anim", KickRSourcePath, "mixamo.com");
AnimationClip comboSlamHit1Clip = EnsureClipFromSource($"{AnimationsFolder}/Anim_Drog_콤보-강타_1_0.anim", HeavyCombo01BSourcePath, "A_MOD_SWD_Attack_HeavyCombo01B_RM_Neut");
AnimationClip comboSlamHit2Clip = EnsureClipFromSource($"{AnimationsFolder}/Anim_Drog_콤보-강타_2_0.anim", LightCombo01BSourcePath, "A_MOD_SWD_Attack_LightCombo01B_RM_Neut");
AnimationClip slamClip = EnsureClipFromSource($"{AnimationsFolder}/Anim_Drog_강타_0.anim", $"{AnimationsFolder}/Anim_Drog_강타R_0.anim");
AnimationClip comboStompHit1Clip = EnsureClipFromSource($"{AnimationsFolder}/Anim_Drog_콤보-발구르기_1_0.anim", ZweihanderAttack013SourcePath, "Zweihander_Attack01_3_Root");
AnimationClip comboStompHit2Clip = EnsureClipFromSource($"{AnimationsFolder}/Anim_Drog_콤보-발구르기_2_0.anim", HeavyCombo01CSourcePath, "A_MOD_SWD_Attack_HeavyCombo01C_RM_Neut");
AnimationClip stompClip = EnsureClipFromSource($"{AnimationsFolder}/Anim_Drog_발구르기_0.anim", $"{AnimationsFolder}/Anim_Drog_발구르기_0.anim");
AnimationClip leapPrepareClip = EnsurePlaceholderClip($"{AnimationsFolder}/Anim_Drog_도약_준비_0.anim");
AnimationClip leapAirClip = EnsurePlaceholderClip($"{AnimationsFolder}/Anim_Drog_도약_공중_0.anim");
AnimationClip leapLandingClip = EnsurePlaceholderClip($"{AnimationsFolder}/Anim_Drog_도약_착지_0.anim");
AnimationClip stepClip = EnsurePlaceholderClip($"{AnimationsFolder}/Anim_Drog_밟기_0.anim");
AnimationClip throwClip = EnsurePlaceholderClip($"{AnimationsFolder}/Anim_Drog_투척_0.anim");
AnimationClip roarClip = EnsurePlaceholderClip($"{AnimationsFolder}/Anim_Drog_포효_0.anim");
AnimationClip executionReadyClip = EnsurePlaceholderClip($"{AnimationsFolder}/Anim_Drog_집행_준비_0.anim");
AnimationClip executionHit1Clip = EnsurePlaceholderClip($"{AnimationsFolder}/Anim_Drog_집행_연타1_0.anim");
AnimationClip executionHit2Clip = EnsurePlaceholderClip($"{AnimationsFolder}/Anim_Drog_집행_연타2_0.anim");
AnimationClip executionHit3Clip = EnsurePlaceholderClip($"{AnimationsFolder}/Anim_Drog_집행_연타3_0.anim");
DamageEffect comboBasic1Hit1Damage = CreateDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_콤보-기본기1_1_0_데미지.asset",
22f,
DamageType.Physical,
0.65f,
AreaShapeType.Fan,
3.25f,
1.25f,
3.25f,
42f,
AreaCenterType.Caster);
DamageEffect comboBasic1Hit2Damage = CreateDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_콤보-기본기1_2_0_데미지.asset",
16f,
DamageType.Physical,
0.5f,
AreaShapeType.Fan,
3.3f,
1.25f,
3.3f,
40f,
AreaCenterType.Caster);
DamageEffect comboBasic2Hit1Damage = CreateDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_콤보-기본기2_1_0_데미지.asset",
26f,
DamageType.Physical,
0.8f,
AreaShapeType.Fan,
3.5f,
1.35f,
3.5f,
46f,
AreaCenterType.Caster);
DamageEffect comboBasic2Hit2Damage = CreateDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_콤보-기본기2_2_0_데미지.asset",
20f,
DamageType.Physical,
0.6f,
AreaShapeType.Fan,
3.6f,
1.35f,
3.6f,
42f,
AreaCenterType.Caster);
DamageEffect slamDamage = CreateDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_강타_0_데미지.asset",
48f,
DamageType.Physical,
1.15f,
AreaShapeType.Fan,
3.4f,
1.2f,
3.4f,
32f,
AreaCenterType.Caster);
DownEffect slamDown = CreateDownEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_강타_1_다운.asset",
1.8f,
AreaShapeType.Fan,
3.4f,
1.2f,
3.4f,
32f,
AreaCenterType.Caster);
DamageEffect comboBasic3Hit1Damage = CreateDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_콤보-기본기3_1_0_데미지.asset",
12f,
DamageType.Physical,
0.35f,
AreaShapeType.Fan,
2.6f,
1.1f,
2.6f,
55f,
AreaCenterType.Caster);
DamageEffect comboBasic3Hit2Damage = CreateDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_콤보-기본기3_2_0_데미지.asset",
12f,
DamageType.Physical,
0.35f,
AreaShapeType.Fan,
2.6f,
1.1f,
2.6f,
55f,
AreaCenterType.Caster);
DamageEffect comboBasic3Hit3Damage = CreateDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_콤보-기본기3_3_0_데미지.asset",
18f,
DamageType.Physical,
0.55f,
AreaShapeType.Fan,
3.1f,
1.15f,
3.1f,
68f,
AreaCenterType.Caster);
DamageEffect comboSlamHit1Damage = CreateDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_콤보-강타_1_0_데미지.asset",
20f,
DamageType.Physical,
0.6f,
AreaShapeType.Fan,
3.6f,
1.3f,
3.6f,
52f,
AreaCenterType.Caster);
DamageEffect comboSlamHit2Damage = CreateDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_콤보-강타_2_0_데미지.asset",
16f,
DamageType.Physical,
0.45f,
AreaShapeType.Fan,
3.2f,
1.15f,
3.2f,
42f,
AreaCenterType.Caster);
DamageEffect comboStompHit1Damage = CreateDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_콤보-발구르기_1_0_데미지.asset",
22f,
DamageType.Physical,
0.65f,
AreaShapeType.Fan,
3.9f,
1.35f,
3.9f,
60f,
AreaCenterType.Caster);
DamageEffect comboStompHit2Damage = CreateDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_콤보-발구르기_2_0_데미지.asset",
18f,
DamageType.Physical,
0.5f,
AreaShapeType.Fan,
3.6f,
1.25f,
3.6f,
44f,
AreaCenterType.Caster);
DamageEffect stompDamage = CreateDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_발구르기_0_데미지.asset",
22f,
DamageType.Physical,
0.65f,
AreaShapeType.Sphere,
4.75f,
1f,
4.75f,
180f,
AreaCenterType.Caster);
StaggerEffect stompStagger = CreateStaggerEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_발구르기_1_경직.asset",
0.35f,
true,
1f,
AreaShapeType.Sphere,
4.75f,
1f,
4.75f,
180f,
AreaCenterType.Caster);
DamageEffect leapLandingDamage = CreateDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_도약_착지_0_데미지.asset",
34f,
DamageType.Physical,
0.95f,
AreaShapeType.Sphere,
4.2f,
1f,
4.2f,
180f,
AreaCenterType.Caster);
KnockbackEffect leapLandingKnockback = CreateKnockbackEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_도약_착지_1_넉백.asset",
8f,
2f,
0.25f,
true,
1f,
AreaShapeType.Sphere,
4.2f,
1f,
4.2f,
180f,
AreaCenterType.Caster);
HitReactionDamageEffect stepDamage = CreateHitReactionDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_밟기_0_피격가중데미지.asset",
52f,
DamageType.Physical,
1.1f,
1.6f,
AreaShapeType.Sphere,
2.8f,
1f,
2.8f,
180f,
AreaCenterType.Caster);
KnockbackEffect stepKnockback = CreateKnockbackEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_밟기_1_넉백.asset",
5f,
1f,
0.18f,
true,
1f,
AreaShapeType.Sphere,
2.8f,
1f,
2.8f,
180f,
AreaCenterType.Caster);
DamageEffect throwDamage = CreateDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_투척_0_데미지.asset",
28f,
DamageType.Physical,
0.7f,
AreaShapeType.Beam,
12f,
1.2f,
0.75f,
0f,
AreaCenterType.Caster);
DamageEffect executionHit1 = CreateDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_집행_연타1_0_데미지.asset",
14f,
DamageType.Physical,
0.35f,
AreaShapeType.Sphere,
8.5f,
1f,
8.5f,
180f,
AreaCenterType.Caster);
DamageEffect executionHit2 = CreateDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_집행_연타2_0_데미지.asset",
17f,
DamageType.Physical,
0.4f,
AreaShapeType.Sphere,
8.5f,
1f,
8.5f,
180f,
AreaCenterType.Caster);
DamageEffect executionHit3 = CreateDamageEffect(
$"{EffectsFolder}/Data_SkillEffect_Drog_집행_연타3_0_데미지.asset",
20f,
DamageType.Physical,
0.45f,
AreaShapeType.Sphere,
8.5f,
1f,
8.5f,
180f,
AreaCenterType.Caster);
SkillData comboBasic1Hit1Skill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_콤보-기본기1_1.asset",
"콤보-기본기1 1타",
"기본기 콤보1의 첫 타격입니다.",
new[] { comboBasic1Hit1Clip0, comboBasic1Hit1Clip1 },
1f,
SkillCastTargetTrackingMode.FaceTarget,
true,
true,
false,
comboBasic1Hit1Damage);
SkillData comboBasic1Hit2Skill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_콤보-기본기1_2.asset",
"콤보-기본기1 2타",
"기본기 콤보1의 후속 타격입니다.",
new[] { comboBasic1Hit2Clip },
1f,
SkillCastTargetTrackingMode.FaceTarget,
true,
true,
false,
comboBasic1Hit2Damage);
SkillData comboBasic2Hit1Skill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_콤보-기본기2_1.asset",
"콤보-기본기2 1타",
"기본기 콤보2의 시작 타격입니다.",
new[] { comboBasic2Hit1Clip0, comboBasic2Hit1Clip1, comboBasic2Hit1Clip2 },
1f,
SkillCastTargetTrackingMode.FaceTarget,
true,
true,
false,
comboBasic2Hit1Damage);
SkillData comboBasic2Hit2Skill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_콤보-기본기2_2.asset",
"콤보-기본기2 2타",
"기본기 콤보2의 마무리 타격입니다.",
new[] { comboBasic2Hit2Clip },
1f,
SkillCastTargetTrackingMode.FaceTarget,
true,
true,
false,
comboBasic2Hit2Damage);
SkillData slamSkill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_강타.asset",
"강타",
"정면 관리 실패를 응징하는 강한 일격입니다.",
new[] { slamClip },
1f,
SkillCastTargetTrackingMode.FaceTarget,
true,
true,
false,
slamDamage,
slamDown);
SkillData comboBasic3Hit1Skill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_콤보-기본기3_1.asset",
"콤보-기본기3 1타",
"기본기 콤보3의 첫 번째 타격입니다.",
new[] { comboBasic3Hit1Clip },
1f,
SkillCastTargetTrackingMode.FaceTarget,
true,
true,
false,
comboBasic3Hit1Damage);
SkillData comboBasic3Hit2Skill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_콤보-기본기3_2.asset",
"콤보-기본기3 2타",
"기본기 콤보3의 두 번째 타격입니다.",
new[] { comboBasic3Hit2Clip },
1f,
SkillCastTargetTrackingMode.FaceTarget,
true,
true,
false,
comboBasic3Hit2Damage);
SkillData comboBasic3Hit3Skill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_콤보-기본기3_3.asset",
"콤보-기본기3 3타",
"기본기 콤보3의 발차기 마무리입니다.",
new[] { comboBasic3Hit3Clip },
1f,
SkillCastTargetTrackingMode.FaceTarget,
true,
true,
false,
comboBasic3Hit3Damage);
SkillData comboSlamHit1Skill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_콤보-강타_1.asset",
"콤보-강타 1타",
"강타 콤보의 첫 선행 타격입니다.",
new[] { comboSlamHit1Clip },
1f,
SkillCastTargetTrackingMode.FaceTarget,
true,
true,
false,
comboSlamHit1Damage);
SkillData comboSlamHit2Skill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_콤보-강타_2.asset",
"콤보-강타 2타",
"강타로 이어지는 두 번째 선행 타격입니다.",
new[] { comboSlamHit2Clip },
1f,
SkillCastTargetTrackingMode.FaceTarget,
true,
true,
false,
comboSlamHit2Damage);
SkillData comboStompHit1Skill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_콤보-발구르기_1.asset",
"콤보-발구르기 1타",
"발구르기 콤보의 첫 선행 타격입니다.",
new[] { comboStompHit1Clip },
1f,
SkillCastTargetTrackingMode.FaceTarget,
true,
true,
false,
comboStompHit1Damage);
SkillData comboStompHit2Skill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_콤보-발구르기_2.asset",
"콤보-발구르기 2타",
"발구르기로 연결되는 두 번째 선행 타격입니다.",
new[] { comboStompHit2Clip },
1f,
SkillCastTargetTrackingMode.FaceTarget,
true,
true,
false,
comboStompHit2Damage);
SkillData stompSkill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_발구르기.asset",
"발구르기",
"근접 측후방 전체를 흔드는 광역 압박입니다.",
new[] { stompClip },
1f,
SkillCastTargetTrackingMode.None,
true,
true,
false,
stompDamage,
stompStagger);
SkillData leapPrepareSkill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_도약_준비.asset",
"도약 준비",
"원거리 이탈 대상에게 시선을 고정합니다.",
new[] { leapPrepareClip },
1f,
SkillCastTargetTrackingMode.FaceTarget,
false,
true,
false);
SkillData leapAirSkill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_도약_공중.asset",
"도약 공중",
"대상 위치로 도약하는 이동 스텝입니다.",
new[] { leapAirClip },
1f,
SkillCastTargetTrackingMode.MoveTowardTarget,
true,
false,
true);
SkillData leapLandingSkill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_도약_착지.asset",
"도약 착지",
"도약 종료 시 주변에 피해와 넉백을 줍니다.",
new[] { leapLandingClip },
1f,
SkillCastTargetTrackingMode.None,
false,
true,
false,
leapLandingDamage,
leapLandingKnockback);
SkillData stepSkill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_밟기.asset",
"밟기",
"다운된 대상을 후속 압박으로 처벌합니다.",
new[] { stepClip },
1f,
SkillCastTargetTrackingMode.FaceTarget,
false,
true,
false,
stepDamage,
stepKnockback);
SkillData throwSkill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_투척.asset",
"투척",
"부활 시전자나 원거리 대상을 견제하는 유틸리티 공격입니다.",
new[] { throwClip },
1f,
SkillCastTargetTrackingMode.FaceTarget,
false,
true,
false,
throwDamage);
SkillData roarSkill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_포효.asset",
"포효",
"Phase 3 진입을 알리는 전환 신호입니다.",
new[] { roarClip },
0.9f,
SkillCastTargetTrackingMode.None,
false,
true,
false);
SkillData executionReadySkill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_집행_준비.asset",
"집행 준비",
"집행 돌입 전 자세를 고정합니다.",
new[] { executionReadyClip },
0.85f,
SkillCastTargetTrackingMode.None,
false,
true,
false);
SkillData executionHit1Skill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_집행_연타1.asset",
"집행 연타1",
"집행의 첫 압박 타격입니다.",
new[] { executionHit1Clip },
1f,
SkillCastTargetTrackingMode.None,
false,
true,
false,
executionHit1);
SkillData executionHit2Skill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_집행_연타2.asset",
"집행 연타2",
"집행의 두 번째 압박 타격입니다.",
new[] { executionHit2Clip },
1.1f,
SkillCastTargetTrackingMode.None,
false,
true,
false,
executionHit2);
SkillData executionHit3Skill = CreateSkill(
$"{SkillsFolder}/Data_Skill_Drog_집행_연타3.asset",
"집행 연타3",
"집행의 세 번째 압박 타격입니다.",
new[] { executionHit3Clip },
1.2f,
SkillCastTargetTrackingMode.None,
false,
true,
false,
executionHit3);
CreatePattern(
$"{PatternsFolder}/Data_Pattern_Drog_콤보-기본기1.asset",
"콤보-기본기1",
PatternCategory.Basic,
false,
true,
TargetResolveMode.HighestThreat,
2.5f,
1,
false,
PatternStepDefinition.CreateSkillStep(comboBasic1Hit1Skill),
PatternStepDefinition.CreateSkillStep(comboBasic1Hit2Skill));
CreatePattern(
$"{PatternsFolder}/Data_Pattern_Drog_콤보-기본기2.asset",
"콤보-기본기2",
PatternCategory.Basic,
false,
true,
TargetResolveMode.HighestThreat,
3f,
1,
false,
PatternStepDefinition.CreateSkillStep(comboBasic2Hit1Skill),
PatternStepDefinition.CreateSkillStep(comboBasic2Hit2Skill));
CreatePattern(
$"{PatternsFolder}/Data_Pattern_Drog_콤보-기본기3.asset",
"콤보-기본기3",
PatternCategory.Basic,
false,
true,
TargetResolveMode.HighestThreat,
3.25f,
1,
false,
PatternStepDefinition.CreateSkillStep(comboBasic3Hit1Skill),
PatternStepDefinition.CreateSkillStep(comboBasic3Hit2Skill),
PatternStepDefinition.CreateSkillStep(comboBasic3Hit3Skill));
CreatePattern(
$"{PatternsFolder}/Data_Pattern_Drog_콤보-강타.asset",
"콤보-강타",
PatternCategory.Basic,
false,
true,
TargetResolveMode.HighestThreat,
4.5f,
1,
false,
PatternStepDefinition.CreateSkillStep(comboSlamHit1Skill),
PatternStepDefinition.CreateSkillStep(comboSlamHit2Skill),
PatternStepDefinition.CreateWaitStep(0.1f),
PatternStepDefinition.CreateSkillStep(slamSkill));
CreatePattern(
$"{PatternsFolder}/Data_Pattern_Drog_콤보-발구르기.asset",
"콤보-발구르기",
PatternCategory.Basic,
false,
true,
TargetResolveMode.HighestThreat,
5f,
1,
false,
PatternStepDefinition.CreateSkillStep(comboStompHit1Skill),
PatternStepDefinition.CreateSkillStep(comboStompHit2Skill),
PatternStepDefinition.CreateWaitStep(0.1f),
PatternStepDefinition.CreateSkillStep(stompSkill));
CreatePattern(
$"{PatternsFolder}/Data_Pattern_Drog_밟기.asset",
"밟기",
PatternCategory.Punish,
false,
false,
TargetResolveMode.HighestThreat,
2.5f,
2,
false,
PatternStepDefinition.CreateSkillStep(stepSkill));
CreatePattern(
$"{PatternsFolder}/Data_Pattern_Drog_도약.asset",
"도약",
PatternCategory.Big,
false,
false,
TargetResolveMode.Mobility,
8f,
2,
false,
PatternStepDefinition.CreateSkillStep(leapPrepareSkill),
PatternStepDefinition.CreateWaitStep(0.1f),
PatternStepDefinition.CreateSkillStep(leapAirSkill),
PatternStepDefinition.CreateWaitStep(0.1f),
PatternStepDefinition.CreateSkillStep(leapLandingSkill));
CreatePattern(
$"{PatternsFolder}/Data_Pattern_Drog_투척.asset",
"투척",
PatternCategory.Basic,
false,
false,
TargetResolveMode.Utility,
10f,
2,
false,
PatternStepDefinition.CreateSkillStep(throwSkill));
CreatePattern(
$"{PatternsFolder}/Data_Pattern_Drog_집행.asset",
"집행",
PatternCategory.Big,
true,
false,
TargetResolveMode.HighestThreat,
45f,
3,
false,
PatternStepDefinition.CreateSkillStep(executionReadySkill),
PatternStepDefinition.CreateChargeWaitStep(2.25f, executionTelegraph, 0.1f, 2f),
PatternStepDefinition.CreateSkillStep(executionHit1Skill),
PatternStepDefinition.CreateWaitStep(0.65f),
PatternStepDefinition.CreateSkillStep(executionHit2Skill),
PatternStepDefinition.CreateWaitStep(0.45f),
PatternStepDefinition.CreateSkillStep(executionHit3Skill));
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
Debug.Log("[DrogCombatAssets] 드로그 스킬/이펙트/패턴 플레이스홀더 자산 재구성이 완료되었습니다.");
}
catch (Exception exception)
{
Debug.LogException(exception);
}
}
///
/// 폴더가 없으면 생성합니다.
///
private static void EnsureFolder(string path)
{
if (AssetDatabase.IsValidFolder(path))
return;
string parent = Path.GetDirectoryName(path)?.Replace('\\', '/');
if (string.IsNullOrEmpty(parent))
return;
EnsureFolder(parent);
AssetDatabase.CreateFolder(parent, Path.GetFileName(path));
}
///
/// 이전 단일 스킬 기반 콤보 자산을 제거합니다.
///
private static void DeleteLegacyComboAssets()
{
string[] legacyPaths =
{
$"{AnimationsFolder}/Anim_Drog_콤보-기본기1_0.anim",
$"{AnimationsFolder}/Anim_Drog_콤보-기본기2_0.anim",
$"{AnimationsFolder}/Anim_Drog_콤보-기본기3_0.anim",
$"{AnimationsFolder}/Anim_Drog_콤보-발구르기_선행_0.anim",
$"{SkillsFolder}/Data_Skill_Drog_콤보-기본기1.asset",
$"{SkillsFolder}/Data_Skill_Drog_콤보-기본기2.asset",
$"{SkillsFolder}/Data_Skill_Drog_콤보-기본기3.asset",
$"{SkillsFolder}/Data_Skill_Drog_콤보-발구르기_선행.asset",
$"{EffectsFolder}/Data_SkillEffect_Drog_콤보-기본기1_0_데미지.asset",
$"{EffectsFolder}/Data_SkillEffect_Drog_콤보-기본기2_0_데미지.asset",
$"{EffectsFolder}/Data_SkillEffect_Drog_콤보-기본기3_0_데미지.asset",
$"{EffectsFolder}/Data_SkillEffect_Drog_콤보-발구르기_선행_0_데미지.asset",
};
for (int i = 0; i < legacyPaths.Length; i++)
{
if (AssetDatabase.LoadMainAssetAtPath(legacyPaths[i]) == null)
continue;
AssetDatabase.DeleteAsset(legacyPaths[i]);
}
}
///
/// 지정 경로의 ScriptableObject를 읽거나 새로 생성합니다.
///
private static T LoadOrCreateAsset(string path) where T : ScriptableObject
{
T asset = AssetDatabase.LoadAssetAtPath(path);
if (asset != null)
return asset;
asset = ScriptableObject.CreateInstance();
asset.name = Path.GetFileNameWithoutExtension(path);
AssetDatabase.CreateAsset(asset, path);
return asset;
}
///
/// 드로그 스킬 플레이스홀더용 빈 애니메이션 클립을 보장합니다.
///
private static AnimationClip EnsurePlaceholderClip(string path)
{
AnimationClip clip = AssetDatabase.LoadAssetAtPath(path);
if (clip != null)
return clip;
clip = new AnimationClip
{
name = Path.GetFileNameWithoutExtension(path),
frameRate = 60f,
};
AssetDatabase.CreateAsset(clip, path);
return clip;
}
///
/// 소스 클립을 독립 .anim 자산으로 복제하거나 기존 자산을 갱신합니다.
///
private static AnimationClip EnsureClipFromSource(string targetPath, string sourcePath, string sourceClipName = null)
{
AnimationClip sourceClip = LoadClipFromPath(sourcePath, sourceClipName);
if (sourceClip == null)
{
Debug.LogWarning($"[DrogCombatAssets] 소스 클립을 찾지 못해 플레이스홀더를 유지합니다: {sourcePath} ({sourceClipName})");
return EnsurePlaceholderClip(targetPath);
}
AnimationClip clonedClip = CloneClip(sourceClip, Path.GetFileNameWithoutExtension(targetPath));
AnimationClip existingClip = AssetDatabase.LoadAssetAtPath(targetPath);
if (existingClip == null)
{
AssetDatabase.CreateAsset(clonedClip, targetPath);
return clonedClip;
}
EditorUtility.CopySerialized(clonedClip, existingClip);
existingClip.name = Path.GetFileNameWithoutExtension(targetPath);
EditorUtility.SetDirty(existingClip);
UnityEngine.Object.DestroyImmediate(clonedClip);
return existingClip;
}
///
/// 경로에서 AnimationClip을 읽습니다. FBX인 경우 지정 이름의 서브 클립을 우선 사용합니다.
///
private static AnimationClip LoadClipFromPath(string path, string preferredClipName = null)
{
AnimationClip directClip = AssetDatabase.LoadAssetAtPath(path);
if (directClip != null && (string.IsNullOrEmpty(preferredClipName) || directClip.name == preferredClipName))
return directClip;
UnityEngine.Object[] subAssets = AssetDatabase.LoadAllAssetsAtPath(path);
AnimationClip fallbackClip = null;
for (int i = 0; i < subAssets.Length; i++)
{
if (subAssets[i] is not AnimationClip clip)
continue;
if (!string.IsNullOrEmpty(preferredClipName) && clip.name == preferredClipName)
return clip;
if (fallbackClip == null && !clip.name.StartsWith("__preview__", StringComparison.Ordinal))
fallbackClip = clip;
}
return fallbackClip;
}
///
/// 소스 클립의 커브와 이벤트를 복사한 독립 AnimationClip을 생성합니다.
///
private static AnimationClip CloneClip(AnimationClip sourceClip, string targetName)
{
AnimationClip clonedClip = new AnimationClip
{
name = targetName,
frameRate = sourceClip.frameRate,
legacy = sourceClip.legacy,
wrapMode = sourceClip.wrapMode,
localBounds = sourceClip.localBounds,
};
EditorCurveBinding[] bindings = AnimationUtility.GetCurveBindings(sourceClip);
for (int i = 0; i < bindings.Length; i++)
{
AnimationCurve curve = AnimationUtility.GetEditorCurve(sourceClip, bindings[i]);
if (curve == null || curve.keys.Length == 0)
continue;
clonedClip.SetCurve(bindings[i].path, bindings[i].type, bindings[i].propertyName, curve);
}
AnimationEvent[] sourceEvents = AnimationUtility.GetAnimationEvents(sourceClip);
if (sourceEvents.Length > 0)
{
var clonedEvents = new AnimationEvent[sourceEvents.Length];
for (int i = 0; i < sourceEvents.Length; i++)
{
clonedEvents[i] = new AnimationEvent
{
time = sourceEvents[i].time,
functionName = sourceEvents[i].functionName,
floatParameter = sourceEvents[i].floatParameter,
intParameter = sourceEvents[i].intParameter,
stringParameter = sourceEvents[i].stringParameter,
objectReferenceParameter = sourceEvents[i].objectReferenceParameter,
messageOptions = sourceEvents[i].messageOptions,
};
}
AnimationUtility.SetAnimationEvents(clonedClip, clonedEvents);
}
return clonedClip;
}
///
/// Effect/Skill/Pattern의 공통 Object 리스트를 설정합니다.
///
private static void SetObjectList(SerializedObject serializedObject, string propertyName, IReadOnlyList values)
{
SerializedProperty listProperty = serializedObject.FindProperty(propertyName);
listProperty.arraySize = values != null ? values.Count : 0;
for (int i = 0; i < listProperty.arraySize; i++)
{
listProperty.GetArrayElementAtIndex(i).objectReferenceValue = values[i];
}
}
///
/// 지정한 클립에 단일 OnEffect(0) 이벤트를 설정합니다. 음수 시간이면 이벤트를 비웁니다.
///
private static void SetSingleOnEffectEvent(AnimationClip clip, float time)
{
if (clip == null)
return;
if (time < 0f)
{
AnimationUtility.SetAnimationEvents(clip, Array.Empty());
EditorUtility.SetDirty(clip);
return;
}
float clampedTime = Mathf.Clamp(time, 0f, Mathf.Max(0f, clip.length - 0.01f));
AnimationUtility.SetAnimationEvents(clip, new[]
{
new AnimationEvent
{
time = clampedTime,
functionName = "OnEffect",
intParameter = 0,
},
});
EditorUtility.SetDirty(clip);
}
///
/// 범위형 효과의 공통 판정 설정을 적용합니다.
///
private static void ConfigureAreaEffect(
SerializedObject serializedObject,
AreaShapeType areaShape,
float areaRadius,
float fanOriginDistance,
float fanRadius,
float fanHalfAngle,
AreaCenterType areaCenter)
{
serializedObject.FindProperty("targetType").enumValueIndex = (int)TargetType.Area;
serializedObject.FindProperty("targetTeam").enumValueIndex = (int)TargetTeam.Enemy;
serializedObject.FindProperty("areaCenter").enumValueIndex = (int)areaCenter;
serializedObject.FindProperty("areaShape").enumValueIndex = (int)areaShape;
serializedObject.FindProperty("targetLayers").intValue = Physics.AllLayers;
serializedObject.FindProperty("includeCasterInArea").boolValue = false;
serializedObject.FindProperty("areaRadius").floatValue = areaRadius;
serializedObject.FindProperty("fanOriginDistance").floatValue = fanOriginDistance;
serializedObject.FindProperty("fanRadius").floatValue = fanRadius;
serializedObject.FindProperty("fanHalfAngle").floatValue = fanHalfAngle;
}
///
/// 범위 피해 효과를 생성하거나 갱신합니다.
///
private static DamageEffect CreateDamageEffect(
string path,
float baseDamage,
DamageType damageType,
float statScaling,
AreaShapeType areaShape,
float areaRadius,
float fanOriginDistance,
float fanRadius,
float fanHalfAngle,
AreaCenterType areaCenter)
{
DamageEffect effect = LoadOrCreateAsset(path);
SerializedObject serializedObject = new SerializedObject(effect);
ConfigureAreaEffect(serializedObject, areaShape, areaRadius, fanOriginDistance, fanRadius, fanHalfAngle, areaCenter);
serializedObject.FindProperty("baseDamage").floatValue = baseDamage;
serializedObject.FindProperty("damageType").enumValueIndex = (int)damageType;
serializedObject.FindProperty("statScaling").floatValue = statScaling;
serializedObject.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(effect);
return effect;
}
///
/// 범위 다운 효과를 생성하거나 갱신합니다.
///
private static DownEffect CreateDownEffect(
string path,
float duration,
AreaShapeType areaShape,
float areaRadius,
float fanOriginDistance,
float fanRadius,
float fanHalfAngle,
AreaCenterType areaCenter)
{
DownEffect effect = LoadOrCreateAsset(path);
SerializedObject serializedObject = new SerializedObject(effect);
ConfigureAreaEffect(serializedObject, areaShape, areaRadius, fanOriginDistance, fanRadius, fanHalfAngle, areaCenter);
serializedObject.FindProperty("duration").floatValue = duration;
serializedObject.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(effect);
return effect;
}
///
/// 범위 넉백 효과를 생성하거나 갱신합니다.
///
private static KnockbackEffect CreateKnockbackEffect(
string path,
float force,
float upwardForce,
float duration,
bool playHitAnimation,
float hitAnimationSpeedMultiplier,
AreaShapeType areaShape,
float areaRadius,
float fanOriginDistance,
float fanRadius,
float fanHalfAngle,
AreaCenterType areaCenter)
{
KnockbackEffect effect = LoadOrCreateAsset(path);
SerializedObject serializedObject = new SerializedObject(effect);
ConfigureAreaEffect(serializedObject, areaShape, areaRadius, fanOriginDistance, fanRadius, fanHalfAngle, areaCenter);
serializedObject.FindProperty("force").floatValue = force;
serializedObject.FindProperty("upwardForce").floatValue = upwardForce;
serializedObject.FindProperty("duration").floatValue = duration;
serializedObject.FindProperty("playHitAnimation").boolValue = playHitAnimation;
serializedObject.FindProperty("hitAnimationSpeedMultiplier").floatValue = hitAnimationSpeedMultiplier;
serializedObject.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(effect);
return effect;
}
///
/// 범위 경직 효과를 생성하거나 갱신합니다.
///
private static StaggerEffect CreateStaggerEffect(
string path,
float duration,
bool playHitAnimation,
float hitAnimationSpeedMultiplier,
AreaShapeType areaShape,
float areaRadius,
float fanOriginDistance,
float fanRadius,
float fanHalfAngle,
AreaCenterType areaCenter)
{
StaggerEffect effect = LoadOrCreateAsset(path);
SerializedObject serializedObject = new SerializedObject(effect);
ConfigureAreaEffect(serializedObject, areaShape, areaRadius, fanOriginDistance, fanRadius, fanHalfAngle, areaCenter);
serializedObject.FindProperty("duration").floatValue = duration;
serializedObject.FindProperty("playHitAnimation").boolValue = playHitAnimation;
serializedObject.FindProperty("hitAnimationSpeedMultiplier").floatValue = hitAnimationSpeedMultiplier;
serializedObject.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(effect);
return effect;
}
///
/// 다운 대상 추가 피해 효과를 생성하거나 갱신합니다.
///
private static HitReactionDamageEffect CreateHitReactionDamageEffect(
string path,
float baseDamage,
DamageType damageType,
float statScaling,
float downedDamageMultiplier,
AreaShapeType areaShape,
float areaRadius,
float fanOriginDistance,
float fanRadius,
float fanHalfAngle,
AreaCenterType areaCenter)
{
HitReactionDamageEffect effect = LoadOrCreateAsset(path);
SerializedObject serializedObject = new SerializedObject(effect);
ConfigureAreaEffect(serializedObject, areaShape, areaRadius, fanOriginDistance, fanRadius, fanHalfAngle, areaCenter);
serializedObject.FindProperty("baseDamage").floatValue = baseDamage;
serializedObject.FindProperty("damageType").enumValueIndex = (int)damageType;
serializedObject.FindProperty("statScaling").floatValue = statScaling;
serializedObject.FindProperty("bonusAgainstDownedTarget").boolValue = true;
serializedObject.FindProperty("downedDamageMultiplier").floatValue = downedDamageMultiplier;
serializedObject.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(effect);
return effect;
}
///
/// 빈 애니메이션 상태에서도 즉시 발동 가능한 드로그 스킬 플레이스홀더를 생성하거나 갱신합니다.
///
private static SkillData CreateSkill(
string path,
string skillName,
string description,
IReadOnlyList clips,
float animationSpeed,
SkillCastTargetTrackingMode trackingMode,
bool useRootMotion,
bool ignoreRootMotionY,
bool jumpToTarget,
params SkillEffect[] castStartEffects)
{
SkillData skill = LoadOrCreateAsset(path);
SerializedObject serializedObject = new SerializedObject(skill);
serializedObject.FindProperty("skillName").stringValue = skillName;
serializedObject.FindProperty("description").stringValue = description;
serializedObject.FindProperty("skillRole").enumValueIndex = (int)SkillRoleType.Attack;
serializedObject.FindProperty("activationType").enumValueIndex = (int)SkillActivationType.Instant;
serializedObject.FindProperty("baseTypes").intValue = (int)SkillBaseType.Attack;
serializedObject.FindProperty("animationSpeed").floatValue = animationSpeed;
serializedObject.FindProperty("useRootMotion").boolValue = useRootMotion;
serializedObject.FindProperty("ignoreRootMotionY").boolValue = ignoreRootMotionY;
serializedObject.FindProperty("jumpToTarget").boolValue = jumpToTarget;
serializedObject.FindProperty("blockMovementWhileCasting").boolValue = true;
serializedObject.FindProperty("blockJumpWhileCasting").boolValue = true;
serializedObject.FindProperty("blockOtherSkillsWhileCasting").boolValue = true;
serializedObject.FindProperty("castTargetTrackingMode").enumValueIndex = (int)trackingMode;
serializedObject.FindProperty("castTargetRotationSpeed").floatValue = 12f;
serializedObject.FindProperty("castTargetStopDistance").floatValue = 2.5f;
serializedObject.FindProperty("cooldown").floatValue = 0f;
serializedObject.FindProperty("manaCost").floatValue = 0f;
serializedObject.FindProperty("maxGemSlotCount").intValue = 0;
serializedObject.FindProperty("castStartEffects").arraySize = 0;
ConfigureTriggeredEffects(serializedObject, castStartEffects);
var clipObjects = new List();
if (clips != null)
{
for (int i = 0; i < clips.Count; i++)
{
if (clips[i] != null)
clipObjects.Add(clips[i]);
}
}
SetObjectList(serializedObject, "animationClips", clipObjects);
serializedObject.ApplyModifiedPropertiesWithoutUndo();
skill.RefreshAnimationClips();
EditorUtility.SetDirty(skill);
return skill;
}
///
/// 전달된 효과를 모두 Trigger Index 0의 애니메이션 이벤트 효과로 기록합니다.
///
private static void ConfigureTriggeredEffects(SerializedObject serializedObject, IReadOnlyList effects)
{
SerializedProperty triggeredEffectsProperty = serializedObject.FindProperty("triggeredEffects");
if (triggeredEffectsProperty == null)
return;
var validEffects = new List();
if (effects != null)
{
for (int i = 0; i < effects.Count; i++)
{
if (effects[i] != null)
validEffects.Add(effects[i]);
}
}
triggeredEffectsProperty.arraySize = validEffects.Count > 0 ? 1 : 0;
if (triggeredEffectsProperty.arraySize == 0)
return;
SerializedProperty entryProperty = triggeredEffectsProperty.GetArrayElementAtIndex(0);
entryProperty.FindPropertyRelative("triggerIndex").intValue = 0;
SerializedProperty effectsProperty = entryProperty.FindPropertyRelative("effects");
effectsProperty.arraySize = validEffects.Count;
for (int i = 0; i < validEffects.Count; i++)
{
effectsProperty.GetArrayElementAtIndex(i).objectReferenceValue = validEffects[i];
}
}
///
/// 드로그 보스 패턴 자산을 생성하거나 갱신합니다.
///
private static BossPatternData CreatePattern(
string path,
string patternName,
PatternCategory category,
bool isSignature,
bool isMelee,
TargetResolveMode targetMode,
float cooldown,
int minPhase,
bool skipJumpStepOnNoTarget,
params PatternStepDefinition[] stepDefinitions)
{
BossPatternData pattern = LoadOrCreateAsset(path);
SerializedObject serializedObject = new SerializedObject(pattern);
serializedObject.FindProperty("patternName").stringValue = patternName;
serializedObject.FindProperty("category").enumValueIndex = (int)category;
serializedObject.FindProperty("isSignature").boolValue = isSignature;
serializedObject.FindProperty("isMelee").boolValue = isMelee;
serializedObject.FindProperty("targetMode").enumValueIndex = (int)targetMode;
serializedObject.FindProperty("cooldown").floatValue = cooldown;
serializedObject.FindProperty("minPhase").intValue = minPhase;
serializedObject.FindProperty("skipJumpStepOnNoTarget").boolValue = skipJumpStepOnNoTarget;
SerializedProperty stepsProperty = serializedObject.FindProperty("steps");
stepsProperty.arraySize = stepDefinitions != null ? stepDefinitions.Length : 0;
for (int i = 0; i < stepsProperty.arraySize; i++)
{
ConfigurePatternStep(stepsProperty.GetArrayElementAtIndex(i), stepDefinitions[i]);
}
serializedObject.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(pattern);
return pattern;
}
///
/// 단일 패턴 스텝 데이터를 SerializedProperty에 기록합니다.
///
private static void ConfigurePatternStep(SerializedProperty stepProperty, PatternStepDefinition definition)
{
stepProperty.FindPropertyRelative("Type").enumValueIndex = (int)definition.StepType;
stepProperty.FindPropertyRelative("Skill").objectReferenceValue = definition.Skill;
stepProperty.FindPropertyRelative("Duration").floatValue = definition.Duration;
SerializedProperty chargeDataProperty = stepProperty.FindPropertyRelative("ChargeData");
if (chargeDataProperty == null)
return;
chargeDataProperty.FindPropertyRelative("requiredDamageRatio").floatValue = definition.RequiredDamageRatio;
chargeDataProperty.FindPropertyRelative("telegraphAbnormality").objectReferenceValue = definition.TelegraphAbnormality;
chargeDataProperty.FindPropertyRelative("staggerDuration").floatValue = definition.StaggerDuration;
}
///
/// 패턴 스텝 정의를 간단히 구성하기 위한 헬퍼입니다.
///
private sealed class PatternStepDefinition
{
public PatternStepType StepType { get; private set; }
public SkillData Skill { get; private set; }
public float Duration { get; private set; }
public AbnormalityData TelegraphAbnormality { get; private set; }
public float RequiredDamageRatio { get; private set; }
public float StaggerDuration { get; private set; }
public static PatternStepDefinition CreateSkillStep(SkillData skill)
{
return new PatternStepDefinition
{
StepType = PatternStepType.Skill,
Skill = skill,
Duration = 0f,
};
}
public static PatternStepDefinition CreateWaitStep(float duration)
{
return new PatternStepDefinition
{
StepType = PatternStepType.Wait,
Duration = duration,
};
}
public static PatternStepDefinition CreateChargeWaitStep(float duration, AbnormalityData telegraphAbnormality, float requiredDamageRatio, float staggerDuration)
{
return new PatternStepDefinition
{
StepType = PatternStepType.ChargeWait,
Duration = duration,
TelegraphAbnormality = telegraphAbnormality,
RequiredDamageRatio = requiredDamageRatio,
StaggerDuration = staggerDuration,
};
}
}
}
}