diff --git a/Assets/_Game/Data/Loadouts/Data_LoadoutPreset_Player_상태복합젬테스트.asset b/Assets/_Game/Data/Loadouts/Data_LoadoutPreset_Player_상태복합젬테스트.asset new file mode 100644 index 00000000..9316e666 --- /dev/null +++ b/Assets/_Game/Data/Loadouts/Data_LoadoutPreset_Player_상태복합젬테스트.asset @@ -0,0 +1,48 @@ +%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: 26d5895a89de4f24aade1ea4b5f7644e, type: 3} + m_Name: "Data_LoadoutPreset_Player_\uC0C1\uD0DC\uBCF5\uD569\uC82C\uD14C\uC2A4\uD2B8" + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.PlayerLoadoutPreset + presetName: "\uC0C1\uD0DC \uBCF5\uD569 \uC82C \uD14C\uC2A4\uD2B8" + description: "\uAC15\uC778\uD568 + \uC57D\uD654 \uC82C\uC744 \uB3D9\uC2DC\uC5D0 + \uC0AC\uC6A9\uD574 \uC790\uAE30 \uAC15\uD654\uC640 \uC801\uC911 \uB514\uBC84\uD504\uB97C + \uD568\uAED8 \uAC80\uC99D\uD558\uB294 \uD504\uB9AC\uC14B" + slots: + - baseSkill: {fileID: 11400000, guid: b7f09e0e899c8fc4bb2cc9204cc6eb4a, type: 2} + socketedGems: + - {fileID: 0} + - {fileID: 0} + - baseSkill: {fileID: 11400000, guid: b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5, type: 2} + socketedGems: + - {fileID: 0} + - {fileID: 0} + - baseSkill: {fileID: 11400000, guid: d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1, type: 2} + socketedGems: + - {fileID: 0} + - {fileID: 0} + - baseSkill: {fileID: 11400000, guid: f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3, type: 2} + socketedGems: + - {fileID: 0} + - {fileID: 0} + - baseSkill: {fileID: 11400000, guid: b8c86399865e91144a3d6fcfddc04fd9, type: 2} + socketedGems: + - {fileID: 0} + - {fileID: 0} + - baseSkill: {fileID: 11400000, guid: 549a9978338eb504690c3c490acc0c60, type: 2} + socketedGems: + - {fileID: 11400000, guid: e020eee86f6c97f4393672759d73602e, type: 2} + - {fileID: 11400000, guid: 2edf7687dc6caa0489ae2111499fcfab, type: 2} + - {fileID: 0} + - baseSkill: {fileID: 11400000, guid: 2ed15dca92a165046b6df17b28f64874, type: 2} + socketedGems: + - {fileID: 0} + - {fileID: 0} diff --git a/Assets/_Game/Data/Loadouts/Data_LoadoutPreset_Player_상태복합젬테스트.asset.meta b/Assets/_Game/Data/Loadouts/Data_LoadoutPreset_Player_상태복합젬테스트.asset.meta new file mode 100644 index 00000000..2132c268 --- /dev/null +++ b/Assets/_Game/Data/Loadouts/Data_LoadoutPreset_Player_상태복합젬테스트.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e73dbec0f2d31484ea06a23369e88424 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Data/Loadouts/Data_LoadoutPreset_Player_자기강화젬테스트.asset b/Assets/_Game/Data/Loadouts/Data_LoadoutPreset_Player_자기강화젬테스트.asset new file mode 100644 index 00000000..744e254a --- /dev/null +++ b/Assets/_Game/Data/Loadouts/Data_LoadoutPreset_Player_자기강화젬테스트.asset @@ -0,0 +1,47 @@ +%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: 26d5895a89de4f24aade1ea4b5f7644e, type: 3} + m_Name: "Data_LoadoutPreset_Player_\uC790\uAE30\uAC15\uD654\uC82C\uD14C\uC2A4\uD2B8" + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.PlayerLoadoutPreset + presetName: "\uC790\uAE30\uAC15\uD654 \uC82C \uD14C\uC2A4\uD2B8" + description: "\uAC15\uC778\uD568 \uC82C\uC73C\uB85C \uC2DC\uC804 \uC2DC \uC790\uAE30 + \uAC15\uD654 \uC0C1\uD0DC\uB97C \uAC80\uC99D\uD558\uB294 \uD504\uB9AC\uC14B" + slots: + - baseSkill: {fileID: 11400000, guid: b7f09e0e899c8fc4bb2cc9204cc6eb4a, type: 2} + socketedGems: + - {fileID: 0} + - {fileID: 0} + - baseSkill: {fileID: 11400000, guid: b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5, type: 2} + socketedGems: + - {fileID: 0} + - {fileID: 0} + - baseSkill: {fileID: 11400000, guid: d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1, type: 2} + socketedGems: + - {fileID: 0} + - {fileID: 0} + - baseSkill: {fileID: 11400000, guid: f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3, type: 2} + socketedGems: + - {fileID: 0} + - {fileID: 0} + - baseSkill: {fileID: 11400000, guid: b8c86399865e91144a3d6fcfddc04fd9, type: 2} + socketedGems: + - {fileID: 0} + - {fileID: 0} + - baseSkill: {fileID: 11400000, guid: 549a9978338eb504690c3c490acc0c60, type: 2} + socketedGems: + - {fileID: 11400000, guid: e020eee86f6c97f4393672759d73602e, type: 2} + - {fileID: 0} + - {fileID: 0} + - baseSkill: {fileID: 11400000, guid: 2ed15dca92a165046b6df17b28f64874, type: 2} + socketedGems: + - {fileID: 0} + - {fileID: 0} diff --git a/Assets/_Game/Data/Loadouts/Data_LoadoutPreset_Player_자기강화젬테스트.asset.meta b/Assets/_Game/Data/Loadouts/Data_LoadoutPreset_Player_자기강화젬테스트.asset.meta new file mode 100644 index 00000000..35dcd86d --- /dev/null +++ b/Assets/_Game/Data/Loadouts/Data_LoadoutPreset_Player_자기강화젬테스트.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4939a9da2935f744389326250b0edf69 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Data/Loadouts/Data_LoadoutPreset_Player_적중이상젬테스트.asset b/Assets/_Game/Data/Loadouts/Data_LoadoutPreset_Player_적중이상젬테스트.asset new file mode 100644 index 00000000..6ed0c0a0 --- /dev/null +++ b/Assets/_Game/Data/Loadouts/Data_LoadoutPreset_Player_적중이상젬테스트.asset @@ -0,0 +1,47 @@ +%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: 26d5895a89de4f24aade1ea4b5f7644e, type: 3} + m_Name: "Data_LoadoutPreset_Player_\uC801\uC911\uC774\uC0C1\uC82C\uD14C\uC2A4\uD2B8" + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.PlayerLoadoutPreset + presetName: "\uC801\uC911 \uC774\uC0C1 \uC82C \uD14C\uC2A4\uD2B8" + description: "\uC57D\uD654 \uC82C\uC73C\uB85C \uC801\uC911 \uB300\uC0C1 \uB514\uBC84\uD504\uB97C + \uAC80\uC99D\uD558\uB294 \uD504\uB9AC\uC14B" + slots: + - baseSkill: {fileID: 11400000, guid: b7f09e0e899c8fc4bb2cc9204cc6eb4a, type: 2} + socketedGems: + - {fileID: 0} + - {fileID: 0} + - baseSkill: {fileID: 11400000, guid: b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5, type: 2} + socketedGems: + - {fileID: 0} + - {fileID: 0} + - baseSkill: {fileID: 11400000, guid: d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1, type: 2} + socketedGems: + - {fileID: 0} + - {fileID: 0} + - baseSkill: {fileID: 11400000, guid: f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3, type: 2} + socketedGems: + - {fileID: 0} + - {fileID: 0} + - baseSkill: {fileID: 11400000, guid: b8c86399865e91144a3d6fcfddc04fd9, type: 2} + socketedGems: + - {fileID: 0} + - {fileID: 0} + - baseSkill: {fileID: 11400000, guid: 549a9978338eb504690c3c490acc0c60, type: 2} + socketedGems: + - {fileID: 11400000, guid: 2edf7687dc6caa0489ae2111499fcfab, type: 2} + - {fileID: 0} + - {fileID: 0} + - baseSkill: {fileID: 11400000, guid: 2ed15dca92a165046b6df17b28f64874, type: 2} + socketedGems: + - {fileID: 0} + - {fileID: 0} diff --git a/Assets/_Game/Data/Loadouts/Data_LoadoutPreset_Player_적중이상젬테스트.asset.meta b/Assets/_Game/Data/Loadouts/Data_LoadoutPreset_Player_적중이상젬테스트.asset.meta new file mode 100644 index 00000000..69c40104 --- /dev/null +++ b/Assets/_Game/Data/Loadouts/Data_LoadoutPreset_Player_적중이상젬테스트.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a2403161604e6984c82d7644e4c11ac2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_강인함.asset b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_강인함.asset new file mode 100644 index 00000000..21efd1e3 --- /dev/null +++ b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_강인함.asset @@ -0,0 +1,33 @@ +%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: e81a62ae7c7624847ab572ff37789bb8, type: 3} + m_Name: "Data_SkillGem_Player_\uAC15\uC778\uD568" + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.SkillGemData + gemName: "\uAC15\uC778\uD568" + description: "\uC2A4\uD0AC \uC0AC\uC6A9 \uC2DC \uC790\uC2E0\uC5D0\uAC8C \uACBD\uC9C1 + \uBA74\uC5ED\uC744 \uBD80\uC5EC\uD558\uB294 \uD14C\uC2A4\uD2B8\uC6A9 \uBC29\uC5B4 + \uC82C" + icon: {fileID: 0} + category: 3 + manaCostMultiplier: 1.05 + cooldownMultiplier: 1.05 + castSpeedMultiplier: 1 + damageMultiplier: 1 + healMultiplier: 1 + shieldMultiplier: 1 + threatMultiplier: 1 + additionalRepeatCount: 0 + castStartEffects: [] + triggeredEffects: [] + selfAbnormalities: + - {fileID: 11400000, guid: f4f55b61c9d04fd2b83b9c80e81fa0a2, type: 2} + onHitAbnormalities: [] diff --git a/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_강인함.asset.meta b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_강인함.asset.meta new file mode 100644 index 00000000..510d36a7 --- /dev/null +++ b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_강인함.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e020eee86f6c97f4393672759d73602e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_관통.asset b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_관통.asset index e85c599b..04f8b883 100644 --- a/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_관통.asset +++ b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_관통.asset @@ -20,9 +20,15 @@ MonoBehaviour: manaCostMultiplier: 1 cooldownMultiplier: 1 castSpeedMultiplier: 1 + damageMultiplier: 1 + healMultiplier: 1 + shieldMultiplier: 1 + threatMultiplier: 1 additionalRepeatCount: 0 castStartEffects: [] triggeredEffects: - triggerIndex: 0 effects: - {fileID: 11400000, guid: 2a467b25340d65f4a854350319f10d0a, type: 2} + selfAbnormalities: [] + onHitAbnormalities: [] diff --git a/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_도전자.asset b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_도전자.asset index 59d4acf1..875afed3 100644 --- a/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_도전자.asset +++ b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_도전자.asset @@ -20,9 +20,15 @@ MonoBehaviour: manaCostMultiplier: 1 cooldownMultiplier: 1 castSpeedMultiplier: 1 + damageMultiplier: 1 + healMultiplier: 1 + shieldMultiplier: 1 + threatMultiplier: 1.5 additionalRepeatCount: 0 castStartEffects: [] triggeredEffects: - triggerIndex: 0 effects: - {fileID: 11400000, guid: f0aaa98426be3d44082a386c00ea9aea, type: 2} + selfAbnormalities: [] + onHitAbnormalities: [] diff --git a/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_수호.asset b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_수호.asset index 0ad3abcc..7b72abba 100644 --- a/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_수호.asset +++ b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_수호.asset @@ -20,9 +20,15 @@ MonoBehaviour: manaCostMultiplier: 1.05 cooldownMultiplier: 1.1 castSpeedMultiplier: 1 + damageMultiplier: 1 + healMultiplier: 1.2 + shieldMultiplier: 1.5 + threatMultiplier: 1 additionalRepeatCount: 0 castStartEffects: [] triggeredEffects: - triggerIndex: 0 effects: - {fileID: 11400000, guid: 65ed1eabc2fb73d43b86230317222608, type: 2} + selfAbnormalities: [] + onHitAbnormalities: [] diff --git a/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_약화.asset b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_약화.asset new file mode 100644 index 00000000..5d32662e --- /dev/null +++ b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_약화.asset @@ -0,0 +1,34 @@ +%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: e81a62ae7c7624847ab572ff37789bb8, type: 3} + m_Name: "Data_SkillGem_Player_\uC57D\uD654" + m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.SkillGemData + gemName: "\uC57D\uD654" + description: "\uC2A4\uD0AC \uC801\uC911 \uB300\uC0C1\uC5D0\uAC8C \uD14C\uC2A4\uD2B8 + \uB514\uBC84\uD504\uB97C \uBD80\uC5EC\uD558\uB294 \uC81C\uC5B4 \uC82C" + icon: {fileID: 0} + category: 5 + manaCostMultiplier: 1.05 + cooldownMultiplier: 1.05 + castSpeedMultiplier: 1 + damageMultiplier: 1 + healMultiplier: 1 + shieldMultiplier: 1 + threatMultiplier: 1 + additionalRepeatCount: 0 + castStartEffects: [] + triggeredEffects: [] + selfAbnormalities: [] + onHitAbnormalities: + - triggerIndex: 0 + abnormalities: + - {fileID: 11400000, guid: c4abb0f89779f294ab99562e085e8f3b, type: 2} diff --git a/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_약화.asset.meta b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_약화.asset.meta new file mode 100644 index 00000000..551db6bf --- /dev/null +++ b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_약화.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2edf7687dc6caa0489ae2111499fcfab +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_연속.asset b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_연속.asset index ca80ae43..2d02723e 100644 --- a/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_연속.asset +++ b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_연속.asset @@ -20,6 +20,12 @@ MonoBehaviour: manaCostMultiplier: 1.2 cooldownMultiplier: 1.15 castSpeedMultiplier: 1.1 + damageMultiplier: 1 + healMultiplier: 1 + shieldMultiplier: 1 + threatMultiplier: 1 additionalRepeatCount: 1 castStartEffects: [] triggeredEffects: [] + selfAbnormalities: [] + onHitAbnormalities: [] diff --git a/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_예리함.asset b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_예리함.asset index bf58697b..2c7965e9 100644 --- a/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_예리함.asset +++ b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_예리함.asset @@ -20,9 +20,15 @@ MonoBehaviour: manaCostMultiplier: 1 cooldownMultiplier: 1 castSpeedMultiplier: 1 + damageMultiplier: 1 + healMultiplier: 1 + shieldMultiplier: 1 + threatMultiplier: 1 additionalRepeatCount: 0 castStartEffects: [] triggeredEffects: - triggerIndex: 0 effects: - {fileID: 11400000, guid: 197e5c38a24c95044a5959bb4c67f055, type: 2} + selfAbnormalities: [] + onHitAbnormalities: [] diff --git a/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_충격.asset b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_충격.asset index 107df785..f371fd14 100644 --- a/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_충격.asset +++ b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_충격.asset @@ -20,9 +20,15 @@ MonoBehaviour: manaCostMultiplier: 1 cooldownMultiplier: 1 castSpeedMultiplier: 1 + damageMultiplier: 1 + healMultiplier: 1 + shieldMultiplier: 1 + threatMultiplier: 1 additionalRepeatCount: 0 castStartEffects: [] triggeredEffects: - triggerIndex: 0 effects: - {fileID: 11400000, guid: 1a6d1b31b640d87499ef7c9e3580ed34, type: 2} + selfAbnormalities: [] + onHitAbnormalities: [] diff --git a/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_파쇄.asset b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_파쇄.asset index a6df4d56..a7eb0579 100644 --- a/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_파쇄.asset +++ b/Assets/_Game/Data/SkillGems/Data_SkillGem_Player_파쇄.asset @@ -20,9 +20,15 @@ MonoBehaviour: manaCostMultiplier: 1.15 cooldownMultiplier: 1.1 castSpeedMultiplier: 1 + damageMultiplier: 1.2 + healMultiplier: 1 + shieldMultiplier: 1 + threatMultiplier: 1 additionalRepeatCount: 0 castStartEffects: [] triggeredEffects: - triggerIndex: 0 effects: - {fileID: 11400000, guid: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4, type: 2} + selfAbnormalities: [] + onHitAbnormalities: [] diff --git a/Assets/_Game/Scripts/Editor/PlayerSkillDebugMenu.cs b/Assets/_Game/Scripts/Editor/PlayerSkillDebugMenu.cs index ba64d664..31474c0d 100644 --- a/Assets/_Game/Scripts/Editor/PlayerSkillDebugMenu.cs +++ b/Assets/_Game/Scripts/Editor/PlayerSkillDebugMenu.cs @@ -36,6 +36,8 @@ namespace Colosseum.Editor private const string StunAbnormalityPath = "Assets/_Game/Data/Abnormalities/Data_Abnormality_Player_Stun.asset"; private const string SilenceAbnormalityPath = "Assets/_Game/Data/Abnormalities/Data_Abnormality_Player_Silence.asset"; private const string MarkAbnormalityPath = "Assets/_Game/Data/Abnormalities/Data_Abnormality_Player_집행자의낙인.asset"; + private const string HitReactionImmuneAbnormalityPath = "Assets/_Game/Data/Abnormalities/Data_Abnormality_Player_경직면역.asset"; + private const string TestDebuffAbnormalityPath = "Assets/_Game/Data/Abnormalities/Data_Abnormality_Test_Debuff.asset"; private const string ShieldAbnormalityPath = "Assets/_Game/Data/Abnormalities/Data_Abnormality_Common_보호막.asset"; private const string ShieldTypeAPath = "Assets/_Game/Data/Abnormalities/Data_Abnormality_Test_보호막A.asset"; private const string ShieldTypeBPath = "Assets/_Game/Data/Abnormalities/Data_Abnormality_Test_보호막B.asset"; @@ -45,6 +47,8 @@ namespace Colosseum.Editor private const string ChallengerGemPath = SkillGemFolderPath + "/Data_SkillGem_Player_도전자.asset"; private const string GuardianGemPath = SkillGemFolderPath + "/Data_SkillGem_Player_수호.asset"; private const string RepeatGemPath = SkillGemFolderPath + "/Data_SkillGem_Player_연속.asset"; + private const string FortitudeGemPath = SkillGemFolderPath + "/Data_SkillGem_Player_강인함.asset"; + private const string WitherGemPath = SkillGemFolderPath + "/Data_SkillGem_Player_약화.asset"; private const string EdgeGemPath = SkillGemFolderPath + "/Data_SkillGem_Player_예리함.asset"; private const string ImpactGemPath = SkillGemFolderPath + "/Data_SkillGem_Player_충격.asset"; private const string BreachGemPath = SkillGemFolderPath + "/Data_SkillGem_Player_관통.asset"; @@ -55,6 +59,9 @@ namespace Colosseum.Editor private const string SupportGemPresetPath = LoadoutPresetFolderPath + "/Data_LoadoutPreset_Player_지원_젬테스트.asset"; private const string DpsGemPresetPath = LoadoutPresetFolderPath + "/Data_LoadoutPreset_Player_딜러_젬테스트.asset"; private const string RepeatGemPresetPath = LoadoutPresetFolderPath + "/Data_LoadoutPreset_Player_반복젬테스트.asset"; + private const string SelfAbnormalityGemPresetPath = LoadoutPresetFolderPath + "/Data_LoadoutPreset_Player_자기강화젬테스트.asset"; + private const string OnHitAbnormalityGemPresetPath = LoadoutPresetFolderPath + "/Data_LoadoutPreset_Player_적중이상젬테스트.asset"; + private const string AbnormalityComboGemPresetPath = LoadoutPresetFolderPath + "/Data_LoadoutPreset_Player_상태복합젬테스트.asset"; private const string TankDualGemPresetPath = LoadoutPresetFolderPath + "/Data_LoadoutPreset_Player_탱커_복합젬테스트.asset"; private const string SupportDualGemPresetPath = LoadoutPresetFolderPath + "/Data_LoadoutPreset_Player_지원_복합젬테스트.asset"; private const string DpsDualGemPresetPath = LoadoutPresetFolderPath + "/Data_LoadoutPreset_Player_딜러_복합젬테스트.asset"; @@ -530,6 +537,24 @@ namespace Colosseum.Editor ApplyLoadoutPreset(RepeatGemPresetPath, "반복 젬"); } + [MenuItem("Tools/Colosseum/Debug/Apply Self Abnormality Gem Loadout")] + private static void ApplySelfAbnormalityGemLoadout() + { + ApplyLoadoutPreset(SelfAbnormalityGemPresetPath, "자기강화 젬"); + } + + [MenuItem("Tools/Colosseum/Debug/Apply On-Hit Abnormality Gem Loadout")] + private static void ApplyOnHitAbnormalityGemLoadout() + { + ApplyLoadoutPreset(OnHitAbnormalityGemPresetPath, "적중 이상 젬"); + } + + [MenuItem("Tools/Colosseum/Debug/Apply Abnormality Combo Gem Loadout")] + private static void ApplyAbnormalityComboGemLoadout() + { + ApplyLoadoutPreset(AbnormalityComboGemPresetPath, "상태 복합 젬"); + } + [MenuItem("Tools/Colosseum/Debug/Apply Tank Dual Gem Loadout")] private static void ApplyTankDualGemLoadout() { @@ -580,6 +605,8 @@ namespace Colosseum.Editor SkillEffect damageEffect = AssetDatabase.LoadAssetAtPath("Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_찌르기_0_데미지.asset"); SkillEffect tauntEffect = AssetDatabase.LoadAssetAtPath("Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_도발_0_도발.asset"); SkillEffect shieldEffect = AssetDatabase.LoadAssetAtPath("Assets/_Game/Data/Skills/Effects/Data_SkillEffect_Player_보호막_0_보호막.asset"); + AbnormalityData hitReactionImmuneAbnormality = AssetDatabase.LoadAssetAtPath(HitReactionImmuneAbnormalityPath); + AbnormalityData testDebuffAbnormality = AssetDatabase.LoadAssetAtPath(TestDebuffAbnormalityPath); DamageEffect edgeDamageEffect = CreateOrUpdateDamageEffectAsset(EdgeDamageEffectPath, 4f); DamageEffect impactDamageEffect = CreateOrUpdateDamageEffectAsset(ImpactDamageEffectPath, 7f); DamageEffect breachDamageEffect = CreateOrUpdateDamageEffectAsset(BreachDamageEffectPath, 10f); @@ -592,6 +619,10 @@ namespace Colosseum.Editor 1.15f, 1.1f, 1f, + 1.2f, + 1f, + 1f, + 1f, 0, damageEffect); @@ -603,6 +634,10 @@ namespace Colosseum.Editor 1f, 1f, 1f, + 1f, + 1f, + 1f, + 1.5f, 0, tauntEffect); @@ -614,6 +649,10 @@ namespace Colosseum.Editor 1.05f, 1.1f, 1f, + 1f, + 1.2f, + 1.5f, + 1f, 0, shieldEffect); @@ -625,9 +664,47 @@ namespace Colosseum.Editor 1.2f, 1.15f, 1.1f, + 1f, + 1f, + 1f, + 1f, 1, null); + CreateOrUpdateGemAsset( + FortitudeGemPath, + "강인함", + "스킬 사용 시 자신에게 경직 면역을 부여하는 테스트용 방어 젬", + SkillGemCategory.Defense, + 1.05f, + 1.05f, + 1f, + 1f, + 1f, + 1f, + 1f, + 0, + null, + new[] { hitReactionImmuneAbnormality }); + + CreateOrUpdateGemAsset( + WitherGemPath, + "약화", + "스킬 적중 대상에게 테스트 디버프를 부여하는 제어 젬", + SkillGemCategory.Control, + 1.05f, + 1.05f, + 1f, + 1f, + 1f, + 1f, + 1f, + 0, + null, + null, + 0, + new[] { testDebuffAbnormality }); + CreateOrUpdateGemAsset( EdgeGemPath, "예리함", @@ -636,6 +713,10 @@ namespace Colosseum.Editor 1f, 1f, 1f, + 1f, + 1f, + 1f, + 1f, 0, edgeDamageEffect); @@ -647,6 +728,10 @@ namespace Colosseum.Editor 1f, 1f, 1f, + 1f, + 1f, + 1f, + 1f, 0, impactDamageEffect); @@ -658,6 +743,10 @@ namespace Colosseum.Editor 1f, 1f, 1f, + 1f, + 1f, + 1f, + 1f, 0, breachDamageEffect); @@ -691,6 +780,8 @@ namespace Colosseum.Editor SkillGemData challengerGem = AssetDatabase.LoadAssetAtPath(ChallengerGemPath); SkillGemData guardianGem = AssetDatabase.LoadAssetAtPath(GuardianGemPath); SkillGemData repeatGem = AssetDatabase.LoadAssetAtPath(RepeatGemPath); + SkillGemData fortitudeGem = AssetDatabase.LoadAssetAtPath(FortitudeGemPath); + SkillGemData witherGem = AssetDatabase.LoadAssetAtPath(WitherGemPath); SkillGemData edgeGem = AssetDatabase.LoadAssetAtPath(EdgeGemPath); SkillGemData impactGem = AssetDatabase.LoadAssetAtPath(ImpactGemPath); SkillGemData breachGem = AssetDatabase.LoadAssetAtPath(BreachGemPath); @@ -749,6 +840,45 @@ namespace Colosseum.Editor CreateEntry(gemTestSkill, repeatGem), CreateEntry(evadeSkill))); + CreateOrUpdatePresetAsset( + SelfAbnormalityGemPresetPath, + "자기강화 젬 테스트", + "강인함 젬으로 시전 시 자기 강화 상태를 검증하는 프리셋", + CreateLoadoutEntries( + CreateEntry(slashSkill), + CreateEntry(pierceSkill), + CreateEntry(spinSkill), + CreateEntry(dashSkill), + CreateEntry(projectileSkill), + CreateEntry(gemTestSkill, fortitudeGem), + CreateEntry(evadeSkill))); + + CreateOrUpdatePresetAsset( + OnHitAbnormalityGemPresetPath, + "적중 이상 젬 테스트", + "약화 젬으로 적중 대상 디버프를 검증하는 프리셋", + CreateLoadoutEntries( + CreateEntry(slashSkill), + CreateEntry(pierceSkill), + CreateEntry(spinSkill), + CreateEntry(dashSkill), + CreateEntry(projectileSkill), + CreateEntry(gemTestSkill, witherGem), + CreateEntry(evadeSkill))); + + CreateOrUpdatePresetAsset( + AbnormalityComboGemPresetPath, + "상태 복합 젬 테스트", + "강인함 + 약화 젬을 동시에 사용해 자기 강화와 적중 디버프를 함께 검증하는 프리셋", + CreateLoadoutEntries( + CreateEntry(slashSkill), + CreateEntry(pierceSkill), + CreateEntry(spinSkill), + CreateEntry(dashSkill), + CreateEntry(projectileSkill), + CreateEntry(gemTestSkill, fortitudeGem, witherGem), + CreateEntry(evadeSkill))); + CreateOrUpdatePresetAsset( TankDualGemPresetPath, "탱커 복합 젬 테스트", @@ -907,6 +1037,10 @@ namespace Colosseum.Editor float resolvedCooldown = loadoutEntry.GetResolvedCooldown(); float resolvedAnimationSpeed = loadoutEntry.GetResolvedAnimationSpeed(); int resolvedRepeatCount = loadoutEntry.GetResolvedRepeatCount(); + float resolvedDamageMultiplier = loadoutEntry.GetResolvedDamageMultiplier(); + float resolvedHealMultiplier = loadoutEntry.GetResolvedHealMultiplier(); + float resolvedShieldMultiplier = loadoutEntry.GetResolvedShieldMultiplier(); + float resolvedThreatMultiplier = loadoutEntry.GetResolvedThreatMultiplier(); StringBuilder builder = new StringBuilder(); builder.Append("[Debug] 6번 슬롯 계산값 | "); @@ -920,6 +1054,14 @@ namespace Colosseum.Editor builder.Append(resolvedAnimationSpeed.ToString("0.###")); builder.Append(" | Repeat="); builder.Append(resolvedRepeatCount); + builder.Append(" | Dmg="); + builder.Append(resolvedDamageMultiplier.ToString("0.###")); + builder.Append(" | Heal="); + builder.Append(resolvedHealMultiplier.ToString("0.###")); + builder.Append(" | Shield="); + builder.Append(resolvedShieldMultiplier.ToString("0.###")); + builder.Append(" | Threat="); + builder.Append(resolvedThreatMultiplier.ToString("0.###")); builder.Append(" | GemSlots="); builder.Append(loadoutEntry.SocketedGems.Count); AppendGemCategorySummary(builder, loadoutEntry); @@ -1164,8 +1306,15 @@ namespace Colosseum.Editor float manaCostMultiplier, float cooldownMultiplier, float castSpeedMultiplier, + float damageMultiplier, + float healMultiplier, + float shieldMultiplier, + float threatMultiplier, int additionalRepeatCount, - SkillEffect triggeredEffect) + SkillEffect triggeredEffect, + AbnormalityData[] selfAbnormalities = null, + int triggeredAbnormalityIndex = -1, + AbnormalityData[] onHitAbnormalities = null) { SkillGemData gem = AssetDatabase.LoadAssetAtPath(assetPath); if (gem == null) @@ -1186,11 +1335,22 @@ namespace Colosseum.Editor serializedGem.FindProperty("manaCostMultiplier").floatValue = manaCostMultiplier; serializedGem.FindProperty("cooldownMultiplier").floatValue = cooldownMultiplier; serializedGem.FindProperty("castSpeedMultiplier").floatValue = castSpeedMultiplier; + serializedGem.FindProperty("damageMultiplier").floatValue = damageMultiplier; + serializedGem.FindProperty("healMultiplier").floatValue = healMultiplier; + serializedGem.FindProperty("shieldMultiplier").floatValue = shieldMultiplier; + serializedGem.FindProperty("threatMultiplier").floatValue = threatMultiplier; serializedGem.FindProperty("additionalRepeatCount").intValue = additionalRepeatCount; SerializedProperty castStartEffectsProperty = serializedGem.FindProperty("castStartEffects"); castStartEffectsProperty.arraySize = 0; + SerializedProperty selfAbnormalitiesProperty = serializedGem.FindProperty("selfAbnormalities"); + selfAbnormalitiesProperty.arraySize = selfAbnormalities != null ? selfAbnormalities.Length : 0; + for (int i = 0; i < selfAbnormalitiesProperty.arraySize; i++) + { + selfAbnormalitiesProperty.GetArrayElementAtIndex(i).objectReferenceValue = selfAbnormalities[i]; + } + SerializedProperty triggeredEffectsProperty = serializedGem.FindProperty("triggeredEffects"); triggeredEffectsProperty.arraySize = triggeredEffect != null ? 1 : 0; if (triggeredEffect != null) @@ -1203,6 +1363,24 @@ namespace Colosseum.Editor effectArray.GetArrayElementAtIndex(0).objectReferenceValue = triggeredEffect; } + SerializedProperty onHitAbnormalitiesProperty = serializedGem.FindProperty("onHitAbnormalities"); + bool hasTriggeredAbnormalities = onHitAbnormalities != null && + onHitAbnormalities.Length > 0 && + triggeredAbnormalityIndex >= 0; + onHitAbnormalitiesProperty.arraySize = hasTriggeredAbnormalities ? 1 : 0; + if (hasTriggeredAbnormalities) + { + SerializedProperty abnormalityEntry = onHitAbnormalitiesProperty.GetArrayElementAtIndex(0); + abnormalityEntry.FindPropertyRelative("triggerIndex").intValue = triggeredAbnormalityIndex; + + SerializedProperty abnormalityArray = abnormalityEntry.FindPropertyRelative("abnormalities"); + abnormalityArray.arraySize = onHitAbnormalities.Length; + for (int i = 0; i < onHitAbnormalities.Length; i++) + { + abnormalityArray.GetArrayElementAtIndex(i).objectReferenceValue = onHitAbnormalities[i]; + } + } + serializedGem.ApplyModifiedPropertiesWithoutUndo(); EditorUtility.SetDirty(gem); } diff --git a/Assets/_Game/Scripts/Skills/Effects/CombatBuffEffect.cs b/Assets/_Game/Scripts/Skills/Effects/CombatBuffEffect.cs index 3be66bda..2b81856d 100644 --- a/Assets/_Game/Scripts/Skills/Effects/CombatBuffEffect.cs +++ b/Assets/_Game/Scripts/Skills/Effects/CombatBuffEffect.cs @@ -2,6 +2,7 @@ using UnityEngine; using Colosseum.Abnormalities; using Colosseum.Combat; +using Colosseum.Skills; namespace Colosseum.Skills.Effects { @@ -28,7 +29,7 @@ namespace Colosseum.Skills.Effects return; ApplyAbnormality(target, caster); - ApplyThreatMultiplier(target); + ApplyThreatMultiplier(target, caster); } private void ApplyAbnormality(GameObject target, GameObject caster) @@ -43,7 +44,7 @@ namespace Colosseum.Skills.Effects abnormalityManager.ApplyAbnormality(abnormalityData, caster); } - private void ApplyThreatMultiplier(GameObject target) + private void ApplyThreatMultiplier(GameObject target, GameObject caster) { if (threatMultiplier <= 0f || threatMultiplierDuration <= 0f) return; @@ -54,7 +55,8 @@ namespace Colosseum.Skills.Effects threatController = target.AddComponent(); } - threatController.ApplyThreatMultiplier(threatMultiplier, threatMultiplierDuration); + float resolvedThreatMultiplier = SkillRuntimeModifierUtility.GetThreatMultiplier(caster); + threatController.ApplyThreatMultiplier(threatMultiplier * resolvedThreatMultiplier, threatMultiplierDuration); } } } diff --git a/Assets/_Game/Scripts/Skills/Effects/DamageEffect.cs b/Assets/_Game/Scripts/Skills/Effects/DamageEffect.cs index e5e97da2..f1e01087 100644 --- a/Assets/_Game/Scripts/Skills/Effects/DamageEffect.cs +++ b/Assets/_Game/Scripts/Skills/Effects/DamageEffect.cs @@ -2,6 +2,7 @@ using UnityEngine; using Colosseum.Stats; using Colosseum.Combat; +using Colosseum.Skills; using Colosseum.Weapons; namespace Colosseum.Skills.Effects @@ -73,7 +74,8 @@ namespace Colosseum.Skills.Effects // 무기 데미지 배율 적용 float damageMultiplier = GetDamageMultiplier(caster); - return baseTotal * damageMultiplier; + float gemMultiplier = SkillRuntimeModifierUtility.GetDamageMultiplier(caster); + return baseTotal * damageMultiplier * gemMultiplier; } /// diff --git a/Assets/_Game/Scripts/Skills/Effects/HealEffect.cs b/Assets/_Game/Scripts/Skills/Effects/HealEffect.cs index e1329415..a6c6ab8f 100644 --- a/Assets/_Game/Scripts/Skills/Effects/HealEffect.cs +++ b/Assets/_Game/Scripts/Skills/Effects/HealEffect.cs @@ -2,6 +2,7 @@ using UnityEngine; using Colosseum.Stats; using Colosseum.Combat; +using Colosseum.Skills; namespace Colosseum.Skills.Effects { @@ -41,10 +42,11 @@ namespace Colosseum.Skills.Effects var stats = caster.GetComponent(); if (stats == null) { - return baseHeal; + return baseHeal * SkillRuntimeModifierUtility.GetHealMultiplier(caster); } - return baseHeal + (stats.HealPower * healScaling); + float resolvedHeal = baseHeal + (stats.HealPower * healScaling); + return resolvedHeal * SkillRuntimeModifierUtility.GetHealMultiplier(caster); } } } diff --git a/Assets/_Game/Scripts/Skills/Effects/ShieldEffect.cs b/Assets/_Game/Scripts/Skills/Effects/ShieldEffect.cs index bc1b5243..80d3bce7 100644 --- a/Assets/_Game/Scripts/Skills/Effects/ShieldEffect.cs +++ b/Assets/_Game/Scripts/Skills/Effects/ShieldEffect.cs @@ -5,6 +5,7 @@ using Colosseum.Enemy; using Colosseum.Player; using Colosseum.Stats; using Colosseum.Combat; +using Colosseum.Skills; namespace Colosseum.Skills.Effects { @@ -55,9 +56,10 @@ namespace Colosseum.Skills.Effects { CharacterStats stats = caster != null ? caster.GetComponent() : null; if (stats == null) - return baseShield; + return baseShield * SkillRuntimeModifierUtility.GetShieldMultiplier(caster); - return baseShield + (stats.HealPower * shieldScaling); + float resolvedShield = baseShield + (stats.HealPower * shieldScaling); + return resolvedShield * SkillRuntimeModifierUtility.GetShieldMultiplier(caster); } } } diff --git a/Assets/_Game/Scripts/Skills/Effects/TauntEffect.cs b/Assets/_Game/Scripts/Skills/Effects/TauntEffect.cs index 216b98cb..601b52a7 100644 --- a/Assets/_Game/Scripts/Skills/Effects/TauntEffect.cs +++ b/Assets/_Game/Scripts/Skills/Effects/TauntEffect.cs @@ -4,6 +4,7 @@ using UnityEngine; using Colosseum.Combat; using Colosseum.Enemy; +using Colosseum.Skills; namespace Colosseum.Skills.Effects { @@ -62,13 +63,14 @@ namespace Colosseum.Skills.Effects if (selfThreatMultiplier <= 0f || selfThreatMultiplierDuration <= 0f) return; + float resolvedThreatMultiplier = SkillRuntimeModifierUtility.GetThreatMultiplier(caster); ThreatController threatController = caster.GetComponent(); if (threatController == null) { threatController = caster.AddComponent(); } - threatController.ApplyThreatMultiplier(selfThreatMultiplier, selfThreatMultiplierDuration); + threatController.ApplyThreatMultiplier(selfThreatMultiplier * resolvedThreatMultiplier, selfThreatMultiplierDuration); } private void ApplyTauntThreat(EnemyBase enemy, GameObject caster) @@ -76,11 +78,14 @@ namespace Colosseum.Skills.Effects if (enemy == null || caster == null || !enemy.UseThreatSystem) return; + float resolvedThreatMultiplier = SkillRuntimeModifierUtility.GetThreatMultiplier(caster); 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); + float resolvedFlatThreat = flatThreatAmount * resolvedThreatMultiplier; + float resolvedLeadBonus = threatLeadBonus * resolvedThreatMultiplier; + float desiredThreat = Mathf.Max(currentCasterThreat + resolvedFlatThreat, highestThreat + resolvedLeadBonus + resolvedFlatThreat); enemy.SetThreat(caster, desiredThreat); CombatBalanceTracker.RecordThreat(caster, Mathf.Max(0f, desiredThreat - currentCasterThreat)); } diff --git a/Assets/_Game/Scripts/Skills/Effects/ThreatModifierEffect.cs b/Assets/_Game/Scripts/Skills/Effects/ThreatModifierEffect.cs index 0cd72c53..92b66d8b 100644 --- a/Assets/_Game/Scripts/Skills/Effects/ThreatModifierEffect.cs +++ b/Assets/_Game/Scripts/Skills/Effects/ThreatModifierEffect.cs @@ -1,6 +1,7 @@ using UnityEngine; using Colosseum.Combat; +using Colosseum.Skills; namespace Colosseum.Skills.Effects { @@ -28,7 +29,8 @@ namespace Colosseum.Skills.Effects threatController = target.AddComponent(); } - threatController.ApplyThreatMultiplier(threatMultiplier, duration); + float resolvedThreatMultiplier = SkillRuntimeModifierUtility.GetThreatMultiplier(caster); + threatController.ApplyThreatMultiplier(threatMultiplier * resolvedThreatMultiplier, duration); } } } diff --git a/Assets/_Game/Scripts/Skills/SkillController.cs b/Assets/_Game/Scripts/Skills/SkillController.cs index 47529d6a..4a116fd7 100644 --- a/Assets/_Game/Scripts/Skills/SkillController.cs +++ b/Assets/_Game/Scripts/Skills/SkillController.cs @@ -2,6 +2,8 @@ using UnityEngine; using System.Collections.Generic; using Unity.Netcode; +using Colosseum.Abnormalities; + namespace Colosseum.Skills { /// @@ -56,6 +58,9 @@ namespace Colosseum.Skills private SkillLoadoutEntry currentLoadoutEntry; private readonly List currentCastStartEffects = new(); private readonly Dictionary> currentTriggeredEffects = new(); + private readonly List currentCastStartAbnormalities = new(); + private readonly Dictionary> currentTriggeredAbnormalities = new(); + private readonly List currentTriggeredTargetsBuffer = new(); private bool waitingForEndAnimation; // EndAnimation 종료 대기 중 private int currentRepeatCount = 1; private int currentIterationIndex = 0; @@ -198,7 +203,7 @@ namespace Colosseum.Skills /// private void TriggerCastStartEffects() { - if (currentSkill == null || currentCastStartEffects.Count == 0) + if (currentSkill == null) return; if (NetworkManager.Singleton != null && !NetworkManager.Singleton.IsServer) @@ -213,6 +218,26 @@ namespace Colosseum.Skills if (debugMode) Debug.Log($"[Skill] Cast start effect: {effect.name} (index {i})"); effect.ExecuteOnCast(gameObject); } + + if (currentCastStartAbnormalities.Count <= 0) + return; + + AbnormalityManager abnormalityManager = GetComponent(); + if (abnormalityManager == null) + { + if (debugMode) Debug.LogWarning("[Skill] Cast start abnormality skipped - no AbnormalityManager"); + return; + } + + for (int i = 0; i < currentCastStartAbnormalities.Count; i++) + { + AbnormalityData abnormality = currentCastStartAbnormalities[i]; + if (abnormality == null) + continue; + + if (debugMode) Debug.Log($"[Skill] Cast start abnormality: {abnormality.abnormalityName} (index {i})"); + abnormalityManager.ApplyAbnormality(abnormality, gameObject); + } } /// @@ -251,12 +276,16 @@ namespace Colosseum.Skills { currentCastStartEffects.Clear(); currentTriggeredEffects.Clear(); + currentCastStartAbnormalities.Clear(); + currentTriggeredAbnormalities.Clear(); if (loadoutEntry == null) return; loadoutEntry.CollectCastStartEffects(currentCastStartEffects); loadoutEntry.CollectTriggeredEffects(currentTriggeredEffects); + loadoutEntry.CollectCastStartAbnormalities(currentCastStartAbnormalities); + loadoutEntry.CollectTriggeredAbnormalities(currentTriggeredAbnormalities); } /// @@ -450,6 +479,8 @@ namespace Colosseum.Skills effect.ExecuteOnCast(gameObject); } + + ApplyTriggeredAbnormalities(index, effects); } /// @@ -529,9 +560,72 @@ namespace Colosseum.Skills currentLoadoutEntry = null; currentCastStartEffects.Clear(); currentTriggeredEffects.Clear(); + currentCastStartAbnormalities.Clear(); + currentTriggeredAbnormalities.Clear(); + currentTriggeredTargetsBuffer.Clear(); waitingForEndAnimation = false; currentRepeatCount = 1; currentIterationIndex = 0; } + + /// + /// 현재 트리거 인덱스에 연결된 젬 이상상태를 적중 대상에게 적용합니다. + /// + private void ApplyTriggeredAbnormalities(int index, List referenceEffects) + { + if (!currentTriggeredAbnormalities.TryGetValue(index, out List abnormalities) || + abnormalities == null || + abnormalities.Count == 0) + { + return; + } + + currentTriggeredTargetsBuffer.Clear(); + + for (int i = 0; i < referenceEffects.Count; i++) + { + SkillEffect effect = referenceEffects[i]; + if (effect == null || effect.TargetType == TargetType.Self) + continue; + + effect.CollectTargets(gameObject, currentTriggeredTargetsBuffer); + } + + if (currentTriggeredTargetsBuffer.Count == 0) + { + if (debugMode) + { + Debug.LogWarning($"[Skill] Trigger abnormality skipped - no hit target resolved for index {index}"); + } + return; + } + + for (int i = 0; i < currentTriggeredTargetsBuffer.Count; i++) + { + GameObject target = currentTriggeredTargetsBuffer[i]; + if (target == null) + continue; + + AbnormalityManager abnormalityManager = target.GetComponent(); + if (abnormalityManager == null) + continue; + + for (int j = 0; j < abnormalities.Count; j++) + { + AbnormalityData abnormality = abnormalities[j]; + if (abnormality == null) + continue; + + if (debugMode) + { + Debug.Log($"[Skill] Trigger abnormality: {abnormality.abnormalityName} -> {target.name} (index {index})"); + } + + abnormalityManager.ApplyAbnormality(abnormality, gameObject); + } + } + + currentTriggeredTargetsBuffer.Clear(); + } } } diff --git a/Assets/_Game/Scripts/Skills/SkillEffect.cs b/Assets/_Game/Scripts/Skills/SkillEffect.cs index 3a8fbd73..753daa9e 100644 --- a/Assets/_Game/Scripts/Skills/SkillEffect.cs +++ b/Assets/_Game/Scripts/Skills/SkillEffect.cs @@ -51,14 +51,32 @@ namespace Colosseum.Skills /// public void ExecuteOnCast(GameObject caster) { + List targets = new List(); + CollectTargets(caster, targets); + + for (int i = 0; i < targets.Count; i++) + { + ApplyEffect(caster, targets[i]); + } + } + + /// + /// 현재 효과가 영향을 줄 대상 목록을 수집합니다. + /// 젬의 적중 이상상태 적용 등에서 동일한 타겟 해석을 재사용하기 위한 경로입니다. + /// + public void CollectTargets(GameObject caster, List destination) + { + if (caster == null || destination == null) + return; + switch (targetType) { case TargetType.Self: - ApplyEffect(caster, caster); + AddUniqueTarget(destination, caster); break; case TargetType.Area: - ExecuteArea(caster); + CollectAreaTargets(caster, destination); break; } } @@ -110,17 +128,14 @@ namespace Colosseum.Skills }; } - private void ExecuteArea(GameObject caster) + private void CollectAreaTargets(GameObject caster, List destination) { Vector3 center = GetAreaCenter(caster); Collider[] hits = Physics.OverlapSphere(center, Mathf.Max(areaRadius, fanRadius), targetLayers); - // 같은 GameObject가 여러 콜라이더를 가질 수 있으므로 중복 제거 - HashSet processedTargets = new HashSet(); foreach (var hit in hits) { if (!includeCasterInArea && hit.gameObject == caster) continue; if (!IsCorrectTeam(caster, hit.gameObject)) continue; - if (processedTargets.Contains(hit.gameObject)) continue; // 부채꼴 판정 if (areaShape == AreaShapeType.Fan) { @@ -128,11 +143,18 @@ namespace Colosseum.Skills continue; } - processedTargets.Add(hit.gameObject); - ApplyEffect(caster, hit.gameObject); + AddUniqueTarget(destination, hit.gameObject); } } + private static void AddUniqueTarget(List destination, GameObject target) + { + if (target == null || destination.Contains(target)) + return; + + destination.Add(target); + } + /// /// 타겟이 부채꼴 범위 내에 있는지 확인 /// diff --git a/Assets/_Game/Scripts/Skills/SkillGemData.cs b/Assets/_Game/Scripts/Skills/SkillGemData.cs index fd3feced..6b879404 100644 --- a/Assets/_Game/Scripts/Skills/SkillGemData.cs +++ b/Assets/_Game/Scripts/Skills/SkillGemData.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using UnityEngine; +using Colosseum.Abnormalities; + namespace Colosseum.Skills { /// @@ -34,6 +36,21 @@ namespace Colosseum.Skills public IReadOnlyList Effects => effects; } + /// + /// 젬이 적중 대상에게 부여할 이상상태 목록입니다. + /// + [Serializable] + public class SkillGemTriggeredAbnormalityEntry + { + [Tooltip("OnEffect(index)와 매칭되는 애니메이션 이벤트 인덱스")] + [Min(0)] [SerializeField] private int triggerIndex = 0; + [Tooltip("해당 인덱스에서 적중 대상에게 부여할 이상상태")] + [SerializeField] private List abnormalities = new(); + + public int TriggerIndex => triggerIndex; + public IReadOnlyList Abnormalities => abnormalities; + } + /// /// 스킬의 기반 효과 위에 추가 동작을 덧붙이는 젬 데이터입니다. /// @@ -55,6 +72,14 @@ namespace Colosseum.Skills [Min(0f)] [SerializeField] private float cooldownMultiplier = 1f; [Tooltip("장착 시 스킬 애니메이션 재생 속도 배율")] [Min(0.1f)] [SerializeField] private float castSpeedMultiplier = 1f; + [Tooltip("장착 시 스킬이 만드는 피해량 배율")] + [Min(0f)] [SerializeField] private float damageMultiplier = 1f; + [Tooltip("장착 시 스킬이 만드는 회복량 배율")] + [Min(0f)] [SerializeField] private float healMultiplier = 1f; + [Tooltip("장착 시 스킬이 만드는 보호막량 배율")] + [Min(0f)] [SerializeField] private float shieldMultiplier = 1f; + [Tooltip("장착 시 스킬이 만드는 위협량 배율")] + [Min(0f)] [SerializeField] private float threatMultiplier = 1f; [Tooltip("기반 스킬 시전을 몇 회 더 반복할지 정의합니다. 현재는 계산/표시용으로만 사용됩니다.")] [Min(0)] [SerializeField] private int additionalRepeatCount = 0; @@ -64,6 +89,12 @@ namespace Colosseum.Skills [Tooltip("애니메이션 이벤트 인덱스별로 발동하는 추가 효과")] [SerializeField] private List triggeredEffects = new(); + [Header("이상상태 부여")] + [Tooltip("스킬 사용 시 자신에게 즉시 부여할 이상상태")] + [SerializeField] private List selfAbnormalities = new(); + [Tooltip("애니메이션 이벤트 인덱스별로 적중 대상에게 부여할 이상상태")] + [SerializeField] private List onHitAbnormalities = new(); + public string GemName => gemName; public string Description => description; public Sprite Icon => icon; @@ -71,8 +102,14 @@ namespace Colosseum.Skills public float ManaCostMultiplier => manaCostMultiplier; public float CooldownMultiplier => cooldownMultiplier; public float CastSpeedMultiplier => castSpeedMultiplier; + public float DamageMultiplier => damageMultiplier; + public float HealMultiplier => healMultiplier; + public float ShieldMultiplier => shieldMultiplier; + public float ThreatMultiplier => threatMultiplier; public int AdditionalRepeatCount => additionalRepeatCount; public IReadOnlyList CastStartEffects => castStartEffects; public IReadOnlyList TriggeredEffects => triggeredEffects; + public IReadOnlyList SelfAbnormalities => selfAbnormalities; + public IReadOnlyList OnHitAbnormalities => onHitAbnormalities; } } diff --git a/Assets/_Game/Scripts/Skills/SkillLoadoutEntry.cs b/Assets/_Game/Scripts/Skills/SkillLoadoutEntry.cs index 32a4dc76..00f232b9 100644 --- a/Assets/_Game/Scripts/Skills/SkillLoadoutEntry.cs +++ b/Assets/_Game/Scripts/Skills/SkillLoadoutEntry.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using UnityEngine; +using Colosseum.Abnormalities; + namespace Colosseum.Skills { /// @@ -156,6 +158,26 @@ namespace Colosseum.Skills return Mathf.Max(0.05f, resolved); } + public float GetResolvedDamageMultiplier() + { + return GetResolvedScalarMultiplier(gem => gem.DamageMultiplier); + } + + public float GetResolvedHealMultiplier() + { + return GetResolvedScalarMultiplier(gem => gem.HealMultiplier); + } + + public float GetResolvedShieldMultiplier() + { + return GetResolvedScalarMultiplier(gem => gem.ShieldMultiplier); + } + + public float GetResolvedThreatMultiplier() + { + return GetResolvedScalarMultiplier(gem => gem.ThreatMultiplier); + } + public int GetResolvedRepeatCount() { if (baseSkill == null) @@ -210,6 +232,26 @@ namespace Colosseum.Skills } } + public void CollectCastStartAbnormalities(List destination) + { + if (destination == null || socketedGems == null) + return; + + for (int i = 0; i < socketedGems.Length; i++) + { + SkillGemData gem = socketedGems[i]; + if (gem == null || gem.SelfAbnormalities == null) + continue; + + for (int j = 0; j < gem.SelfAbnormalities.Count; j++) + { + AbnormalityData abnormality = gem.SelfAbnormalities[j]; + if (abnormality != null) + destination.Add(abnormality); + } + } + } + public void CollectTriggeredEffects(Dictionary> destination) { if (destination == null) @@ -254,6 +296,35 @@ namespace Colosseum.Skills } } + public void CollectTriggeredAbnormalities(Dictionary> destination) + { + if (destination == null || socketedGems == null) + return; + + for (int i = 0; i < socketedGems.Length; i++) + { + SkillGemData gem = socketedGems[i]; + if (gem == null || gem.OnHitAbnormalities == null) + continue; + + for (int j = 0; j < gem.OnHitAbnormalities.Count; j++) + { + SkillGemTriggeredAbnormalityEntry entry = gem.OnHitAbnormalities[j]; + if (entry == null || entry.Abnormalities == null) + continue; + + for (int k = 0; k < entry.Abnormalities.Count; k++) + { + AbnormalityData abnormality = entry.Abnormalities[k]; + if (abnormality == null) + continue; + + AddTriggeredAbnormality(destination, entry.TriggerIndex, abnormality); + } + } + } + } + private static void AddTriggeredEffect(Dictionary> destination, int triggerIndex, SkillEffect effect) { if (!destination.TryGetValue(triggerIndex, out List effectList)) @@ -264,5 +335,75 @@ namespace Colosseum.Skills effectList.Add(effect); } + + private static void AddTriggeredAbnormality(Dictionary> destination, int triggerIndex, AbnormalityData abnormality) + { + if (!destination.TryGetValue(triggerIndex, out List abnormalityList)) + { + abnormalityList = new List(); + destination.Add(triggerIndex, abnormalityList); + } + + abnormalityList.Add(abnormality); + } + + private float GetResolvedScalarMultiplier(System.Func selector) + { + if (baseSkill == null) + return 1f; + + float resolved = 1f; + if (socketedGems == null) + return resolved; + + for (int i = 0; i < socketedGems.Length; i++) + { + SkillGemData gem = socketedGems[i]; + if (gem == null) + continue; + + resolved *= Mathf.Max(0f, selector(gem)); + } + + return resolved; + } + } + + /// + /// 현재 시전 중인 스킬 로드아웃의 젬 보정값을 안전하게 조회하는 유틸리티입니다. + /// + public static class SkillRuntimeModifierUtility + { + public static float GetDamageMultiplier(GameObject caster) + { + return GetCurrentLoadout(caster)?.GetResolvedDamageMultiplier() ?? 1f; + } + + public static float GetHealMultiplier(GameObject caster) + { + return GetCurrentLoadout(caster)?.GetResolvedHealMultiplier() ?? 1f; + } + + public static float GetShieldMultiplier(GameObject caster) + { + return GetCurrentLoadout(caster)?.GetResolvedShieldMultiplier() ?? 1f; + } + + public static float GetThreatMultiplier(GameObject caster) + { + return GetCurrentLoadout(caster)?.GetResolvedThreatMultiplier() ?? 1f; + } + + private static SkillLoadoutEntry GetCurrentLoadout(GameObject caster) + { + if (caster == null) + return null; + + SkillController skillController = caster.GetComponent(); + if (skillController == null) + return null; + + return skillController.CurrentLoadoutEntry; + } } }