diff --git a/Assets/_Game/Data/Abnormalities/Data_Abnormality_Player_방어태세.asset b/Assets/_Game/Data/Abnormalities/Data_Abnormality_Player_방어태세.asset new file mode 100644 index 00000000..bd47c12f --- /dev/null +++ b/Assets/_Game/Data/Abnormalities/Data_Abnormality_Player_방어태세.asset @@ -0,0 +1,25 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6170bac0d8f253349adf49e3f2a39c3f, type: 3} + m_Name: Data_Abnormality_Player_방어태세 + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Abnormalities.AbnormalityData + abnormalityName: 방어 태세 + icon: {fileID: 0} + duration: 4 + level: 1 + isDebuff: 0 + statModifiers: [] + periodicInterval: 0 + periodicValue: 0 + controlType: 0 + slowMultiplier: 0.5 + incomingDamageMultiplier: 0.65 diff --git a/Assets/_Game/Data/Abnormalities/Data_Abnormality_Player_방어태세.asset.meta b/Assets/_Game/Data/Abnormalities/Data_Abnormality_Player_방어태세.asset.meta new file mode 100644 index 00000000..0e52e70f --- /dev/null +++ b/Assets/_Game/Data/Abnormalities/Data_Abnormality_Player_방어태세.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 125cb0e546495694c8d1d99ff0e15057 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Data/Abnormalities/Data_Abnormality_Player_철벽.asset b/Assets/_Game/Data/Abnormalities/Data_Abnormality_Player_철벽.asset new file mode 100644 index 00000000..b7cb11d3 --- /dev/null +++ b/Assets/_Game/Data/Abnormalities/Data_Abnormality_Player_철벽.asset @@ -0,0 +1,25 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6170bac0d8f253349adf49e3f2a39c3f, type: 3} + m_Name: Data_Abnormality_Player_철벽 + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Abnormalities.AbnormalityData + abnormalityName: 철벽 + icon: {fileID: 0} + duration: 1.5 + level: 1 + isDebuff: 0 + statModifiers: [] + periodicInterval: 0 + periodicValue: 0 + controlType: 4 + slowMultiplier: 0.5 + incomingDamageMultiplier: 1 diff --git a/Assets/_Game/Data/Abnormalities/Data_Abnormality_Player_철벽.asset.meta b/Assets/_Game/Data/Abnormalities/Data_Abnormality_Player_철벽.asset.meta new file mode 100644 index 00000000..61f41fda --- /dev/null +++ b/Assets/_Game/Data/Abnormalities/Data_Abnormality_Player_철벽.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3d0f7370ef4e6e64a96ae38b4c266af5 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Data/Skills/Data_Skill_Player_광역치유.asset b/Assets/_Game/Data/Skills/Data_Skill_Player_광역치유.asset new file mode 100644 index 00000000..2e0ad21f --- /dev/null +++ b/Assets/_Game/Data/Skills/Data_Skill_Player_광역치유.asset @@ -0,0 +1,30 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 94f0a76cebcac2f4fb5daf1b675fd79f, type: 3} + m_Name: Data_Skill_Player_광역치유 + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.SkillData + skillName: 광역 치유 + description: 주변 아군과 자신의 체력을 함께 회복한다. + icon: {fileID: 0} + skillClip: {fileID: -8689311932429934276, guid: ac0adc4c7f982fe4d82eac9c2267f0c6, type: 3} + endClip: {fileID: 0} + animationSpeed: 1 + useRootMotion: 0 + ignoreRootMotionY: 1 + jumpToTarget: 0 + blockMovementWhileCasting: 1 + blockJumpWhileCasting: 1 + blockOtherSkillsWhileCasting: 1 + cooldown: 16 + manaCost: 30 + effects: + - {fileID: 11400000, guid: d33ec3ec97ad8084e81bb5a60f1e0eca, type: 2} diff --git a/Assets/_Game/Data/Skills/Data_Skill_Player_광역치유.asset.meta b/Assets/_Game/Data/Skills/Data_Skill_Player_광역치유.asset.meta new file mode 100644 index 00000000..63671563 --- /dev/null +++ b/Assets/_Game/Data/Skills/Data_Skill_Player_광역치유.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7a245d40a0d21b248b942033d4ec4309 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Data/Skills/Data_Skill_Player_도발.asset b/Assets/_Game/Data/Skills/Data_Skill_Player_도발.asset new file mode 100644 index 00000000..fff744c1 --- /dev/null +++ b/Assets/_Game/Data/Skills/Data_Skill_Player_도발.asset @@ -0,0 +1,30 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 94f0a76cebcac2f4fb5daf1b675fd79f, type: 3} + m_Name: Data_Skill_Player_도발 + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.SkillData + skillName: 도발 + description: 주변 적의 위협 수치를 크게 높이고 짧은 시간 동안 위협 생성량을 증가시킨다. + icon: {fileID: 0} + skillClip: {fileID: -8689311932429934276, guid: ac0adc4c7f982fe4d82eac9c2267f0c6, type: 3} + endClip: {fileID: 0} + animationSpeed: 1 + useRootMotion: 0 + ignoreRootMotionY: 1 + jumpToTarget: 0 + blockMovementWhileCasting: 1 + blockJumpWhileCasting: 1 + blockOtherSkillsWhileCasting: 1 + cooldown: 8 + manaCost: 10 + effects: + - {fileID: 11400000, guid: f0aaa98426be3d44082a386c00ea9aea, type: 2} diff --git a/Assets/_Game/Data/Skills/Data_Skill_Player_도발.asset.meta b/Assets/_Game/Data/Skills/Data_Skill_Player_도발.asset.meta new file mode 100644 index 00000000..1049c757 --- /dev/null +++ b/Assets/_Game/Data/Skills/Data_Skill_Player_도발.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1020083ab98b8214f918fa2ab7c1a3a1 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Data/Skills/Data_Skill_Player_방어태세.asset b/Assets/_Game/Data/Skills/Data_Skill_Player_방어태세.asset new file mode 100644 index 00000000..e9d2519d --- /dev/null +++ b/Assets/_Game/Data/Skills/Data_Skill_Player_방어태세.asset @@ -0,0 +1,30 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 94f0a76cebcac2f4fb5daf1b675fd79f, type: 3} + m_Name: Data_Skill_Player_방어태세 + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.SkillData + skillName: 방어 태세 + description: 짧은 시간 동안 받는 피해를 줄이고 위협 생성량을 높인다. + icon: {fileID: 0} + skillClip: {fileID: -8689311932429934276, guid: ac0adc4c7f982fe4d82eac9c2267f0c6, type: 3} + endClip: {fileID: 0} + animationSpeed: 1 + useRootMotion: 0 + ignoreRootMotionY: 1 + jumpToTarget: 0 + blockMovementWhileCasting: 1 + blockJumpWhileCasting: 1 + blockOtherSkillsWhileCasting: 1 + cooldown: 10 + manaCost: 12 + effects: + - {fileID: 11400000, guid: a7024f38a9ce6c94ba466164604bde3b, type: 2} diff --git a/Assets/_Game/Data/Skills/Data_Skill_Player_방어태세.asset.meta b/Assets/_Game/Data/Skills/Data_Skill_Player_방어태세.asset.meta new file mode 100644 index 00000000..9a7820e0 --- /dev/null +++ b/Assets/_Game/Data/Skills/Data_Skill_Player_방어태세.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a822c7e8c7cee5546ad594b582208e53 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Data/Skills/Data_Skill_Player_보호막.asset b/Assets/_Game/Data/Skills/Data_Skill_Player_보호막.asset new file mode 100644 index 00000000..68d1dfb9 --- /dev/null +++ b/Assets/_Game/Data/Skills/Data_Skill_Player_보호막.asset @@ -0,0 +1,30 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 94f0a76cebcac2f4fb5daf1b675fd79f, type: 3} + m_Name: Data_Skill_Player_보호막 + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.SkillData + skillName: 보호막 + description: 주변 아군과 자신에게 피해를 흡수하는 보호막을 부여한다. + icon: {fileID: 0} + skillClip: {fileID: -8689311932429934276, guid: ac0adc4c7f982fe4d82eac9c2267f0c6, type: 3} + endClip: {fileID: 0} + animationSpeed: 1 + useRootMotion: 0 + ignoreRootMotionY: 1 + jumpToTarget: 0 + blockMovementWhileCasting: 1 + blockJumpWhileCasting: 1 + blockOtherSkillsWhileCasting: 1 + cooldown: 18 + manaCost: 24 + effects: + - {fileID: 11400000, guid: 65ed1eabc2fb73d43b86230317222608, type: 2} diff --git a/Assets/_Game/Data/Skills/Data_Skill_Player_보호막.asset.meta b/Assets/_Game/Data/Skills/Data_Skill_Player_보호막.asset.meta new file mode 100644 index 00000000..3e153886 --- /dev/null +++ b/Assets/_Game/Data/Skills/Data_Skill_Player_보호막.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b78d2eb76cdfbe248b65bafe6e1dc231 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Data/Skills/Data_Skill_Player_철벽.asset b/Assets/_Game/Data/Skills/Data_Skill_Player_철벽.asset new file mode 100644 index 00000000..6d85a201 --- /dev/null +++ b/Assets/_Game/Data/Skills/Data_Skill_Player_철벽.asset @@ -0,0 +1,30 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 94f0a76cebcac2f4fb5daf1b675fd79f, type: 3} + m_Name: Data_Skill_Player_철벽 + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.SkillData + skillName: 철벽 + description: 짧은 시간 동안 무적이 되며 위협 생성량이 약간 증가한다. + icon: {fileID: 0} + skillClip: {fileID: -8689311932429934276, guid: ac0adc4c7f982fe4d82eac9c2267f0c6, type: 3} + endClip: {fileID: 0} + animationSpeed: 1 + useRootMotion: 0 + ignoreRootMotionY: 1 + jumpToTarget: 0 + blockMovementWhileCasting: 1 + blockJumpWhileCasting: 1 + blockOtherSkillsWhileCasting: 1 + cooldown: 18 + manaCost: 20 + effects: + - {fileID: 11400000, guid: bc418a5bb985ee34395994d50918086b, type: 2} diff --git a/Assets/_Game/Data/Skills/Data_Skill_Player_철벽.asset.meta b/Assets/_Game/Data/Skills/Data_Skill_Player_철벽.asset.meta new file mode 100644 index 00000000..24c818d9 --- /dev/null +++ b/Assets/_Game/Data/Skills/Data_Skill_Player_철벽.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 29e1ce0656471b54f84b18a773032a99 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Data/Skills/Data_Skill_Player_치유.asset b/Assets/_Game/Data/Skills/Data_Skill_Player_치유.asset new file mode 100644 index 00000000..d917def4 --- /dev/null +++ b/Assets/_Game/Data/Skills/Data_Skill_Player_치유.asset @@ -0,0 +1,30 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 94f0a76cebcac2f4fb5daf1b675fd79f, type: 3} + m_Name: Data_Skill_Player_치유 + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.SkillData + skillName: 치유 + description: 자신의 체력을 빠르게 회복한다. + icon: {fileID: 0} + skillClip: {fileID: -8689311932429934276, guid: ac0adc4c7f982fe4d82eac9c2267f0c6, type: 3} + endClip: {fileID: 0} + animationSpeed: 1 + useRootMotion: 0 + ignoreRootMotionY: 1 + jumpToTarget: 0 + blockMovementWhileCasting: 1 + blockJumpWhileCasting: 1 + blockOtherSkillsWhileCasting: 1 + cooldown: 8 + manaCost: 18 + effects: + - {fileID: 11400000, guid: fa5f619fe89f93f4293a0d5edcfe9592, type: 2} diff --git a/Assets/_Game/Data/Skills/Data_Skill_Player_치유.asset.meta b/Assets/_Game/Data/Skills/Data_Skill_Player_치유.asset.meta new file mode 100644 index 00000000..be23bf20 --- /dev/null +++ b/Assets/_Game/Data/Skills/Data_Skill_Player_치유.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 21598931a138aa44c86d85d67f6c534a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_광역치유_0_회복.asset b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_광역치유_0_회복.asset new file mode 100644 index 00000000..41bc9d0c --- /dev/null +++ b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_광역치유_0_회복.asset @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: abc224c01f587d447bc8df723ef522ba, type: 3} + m_Name: Data_SkillEffect_Player_광역치유_0_회복 + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.Effects.HealEffect + targetType: 1 + targetTeam: 1 + areaCenter: 0 + areaShape: 0 + targetLayers: + serializedVersion: 2 + m_Bits: 4294967295 + includeCasterInArea: 1 + areaRadius: 6 + fanOriginDistance: 1 + fanRadius: 3 + fanHalfAngle: 45 + baseHeal: 18 + healScaling: 0.75 diff --git a/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_광역치유_0_회복.asset.meta b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_광역치유_0_회복.asset.meta new file mode 100644 index 00000000..a467d52a --- /dev/null +++ b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_광역치유_0_회복.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d33ec3ec97ad8084e81bb5a60f1e0eca +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_도발_0_도발.asset b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_도발_0_도발.asset new file mode 100644 index 00000000..fae5552a --- /dev/null +++ b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_도발_0_도발.asset @@ -0,0 +1,29 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bd72562b167fced4191f12bd3a86d341, type: 3} + m_Name: Data_SkillEffect_Player_도발_0_도발 + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.Effects.TauntEffect + targetType: 0 + targetTeam: 0 + areaCenter: 0 + areaShape: 0 + targetLayers: + serializedVersion: 2 + m_Bits: 4294967295 + areaRadius: 5 + fanOriginDistance: 1 + fanRadius: 3 + fanHalfAngle: 45 + flatThreatAmount: 60 + threatLeadBonus: 20 + selfThreatMultiplier: 1.75 + selfThreatMultiplierDuration: 5 diff --git a/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_도발_0_도발.asset.meta b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_도발_0_도발.asset.meta new file mode 100644 index 00000000..85fadb37 --- /dev/null +++ b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_도발_0_도발.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f0aaa98426be3d44082a386c00ea9aea +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_방어태세_0_강화.asset b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_방어태세_0_강화.asset new file mode 100644 index 00000000..2c5c9788 --- /dev/null +++ b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_방어태세_0_강화.asset @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 639a0e2e83c292b4aaf5bc4b1532f099, type: 3} + m_Name: Data_SkillEffect_Player_방어태세_0_강화 + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.Effects.CombatBuffEffect + targetType: 0 + targetTeam: 0 + areaCenter: 0 + areaShape: 0 + targetLayers: + serializedVersion: 2 + m_Bits: 0 + areaRadius: 3 + fanOriginDistance: 1 + fanRadius: 3 + fanHalfAngle: 45 + abnormalityData: {fileID: 11400000, guid: 125cb0e546495694c8d1d99ff0e15057, type: 2} + threatMultiplier: 1.35 + threatMultiplierDuration: 4 diff --git a/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_방어태세_0_강화.asset.meta b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_방어태세_0_강화.asset.meta new file mode 100644 index 00000000..2c422ce7 --- /dev/null +++ b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_방어태세_0_강화.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a7024f38a9ce6c94ba466164604bde3b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_보호막_0_보호막.asset b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_보호막_0_보호막.asset new file mode 100644 index 00000000..f246c56f --- /dev/null +++ b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_보호막_0_보호막.asset @@ -0,0 +1,29 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6598d3be8b5522b4494d1f60cbc1986c, type: 3} + m_Name: Data_SkillEffect_Player_보호막_0_보호막 + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.Effects.ShieldEffect + targetType: 1 + targetTeam: 1 + areaCenter: 0 + areaShape: 0 + targetLayers: + serializedVersion: 2 + m_Bits: 4294967295 + includeCasterInArea: 1 + areaRadius: 6 + fanOriginDistance: 1 + fanRadius: 3 + fanHalfAngle: 45 + baseShield: 28 + shieldScaling: 0.8 + duration: 5 diff --git a/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_보호막_0_보호막.asset.meta b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_보호막_0_보호막.asset.meta new file mode 100644 index 00000000..26c263ed --- /dev/null +++ b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_보호막_0_보호막.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 65ed1eabc2fb73d43b86230317222608 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_철벽_0_강화.asset b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_철벽_0_강화.asset new file mode 100644 index 00000000..b6662e84 --- /dev/null +++ b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_철벽_0_강화.asset @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 639a0e2e83c292b4aaf5bc4b1532f099, type: 3} + m_Name: Data_SkillEffect_Player_철벽_0_강화 + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.Effects.CombatBuffEffect + targetType: 0 + targetTeam: 0 + areaCenter: 0 + areaShape: 0 + targetLayers: + serializedVersion: 2 + m_Bits: 0 + areaRadius: 3 + fanOriginDistance: 1 + fanRadius: 3 + fanHalfAngle: 45 + abnormalityData: {fileID: 11400000, guid: 3d0f7370ef4e6e64a96ae38b4c266af5, type: 2} + threatMultiplier: 1.2 + threatMultiplierDuration: 1.5 diff --git a/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_철벽_0_강화.asset.meta b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_철벽_0_강화.asset.meta new file mode 100644 index 00000000..ed41986e --- /dev/null +++ b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_철벽_0_강화.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bc418a5bb985ee34395994d50918086b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_치유_0_회복.asset b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_치유_0_회복.asset new file mode 100644 index 00000000..3ad2a8bc --- /dev/null +++ b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_치유_0_회복.asset @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: abc224c01f587d447bc8df723ef522ba, type: 3} + m_Name: Data_SkillEffect_Player_치유_0_회복 + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.Effects.HealEffect + targetType: 0 + targetTeam: 1 + areaCenter: 0 + areaShape: 0 + targetLayers: + serializedVersion: 2 + m_Bits: 4294967295 + includeCasterInArea: 0 + areaRadius: 3 + fanOriginDistance: 1 + fanRadius: 3 + fanHalfAngle: 45 + baseHeal: 30 + healScaling: 1 diff --git a/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_치유_0_회복.asset.meta b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_치유_0_회복.asset.meta new file mode 100644 index 00000000..6af22b46 --- /dev/null +++ b/Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_치유_0_회복.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fa5f619fe89f93f4293a0d5edcfe9592 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Prefabs/Player/Prefab_Player_Default.prefab b/Assets/_Game/Prefabs/Player/Prefab_Player_Default.prefab index 9a9e5f2e..57acf508 100644 --- a/Assets/_Game/Prefabs/Player/Prefab_Player_Default.prefab +++ b/Assets/_Game/Prefabs/Player/Prefab_Player_Default.prefab @@ -329,12 +329,12 @@ MonoBehaviour: m_EditorClassIdentifier: Colosseum.Game::Colosseum.Player.PlayerSkillInput ShowTopMostFoldoutHeaderGroup: 1 skillSlots: - - {fileID: 11400000, guid: b7f09e0e899c8fc4bb2cc9204cc6eb4a, type: 2} - - {fileID: 11400000, guid: b8c86399865e91144a3d6fcfddc04fd9, type: 2} - - {fileID: 0} - - {fileID: 0} - - {fileID: 0} - - {fileID: 0} + - {fileID: 11400000, guid: b7f09e0e899c8fc4bb2cc9204cc6eb4a, type: 2} + - {fileID: 11400000, guid: b8c86399865e91144a3d6fcfddc04fd9, type: 2} + - {fileID: 11400000, guid: 1020083ab98b8214f918fa2ab7c1a3a1, type: 2} + - {fileID: 11400000, guid: a822c7e8c7cee5546ad594b582208e53, type: 2} + - {fileID: 11400000, guid: 29e1ce0656471b54f84b18a773032a99, type: 2} + - {fileID: 0} - {fileID: 11400000, guid: 2ed15dca92a165046b6df17b28f64874, type: 2} skillController: {fileID: 6912018896034183004} networkController: {fileID: 0} diff --git a/Assets/_Game/Scripts/Combat.meta b/Assets/_Game/Scripts/Combat.meta new file mode 100644 index 00000000..721471b4 --- /dev/null +++ b/Assets/_Game/Scripts/Combat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aa83afc530053564abc8d7100f96194c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Scripts/Combat/ThreatController.cs b/Assets/_Game/Scripts/Combat/ThreatController.cs new file mode 100644 index 00000000..b9c7a37a --- /dev/null +++ b/Assets/_Game/Scripts/Combat/ThreatController.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; + +using UnityEngine; + +namespace Colosseum.Combat +{ + /// + /// 전투 중 생성하는 위협 배율을 관리합니다. + /// 탱커 스킬이 짧은 시간 동안 위협 생성량을 높이는 데 사용합니다. + /// + [DisallowMultipleComponent] + public class ThreatController : MonoBehaviour + { + [Serializable] + private class TimedThreatModifier + { + [Min(0f)] public float multiplier = 1f; + [Min(0f)] public float endTime; + } + + [Header("Threat")] + [Tooltip("기본 위협 생성 배율")] + [Min(0f)] [SerializeField] private float baseThreatMultiplier = 1f; + + [Tooltip("디버그 로그 출력 여부")] + [SerializeField] private bool debugMode = false; + + [Header("Debug")] + [Tooltip("현재 적용 중인 위협 생성 배율")] + [Min(0f)] [SerializeField] private float currentThreatMultiplier = 1f; + + private readonly List activeModifiers = new List(); + + /// + /// 현재 적용 중인 위협 생성 배율 + /// + public float CurrentThreatMultiplier => currentThreatMultiplier; + + private void Awake() + { + RecalculateThreatMultiplier(); + } + + private void Update() + { + if (activeModifiers.Count == 0) + return; + + bool changed = false; + for (int i = activeModifiers.Count - 1; i >= 0; i--) + { + if (Time.time < activeModifiers[i].endTime) + continue; + + activeModifiers.RemoveAt(i); + changed = true; + } + + if (changed) + { + RecalculateThreatMultiplier(); + } + } + + /// + /// 일정 시간 동안 위협 생성 배율을 추가합니다. + /// + public void ApplyThreatMultiplier(float multiplier, float duration) + { + if (multiplier <= 0f || duration <= 0f) + return; + + activeModifiers.Add(new TimedThreatModifier + { + multiplier = multiplier, + endTime = Time.time + duration, + }); + + RecalculateThreatMultiplier(); + + if (debugMode) + { + Debug.Log($"[Threat] {gameObject.name} 위협 배율 적용: x{multiplier:F2} / {duration:F2}s"); + } + } + + /// + /// 모든 임시 위협 배율을 제거합니다. + /// + public void ClearThreatModifiers() + { + if (activeModifiers.Count == 0) + return; + + activeModifiers.Clear(); + RecalculateThreatMultiplier(); + } + + private void RecalculateThreatMultiplier() + { + float nextMultiplier = Mathf.Max(0f, baseThreatMultiplier); + for (int i = 0; i < activeModifiers.Count; i++) + { + nextMultiplier *= Mathf.Max(0f, activeModifiers[i].multiplier); + } + + currentThreatMultiplier = nextMultiplier; + } + } +} diff --git a/Assets/_Game/Scripts/Combat/ThreatController.cs.meta b/Assets/_Game/Scripts/Combat/ThreatController.cs.meta new file mode 100644 index 00000000..47205720 --- /dev/null +++ b/Assets/_Game/Scripts/Combat/ThreatController.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 28ce8e804d41f534e887036d4f43c3e3 \ No newline at end of file diff --git a/Assets/_Game/Scripts/Editor/PlayerSkillDebugMenu.cs b/Assets/_Game/Scripts/Editor/PlayerSkillDebugMenu.cs new file mode 100644 index 00000000..b4a035c2 --- /dev/null +++ b/Assets/_Game/Scripts/Editor/PlayerSkillDebugMenu.cs @@ -0,0 +1,200 @@ +using System.Text; + +using Colosseum.Enemy; +using Colosseum.Player; +using Colosseum.Skills; + +using UnityEditor; +using UnityEngine; + +namespace Colosseum.Editor +{ + /// + /// 플레이 모드에서 로컬 플레이어 스킬과 보스 위협 상태를 빠르게 검증하는 디버그 메뉴입니다. + /// + public static class PlayerSkillDebugMenu + { + private const int TemporaryDebugSlotIndex = 5; + private const string HealSkillPath = "Assets/_Game/Data/Skills/Data_Skill_Player_치유.asset"; + private const string AreaHealSkillPath = "Assets/_Game/Data/Skills/Data_Skill_Player_광역치유.asset"; + private const string ShieldSkillPath = "Assets/_Game/Data/Skills/Data_Skill_Player_보호막.asset"; + + [MenuItem("Tools/Colosseum/Debug/Cast Local Skill 3")] + private static void CastLocalSkill3() + { + CastLocalSkill(2); + } + + [MenuItem("Tools/Colosseum/Debug/Cast Local Skill 4")] + private static void CastLocalSkill4() + { + CastLocalSkill(3); + } + + [MenuItem("Tools/Colosseum/Debug/Cast Local Skill 5")] + private static void CastLocalSkill5() + { + CastLocalSkill(4); + } + + [MenuItem("Tools/Colosseum/Debug/Cast Local Heal")] + private static void CastLocalHeal() + { + CastLocalSkillAsset(HealSkillPath); + } + + [MenuItem("Tools/Colosseum/Debug/Cast Local Area Heal")] + private static void CastLocalAreaHeal() + { + CastLocalSkillAsset(AreaHealSkillPath); + } + + [MenuItem("Tools/Colosseum/Debug/Cast Local Shield")] + private static void CastLocalShield() + { + CastLocalSkillAsset(ShieldSkillPath); + } + + [MenuItem("Tools/Colosseum/Debug/Damage Local Player 30")] + private static void DamageLocalPlayer30() + { + if (!EditorApplication.isPlaying) + { + Debug.LogWarning("[Debug] 플레이 모드에서만 사용할 수 있습니다."); + return; + } + + PlayerNetworkController localNetworkController = FindLocalNetworkController(); + if (localNetworkController == null) + { + Debug.LogWarning("[Debug] 로컬 PlayerNetworkController를 찾지 못했습니다."); + return; + } + + localNetworkController.TakeDamageRpc(30f); + } + + [MenuItem("Tools/Colosseum/Debug/Log Local Player Status")] + private static void LogLocalPlayerStatus() + { + if (!EditorApplication.isPlaying) + { + Debug.LogWarning("[Debug] 플레이 모드에서만 사용할 수 있습니다."); + return; + } + + PlayerNetworkController localNetworkController = FindLocalNetworkController(); + if (localNetworkController == null) + { + Debug.LogWarning("[Debug] 로컬 PlayerNetworkController를 찾지 못했습니다."); + return; + } + + Debug.Log( + $"[Debug] 로컬 플레이어 상태 | HP {localNetworkController.Health:F1}/{localNetworkController.MaxHealth:F1} | " + + $"MP {localNetworkController.Mana:F1}/{localNetworkController.MaxMana:F1} | Shield {localNetworkController.Shield:F1}"); + } + + [MenuItem("Tools/Colosseum/Debug/Log Boss Threat Summary")] + private static void LogBossThreatSummary() + { + if (!EditorApplication.isPlaying) + { + Debug.LogWarning("[Debug] 플레이 모드에서만 사용할 수 있습니다."); + return; + } + + EnemyBase[] enemies = Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None); + if (enemies == null || enemies.Length == 0) + { + Debug.LogWarning("[Debug] 활성 EnemyBase가 없습니다."); + return; + } + + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < enemies.Length; i++) + { + EnemyBase enemy = enemies[i]; + if (enemy == null) + continue; + + if (builder.Length > 0) + builder.AppendLine().AppendLine(); + + builder.Append(enemy.name); + builder.Append(" : "); + builder.Append(enemy.GetThreatDebugSummary().Replace("\r\n", " | ").Replace("\n", " | ")); + } + + Debug.Log($"[Debug] 보스 위협 요약\n{builder}"); + } + + private static PlayerSkillInput FindLocalSkillInput() + { + PlayerSkillInput[] skillInputs = Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None); + for (int i = 0; i < skillInputs.Length; i++) + { + if (skillInputs[i] != null && skillInputs[i].IsOwner) + return skillInputs[i]; + } + + return null; + } + + private static PlayerNetworkController FindLocalNetworkController() + { + PlayerNetworkController[] networkControllers = Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None); + for (int i = 0; i < networkControllers.Length; i++) + { + if (networkControllers[i] != null && networkControllers[i].IsOwner) + return networkControllers[i]; + } + + return null; + } + + private static void CastLocalSkill(int slotIndex) + { + if (!EditorApplication.isPlaying) + { + Debug.LogWarning("[Debug] 플레이 모드에서만 사용할 수 있습니다."); + return; + } + + PlayerSkillInput localSkillInput = FindLocalSkillInput(); + if (localSkillInput == null) + { + Debug.LogWarning("[Debug] 로컬 PlayerSkillInput을 찾지 못했습니다."); + return; + } + + localSkillInput.DebugCastSkill(slotIndex); + } + + private static void CastLocalSkillAsset(string assetPath) + { + if (!EditorApplication.isPlaying) + { + Debug.LogWarning("[Debug] 플레이 모드에서만 사용할 수 있습니다."); + return; + } + + PlayerSkillInput localSkillInput = FindLocalSkillInput(); + if (localSkillInput == null) + { + Debug.LogWarning("[Debug] 로컬 PlayerSkillInput을 찾지 못했습니다."); + return; + } + + SkillData skill = AssetDatabase.LoadAssetAtPath(assetPath); + if (skill == null) + { + Debug.LogWarning($"[Debug] 스킬 에셋을 찾지 못했습니다: {assetPath}"); + return; + } + + localSkillInput.SetSkill(TemporaryDebugSlotIndex, skill); + localSkillInput.DebugCastSkill(TemporaryDebugSlotIndex); + } + } +} diff --git a/Assets/_Game/Scripts/Editor/PlayerSkillDebugMenu.cs.meta b/Assets/_Game/Scripts/Editor/PlayerSkillDebugMenu.cs.meta new file mode 100644 index 00000000..fc21833e --- /dev/null +++ b/Assets/_Game/Scripts/Editor/PlayerSkillDebugMenu.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 024b92839f405134e8824931db2091a6 \ No newline at end of file diff --git a/Assets/_Game/Scripts/Enemy/EnemyBase.cs b/Assets/_Game/Scripts/Enemy/EnemyBase.cs index f472b104..fcd85df7 100644 --- a/Assets/_Game/Scripts/Enemy/EnemyBase.cs +++ b/Assets/_Game/Scripts/Enemy/EnemyBase.cs @@ -562,7 +562,7 @@ namespace Colosseum.Enemy if (sourceObject == null) return; - AddThreat(sourceObject, damage * damageThreatMultiplier); + AddThreat(sourceObject, damage * damageThreatMultiplier * GetThreatSourceMultiplier(sourceObject)); } /// @@ -672,5 +672,17 @@ namespace Colosseum.Enemy _ => null, }; } + + /// + /// 공격자가 가진 현재 위협 생성 배율을 반환합니다. + /// + private static float GetThreatSourceMultiplier(GameObject sourceObject) + { + if (sourceObject == null) + return 1f; + + ThreatController threatController = sourceObject.GetComponent(); + return threatController != null ? Mathf.Max(0f, threatController.CurrentThreatMultiplier) : 1f; + } } } diff --git a/Assets/_Game/Scripts/Player/PlayerNetworkController.cs b/Assets/_Game/Scripts/Player/PlayerNetworkController.cs index a6b9d4ba..e21b0696 100644 --- a/Assets/_Game/Scripts/Player/PlayerNetworkController.cs +++ b/Assets/_Game/Scripts/Player/PlayerNetworkController.cs @@ -25,9 +25,11 @@ namespace Colosseum.Player private NetworkVariable currentHealth = new NetworkVariable(100f); private NetworkVariable currentMana = new NetworkVariable(50f); private NetworkVariable isDead = new NetworkVariable(false); + private NetworkVariable currentShield = new NetworkVariable(0f); public float Health => currentHealth.Value; public float Mana => currentMana.Value; + public float Shield => currentShield.Value; public float MaxHealth => characterStats != null ? characterStats.MaxHealth : 100f; public float MaxMana => characterStats != null ? characterStats.MaxMana : 50f; public CharacterStats Stats => characterStats; @@ -35,6 +37,7 @@ namespace Colosseum.Player // 체력/마나 변경 이벤트 public event Action OnHealthChanged; // (oldValue, newValue) public event Action OnManaChanged; // (oldValue, newValue) + public event Action OnShieldChanged; // (oldValue, newValue) // 사망 이벤트 public event Action OnDeath; @@ -61,6 +64,7 @@ namespace Colosseum.Player // 네트워크 변수 변경 콜백 등록 currentHealth.OnValueChanged += HandleHealthChanged; currentMana.OnValueChanged += HandleManaChanged; + currentShield.OnValueChanged += HandleShieldChanged; isDead.OnValueChanged += HandleDeathStateChanged; // 초기화 @@ -68,6 +72,7 @@ namespace Colosseum.Player { currentHealth.Value = MaxHealth; currentMana.Value = MaxMana; + currentShield.Value = 0f; isDead.Value = false; } } @@ -77,6 +82,7 @@ namespace Colosseum.Player // 콜백 해제 currentHealth.OnValueChanged -= HandleHealthChanged; currentMana.OnValueChanged -= HandleManaChanged; + currentShield.OnValueChanged -= HandleShieldChanged; isDead.OnValueChanged -= HandleDeathStateChanged; } @@ -90,6 +96,11 @@ namespace Colosseum.Player OnManaChanged?.Invoke(oldValue, newValue); } + private void HandleShieldChanged(float oldValue, float newValue) + { + OnShieldChanged?.Invoke(oldValue, newValue); + } + private void HandleDeathStateChanged(bool oldValue, bool newValue) { OnDeathStateChanged?.Invoke(newValue); @@ -104,7 +115,8 @@ namespace Colosseum.Player if (isDead.Value || IsDamageImmune()) return; float finalDamage = damage * GetIncomingDamageMultiplier(); - float actualDamage = Mathf.Min(finalDamage, currentHealth.Value); + float mitigatedDamage = ConsumeShield(finalDamage); + float actualDamage = Mathf.Min(mitigatedDamage, currentHealth.Value); currentHealth.Value = Mathf.Max(0f, currentHealth.Value - actualDamage); if (currentHealth.Value <= 0f) @@ -167,6 +179,7 @@ namespace Colosseum.Player if (isDead.Value) return; isDead.Value = true; + currentShield.Value = 0f; // 사망 시 활성 이상 상태를 정리해 리스폰 시 잔존하지 않게 합니다. if (abnormalityManager != null) @@ -188,6 +201,12 @@ namespace Colosseum.Player hitReactionController.ClearHitReactionState(); } + var threatController = GetComponent(); + if (threatController != null) + { + threatController.ClearThreatModifiers(); + } + // 스킬 입력 비활성화 var skillInput = GetComponent(); if (skillInput != null) @@ -226,6 +245,7 @@ namespace Colosseum.Player isDead.Value = false; currentHealth.Value = MaxHealth; currentMana.Value = MaxMana; + currentShield.Value = 0f; // 이동 재활성화 var movement = GetComponent(); @@ -241,6 +261,12 @@ namespace Colosseum.Player hitReactionController.ClearHitReactionState(); } + var threatController = GetComponent(); + if (threatController != null) + { + threatController.ClearThreatModifiers(); + } + // 스킬 입력 재활성화 var skillInput = GetComponent(); if (skillInput != null) @@ -275,7 +301,8 @@ namespace Colosseum.Player if (!IsServer || isDead.Value || IsDamageImmune()) return 0f; float finalDamage = damage * GetIncomingDamageMultiplier(); - float actualDamage = Mathf.Min(finalDamage, currentHealth.Value); + float mitigatedDamage = ConsumeShield(finalDamage); + float actualDamage = Mathf.Min(mitigatedDamage, currentHealth.Value); currentHealth.Value = Mathf.Max(0f, currentHealth.Value - actualDamage); if (currentHealth.Value <= 0f) @@ -299,6 +326,23 @@ namespace Colosseum.Player return actualHeal; } + /// + /// 보호막을 적용합니다. + /// + public void ApplyShield(float amount, float duration) + { + if (!IsServer || isDead.Value || amount <= 0f) + return; + + currentShield.Value = Mathf.Max(currentShield.Value, amount); + + if (duration > 0f) + { + CancelInvoke(nameof(ClearShield)); + Invoke(nameof(ClearShield), duration); + } + } + private bool IsDamageImmune() { return abnormalityManager != null && abnormalityManager.IsInvincible; @@ -311,6 +355,24 @@ namespace Colosseum.Player return Mathf.Max(0f, abnormalityManager.IncomingDamageMultiplier); } + + private float ConsumeShield(float incomingDamage) + { + if (incomingDamage <= 0f || currentShield.Value <= 0f) + return incomingDamage; + + float shieldAbsorb = Mathf.Min(currentShield.Value, incomingDamage); + currentShield.Value = Mathf.Max(0f, currentShield.Value - shieldAbsorb); + return Mathf.Max(0f, incomingDamage - shieldAbsorb); + } + + private void ClearShield() + { + if (!IsServer) + return; + + currentShield.Value = 0f; + } #endregion } } diff --git a/Assets/_Game/Scripts/Player/PlayerSkillInput.cs b/Assets/_Game/Scripts/Player/PlayerSkillInput.cs index 45cb17ef..226d82f0 100644 --- a/Assets/_Game/Scripts/Player/PlayerSkillInput.cs +++ b/Assets/_Game/Scripts/Player/PlayerSkillInput.cs @@ -268,6 +268,18 @@ namespace Colosseum.Player return !skillController.IsOnCooldown(skill) && !skillController.IsExecutingSkill; } + /// + /// 디버그용 스킬 시전 진입점입니다. + /// 로컬 플레이어 검증 시 지정한 슬롯의 스킬을 즉시 요청합니다. + /// + public void DebugCastSkill(int slotIndex) + { + if (!IsOwner) + return; + + OnSkillInput(slotIndex); + } + private void OnSkill1Performed(InputAction.CallbackContext context) => OnSkillInput(0); private void OnSkill2Performed(InputAction.CallbackContext context) => OnSkillInput(1); diff --git a/Assets/_Game/Scripts/Skills/Effects/CombatBuffEffect.cs b/Assets/_Game/Scripts/Skills/Effects/CombatBuffEffect.cs new file mode 100644 index 00000000..3be66bda --- /dev/null +++ b/Assets/_Game/Scripts/Skills/Effects/CombatBuffEffect.cs @@ -0,0 +1,60 @@ +using UnityEngine; + +using Colosseum.Abnormalities; +using Colosseum.Combat; + +namespace Colosseum.Skills.Effects +{ + /// + /// 이상상태와 위협 생성 배율을 함께 적용하는 자기 강화 효과입니다. + /// 탱킹 스킬의 방어/위협 유지 용도로 사용합니다. + /// + [CreateAssetMenu(fileName = "CombatBuffEffect", menuName = "Colosseum/Skills/Effects/Combat Buff")] + public class CombatBuffEffect : SkillEffect + { + [Header("Buff")] + [Tooltip("적용할 이상상태 데이터")] + [SerializeField] private AbnormalityData abnormalityData; + + [Tooltip("함께 적용할 위협 생성 배율")] + [Min(0f)] [SerializeField] private float threatMultiplier = 1f; + + [Tooltip("위협 생성 배율 지속 시간")] + [Min(0f)] [SerializeField] private float threatMultiplierDuration = 0f; + + protected override void ApplyEffect(GameObject caster, GameObject target) + { + if (target == null) + return; + + ApplyAbnormality(target, caster); + ApplyThreatMultiplier(target); + } + + private void ApplyAbnormality(GameObject target, GameObject caster) + { + if (abnormalityData == null) + return; + + AbnormalityManager abnormalityManager = target.GetComponent(); + if (abnormalityManager == null) + return; + + abnormalityManager.ApplyAbnormality(abnormalityData, caster); + } + + private void ApplyThreatMultiplier(GameObject target) + { + if (threatMultiplier <= 0f || threatMultiplierDuration <= 0f) + return; + + ThreatController threatController = target.GetComponent(); + if (threatController == null) + { + threatController = target.AddComponent(); + } + + threatController.ApplyThreatMultiplier(threatMultiplier, threatMultiplierDuration); + } + } +} diff --git a/Assets/_Game/Scripts/Skills/Effects/CombatBuffEffect.cs.meta b/Assets/_Game/Scripts/Skills/Effects/CombatBuffEffect.cs.meta new file mode 100644 index 00000000..bf3584cc --- /dev/null +++ b/Assets/_Game/Scripts/Skills/Effects/CombatBuffEffect.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 639a0e2e83c292b4aaf5bc4b1532f099 \ No newline at end of file diff --git a/Assets/_Game/Scripts/Skills/Effects/ShieldEffect.cs b/Assets/_Game/Scripts/Skills/Effects/ShieldEffect.cs new file mode 100644 index 00000000..1f04289e --- /dev/null +++ b/Assets/_Game/Scripts/Skills/Effects/ShieldEffect.cs @@ -0,0 +1,47 @@ +using UnityEngine; + +using Colosseum.Player; +using Colosseum.Stats; + +namespace Colosseum.Skills.Effects +{ + /// + /// 보호막 효과입니다. + /// 대상에게 일정 시간 동안 피해를 흡수하는 보호막을 부여합니다. + /// + [CreateAssetMenu(fileName = "ShieldEffect", menuName = "Colosseum/Skills/Effects/Shield")] + public class ShieldEffect : SkillEffect + { + [Header("Shield")] + [Tooltip("기본 보호막 수치")] + [Min(0f)] [SerializeField] private float baseShield = 100f; + + [Tooltip("회복력 계수")] + [Min(0f)] [SerializeField] private float shieldScaling = 0.5f; + + [Tooltip("보호막 지속 시간")] + [Min(0f)] [SerializeField] private float duration = 5f; + + protected override void ApplyEffect(GameObject caster, GameObject target) + { + if (target == null) + return; + + PlayerNetworkController networkController = target.GetComponent(); + if (networkController == null) + return; + + float totalShield = CalculateShield(caster); + networkController.ApplyShield(totalShield, duration); + } + + private float CalculateShield(GameObject caster) + { + CharacterStats stats = caster != null ? caster.GetComponent() : null; + if (stats == null) + return baseShield; + + return baseShield + (stats.HealPower * shieldScaling); + } + } +} diff --git a/Assets/_Game/Scripts/Skills/Effects/ShieldEffect.cs.meta b/Assets/_Game/Scripts/Skills/Effects/ShieldEffect.cs.meta new file mode 100644 index 00000000..790ff19d --- /dev/null +++ b/Assets/_Game/Scripts/Skills/Effects/ShieldEffect.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 6598d3be8b5522b4494d1f60cbc1986c \ No newline at end of file diff --git a/Assets/_Game/Scripts/Skills/Effects/TauntEffect.cs b/Assets/_Game/Scripts/Skills/Effects/TauntEffect.cs new file mode 100644 index 00000000..ae29edcd --- /dev/null +++ b/Assets/_Game/Scripts/Skills/Effects/TauntEffect.cs @@ -0,0 +1,87 @@ +using System.Collections.Generic; + +using UnityEngine; + +using Colosseum.Combat; +using Colosseum.Enemy; + +namespace Colosseum.Skills.Effects +{ + /// + /// 주변 적의 위협 수치를 높여 주 대상을 자신에게 돌리는 도발 효과입니다. + /// 필요 시 시전자에게 임시 위협 생성 배율도 함께 부여합니다. + /// + [CreateAssetMenu(fileName = "TauntEffect", menuName = "Colosseum/Skills/Effects/Taunt")] + public class TauntEffect : SkillEffect + { + [Header("Taunt Settings")] + [Tooltip("도발 시 추가할 기본 위협 수치")] + [Min(0f)] [SerializeField] private float flatThreatAmount = 50f; + + [Tooltip("현재 최고 위협보다 이 값만큼 더 높게 설정합니다.")] + [Min(0f)] [SerializeField] private float threatLeadBonus = 10f; + + [Tooltip("도발과 함께 시전자에게 부여할 위협 생성 배율")] + [Min(0f)] [SerializeField] private float selfThreatMultiplier = 1.5f; + + [Tooltip("위협 생성 배율 지속 시간")] + [Min(0f)] [SerializeField] private float selfThreatMultiplierDuration = 5f; + + private readonly Collider[] overlapBuffer = new Collider[16]; + private readonly HashSet processedEnemies = new HashSet(); + + protected override void ApplyEffect(GameObject caster, GameObject target) + { + if (caster == null) + return; + + ApplySelfThreatMultiplier(caster); + + processedEnemies.Clear(); + int hitCount = Physics.OverlapSphereNonAlloc(caster.transform.position, areaRadius, overlapBuffer, targetLayers); + for (int i = 0; i < hitCount; i++) + { + Collider hit = overlapBuffer[i]; + if (hit == null) + continue; + + EnemyBase enemy = hit.GetComponentInParent(); + if (enemy == null || processedEnemies.Contains(enemy)) + continue; + + if (!IsValidTarget(caster, enemy.gameObject)) + continue; + + processedEnemies.Add(enemy); + ApplyTauntThreat(enemy, caster); + } + } + + private void ApplySelfThreatMultiplier(GameObject caster) + { + if (selfThreatMultiplier <= 0f || selfThreatMultiplierDuration <= 0f) + return; + + ThreatController threatController = caster.GetComponent(); + if (threatController == null) + { + threatController = caster.AddComponent(); + } + + threatController.ApplyThreatMultiplier(selfThreatMultiplier, selfThreatMultiplierDuration); + } + + private void ApplyTauntThreat(EnemyBase enemy, GameObject caster) + { + if (enemy == null || caster == null || !enemy.UseThreatSystem) + return; + + GameObject highestThreatTarget = enemy.GetHighestThreatTarget(); + float highestThreat = highestThreatTarget != null ? enemy.GetThreat(highestThreatTarget) : 0f; + float currentCasterThreat = enemy.GetThreat(caster); + + float desiredThreat = Mathf.Max(currentCasterThreat + flatThreatAmount, highestThreat + threatLeadBonus + flatThreatAmount); + enemy.SetThreat(caster, desiredThreat); + } + } +} diff --git a/Assets/_Game/Scripts/Skills/Effects/TauntEffect.cs.meta b/Assets/_Game/Scripts/Skills/Effects/TauntEffect.cs.meta new file mode 100644 index 00000000..22c2c4de --- /dev/null +++ b/Assets/_Game/Scripts/Skills/Effects/TauntEffect.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: bd72562b167fced4191f12bd3a86d341 \ No newline at end of file diff --git a/Assets/_Game/Scripts/Skills/Effects/ThreatModifierEffect.cs b/Assets/_Game/Scripts/Skills/Effects/ThreatModifierEffect.cs new file mode 100644 index 00000000..0cd72c53 --- /dev/null +++ b/Assets/_Game/Scripts/Skills/Effects/ThreatModifierEffect.cs @@ -0,0 +1,34 @@ +using UnityEngine; + +using Colosseum.Combat; + +namespace Colosseum.Skills.Effects +{ + /// + /// 시전자 또는 대상의 위협 생성 배율을 일정 시간 증가시킵니다. + /// + [CreateAssetMenu(fileName = "ThreatModifierEffect", menuName = "Colosseum/Skills/Effects/Threat Modifier")] + public class ThreatModifierEffect : SkillEffect + { + [Header("Threat Modifier")] + [Tooltip("적용할 위협 생성 배율")] + [Min(0f)] [SerializeField] private float threatMultiplier = 1.5f; + + [Tooltip("배율 지속 시간")] + [Min(0f)] [SerializeField] private float duration = 5f; + + protected override void ApplyEffect(GameObject caster, GameObject target) + { + if (target == null || threatMultiplier <= 0f || duration <= 0f) + return; + + ThreatController threatController = target.GetComponent(); + if (threatController == null) + { + threatController = target.AddComponent(); + } + + threatController.ApplyThreatMultiplier(threatMultiplier, duration); + } + } +} diff --git a/Assets/_Game/Scripts/Skills/Effects/ThreatModifierEffect.cs.meta b/Assets/_Game/Scripts/Skills/Effects/ThreatModifierEffect.cs.meta new file mode 100644 index 00000000..86ce8767 --- /dev/null +++ b/Assets/_Game/Scripts/Skills/Effects/ThreatModifierEffect.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ae36db0b9307b554bae67c8825a36b99 \ No newline at end of file diff --git a/Assets/_Game/Scripts/Skills/SkillEffect.cs b/Assets/_Game/Scripts/Skills/SkillEffect.cs index aaa5bb6b..3a8fbd73 100644 --- a/Assets/_Game/Scripts/Skills/SkillEffect.cs +++ b/Assets/_Game/Scripts/Skills/SkillEffect.cs @@ -22,6 +22,8 @@ namespace Colosseum.Skills [SerializeField] protected AreaCenterType areaCenter = AreaCenterType.Caster; [SerializeField] protected AreaShapeType areaShape = AreaShapeType.Sphere; [SerializeField] protected LayerMask targetLayers; + [Tooltip("Area 범위 효과일 때 시전자 본인 포함 여부")] + [SerializeField] protected bool includeCasterInArea = false; [Header("Sphere Settings")] [Min(0.1f)] [SerializeField] protected float areaRadius = 3f; @@ -42,6 +44,7 @@ namespace Colosseum.Skills public float FanOriginDistance => fanOriginDistance; public float FanRadius => fanRadius; public float FanHalfAngle => fanHalfAngle; + public bool IncludeCasterInArea => includeCasterInArea; /// /// 스킬 시전 시 호출 @@ -115,7 +118,7 @@ namespace Colosseum.Skills HashSet processedTargets = new HashSet(); foreach (var hit in hits) { - if (hit.gameObject == caster) continue; + if (!includeCasterInArea && hit.gameObject == caster) continue; if (!IsCorrectTeam(caster, hit.gameObject)) continue; if (processedTargets.Contains(hit.gameObject)) continue; // 부채꼴 판정 diff --git a/Assets/_Game/Scripts/UI/PlayerHUD.cs b/Assets/_Game/Scripts/UI/PlayerHUD.cs index cd665ce6..f039fdb2 100644 --- a/Assets/_Game/Scripts/UI/PlayerHUD.cs +++ b/Assets/_Game/Scripts/UI/PlayerHUD.cs @@ -77,6 +77,7 @@ namespace Colosseum.UI targetPlayer.OnHealthChanged += HandleHealthChanged; targetPlayer.OnManaChanged += HandleManaChanged; + targetPlayer.OnShieldChanged += HandleShieldChanged; } private void UnsubscribeFromEvents() @@ -85,13 +86,14 @@ namespace Colosseum.UI targetPlayer.OnHealthChanged -= HandleHealthChanged; targetPlayer.OnManaChanged -= HandleManaChanged; + targetPlayer.OnShieldChanged -= HandleShieldChanged; } private void HandleHealthChanged(float oldValue, float newValue) { if (healthBar != null && targetPlayer != null) { - healthBar.SetValue(newValue, targetPlayer.MaxHealth); + healthBar.SetValue(newValue, targetPlayer.MaxHealth, targetPlayer.Shield); } } @@ -103,13 +105,21 @@ namespace Colosseum.UI } } + private void HandleShieldChanged(float oldValue, float newValue) + { + if (healthBar != null && targetPlayer != null) + { + healthBar.SetValue(targetPlayer.Health, targetPlayer.MaxHealth, newValue); + } + } + private void UpdateStatBars() { if (targetPlayer == null) return; if (healthBar != null) { - healthBar.SetValue(targetPlayer.Health, targetPlayer.MaxHealth); + healthBar.SetValue(targetPlayer.Health, targetPlayer.MaxHealth, targetPlayer.Shield); } if (manaBar != null) diff --git a/Assets/_Game/Scripts/UI/StatBar.cs b/Assets/_Game/Scripts/UI/StatBar.cs index fc1215d5..a6068c74 100644 --- a/Assets/_Game/Scripts/UI/StatBar.cs +++ b/Assets/_Game/Scripts/UI/StatBar.cs @@ -32,14 +32,24 @@ namespace Colosseum.UI private float currentValue; private float maxValue; private float displayValue; + private float bonusValue; /// /// 바 값 설정 /// public void SetValue(float current, float max) + { + SetValue(current, max, 0f); + } + + /// + /// 바 값과 보너스 수치를 함께 설정합니다. + /// + public void SetValue(float current, float max, float bonus) { currentValue = current; maxValue = max; + bonusValue = Mathf.Max(0f, bonus); if (!smoothTransition) { @@ -102,7 +112,14 @@ namespace Colosseum.UI // 텍스트 if (valueText != null) { - valueText.text = $"{Mathf.CeilToInt(displayValue)} / {Mathf.CeilToInt(maxValue)}"; + if (bonusValue > 0f) + { + valueText.text = $"{Mathf.CeilToInt(displayValue)} / {Mathf.CeilToInt(maxValue)} (+{Mathf.CeilToInt(bonusValue)})"; + } + else + { + valueText.text = $"{Mathf.CeilToInt(displayValue)} / {Mathf.CeilToInt(maxValue)}"; + } } }