diff --git a/.claude/settings.local.json b/.claude/settings.local.json
index 4cf7fc51..f985ddfe 100644
--- a/.claude/settings.local.json
+++ b/.claude/settings.local.json
@@ -5,7 +5,13 @@
"Bash(git fsck:*)",
"Bash(git commit:*)",
"Bash(git read-tree:*)",
- "Bash(git push:*)"
+ "Bash(git push:*)",
+ "Bash(cd \"D:/Colosseum/Assets/Scripts/StatusEffects\" && sed -i 's/ActiveStatusEffect/ActiveStatusEffect/g' StatusEffectManager.cs)",
+ "Bash(cd \"D:/Colosseum/Assets/Scripts/UI\" && sed -i 's/ActiveStatusEffect/ActiveStatusEffect/g' StatusEffectUI.cs StatusEffectListUI.cs)",
+ "Bash(cd \"D:/Colosseum/Assets/Scripts\" && mv StatusEffects Abnormalities)",
+ "Bash(cd \"D:/Colosseum/Assets/Scripts/Abnormalities\" && mv StatusEffectData.cs AbnormalityData.cs && mv ActiveStatusEffect.cs ActiveAbnormality.cs && mv StatusEffectManager.cs AbnormalityManager.cs)",
+ "Bash(cd \"D:/Colosseum/Assets/Scripts/UI\" && mv StatusEffectUI.cs AbnormalitySlotUI.cs && mv StatusEffectListUI.cs AbnormalityListUI.cs)",
+ "Bash(git -C \"D:/Colosseum\" mv \"Assets/Scripts/Skills/Effects/BuffEffect.cs\" \"Assets/Scripts/Skills/Effects/AbnormalityEffect.cs\")"
]
}
}
diff --git a/Assets/Abnormalities.meta b/Assets/Abnormalities.meta
new file mode 100644
index 00000000..ef1f3c36
--- /dev/null
+++ b/Assets/Abnormalities.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 72b7a9faa543d444882609fe047a2073
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Abnormalities/Abnormality_Test_Buff.asset b/Assets/Abnormalities/Abnormality_Test_Buff.asset
new file mode 100644
index 00000000..c3e4f6be
--- /dev/null
+++ b/Assets/Abnormalities/Abnormality_Test_Buff.asset
@@ -0,0 +1,24 @@
+%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: b08cc671f858a3b409170a5356e960a0, type: 3}
+ m_Name: Abnormality_Test_Buff
+ m_EditorClassIdentifier: Colosseum.Game::Colosseum.Abnormalities.AbnormalityData
+ abnormalityName: Abnormality
+ icon: {fileID: 21300000, guid: 173f7bf0258285c4f8bf01825ac02a11, type: 3}
+ duration: 99
+ level: 1
+ isDebuff: 0
+ statModifiers: []
+ periodicInterval: 0
+ periodicValue: 0
+ controlType: 0
+ slowMultiplier: 0.5
diff --git a/Assets/Abnormalities/Abnormality_Test_Buff.asset.meta b/Assets/Abnormalities/Abnormality_Test_Buff.asset.meta
new file mode 100644
index 00000000..8aee3144
--- /dev/null
+++ b/Assets/Abnormalities/Abnormality_Test_Buff.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: da5a38e4e2c383940a34d9d8080fbbe0
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Abnormalities/Abnormality_Test_Debuff.asset b/Assets/Abnormalities/Abnormality_Test_Debuff.asset
new file mode 100644
index 00000000..b055031d
--- /dev/null
+++ b/Assets/Abnormalities/Abnormality_Test_Debuff.asset
@@ -0,0 +1,24 @@
+%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: b08cc671f858a3b409170a5356e960a0, type: 3}
+ m_Name: Abnormality_Test_Debuff
+ m_EditorClassIdentifier: Colosseum.Game::Colosseum.Abnormalities.AbnormalityData
+ abnormalityName: Abnormality
+ icon: {fileID: 21300000, guid: 173f7bf0258285c4f8bf01825ac02a11, type: 3}
+ duration: 99
+ level: 1
+ isDebuff: 1
+ statModifiers: []
+ periodicInterval: 0
+ periodicValue: 0
+ controlType: 0
+ slowMultiplier: 0.5
diff --git a/Assets/Abnormalities/Abnormality_Test_Debuff.asset.meta b/Assets/Abnormalities/Abnormality_Test_Debuff.asset.meta
new file mode 100644
index 00000000..54c22c3b
--- /dev/null
+++ b/Assets/Abnormalities/Abnormality_Test_Debuff.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c4abb0f89779f294ab99562e085e8f3b
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/External_Used/Animations/Melee_Slash.fbx.meta b/Assets/External_Used/Animations/Melee_Slash.fbx.meta
index 0452702c..faf74fc2 100644
--- a/Assets/External_Used/Animations/Melee_Slash.fbx.meta
+++ b/Assets/External_Used/Animations/Melee_Slash.fbx.meta
@@ -55,6 +55,20 @@ ModelImporter:
bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
curves: []
events:
+ - time: 0.4590326
+ functionName: OnEffect
+ data:
+ objectReferenceParameter: {instanceID: 0}
+ floatParameter: 0
+ intParameter: 1
+ messageOptions: 0
+ - time: 0.46052074
+ functionName: OnEffect
+ data:
+ objectReferenceParameter: {instanceID: 0}
+ floatParameter: 0
+ intParameter: 2
+ messageOptions: 0
- time: 0.4627699
functionName: OnEffect
data:
diff --git a/Assets/External_Used/UI/SPR_FantasyWarrior_Frame_Box_16.png b/Assets/External_Used/UI/SPR_FantasyWarrior_Frame_Box_16.png
new file mode 100644
index 00000000..c207d8f1
Binary files /dev/null and b/Assets/External_Used/UI/SPR_FantasyWarrior_Frame_Box_16.png differ
diff --git a/Assets/External_Used/UI/SPR_FantasyWarrior_Frame_Box_16.png.meta b/Assets/External_Used/UI/SPR_FantasyWarrior_Frame_Box_16.png.meta
new file mode 100644
index 00000000..04425dc9
--- /dev/null
+++ b/Assets/External_Used/UI/SPR_FantasyWarrior_Frame_Box_16.png.meta
@@ -0,0 +1,108 @@
+fileFormatVersion: 2
+guid: 976db4f04c3bd4e469e9b8eb2c20e1ca
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: -1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 0
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 80, y: 80, z: 80, w: 80}
+ spriteGenerateFallbackPhysicsShape: 0
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 3
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID: 5e97eb03825dee720800000000000000
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/External_Used/UI/UI_AbnormalitySlot.prefab b/Assets/External_Used/UI/UI_AbnormalitySlot.prefab
new file mode 100644
index 00000000..0661d592
--- /dev/null
+++ b/Assets/External_Used/UI/UI_AbnormalitySlot.prefab
@@ -0,0 +1,696 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &3383354828365798028
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 8742265258977334277}
+ - component: {fileID: 3698892055439276710}
+ - component: {fileID: 9068576939756357679}
+ - component: {fileID: 8350059981962847808}
+ - component: {fileID: 800351318774919540}
+ - component: {fileID: 5402880947663824673}
+ m_Layer: 5
+ m_Name: UI_AbnormalitySlot
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &8742265258977334277
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 3383354828365798028}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 2211778034640404479}
+ - {fileID: 2830353451877067372}
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 0, y: 0}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 50, y: 50}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &3698892055439276710
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 3383354828365798028}
+ m_CullTransparentMesh: 1
+--- !u!114 &9068576939756357679
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 3383354828365798028}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 0, g: 1, b: 0.14357352, a: 0}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 0
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_Sprite: {fileID: 0}
+ m_Type: 0
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+ m_PixelsPerUnitMultiplier: 1
+--- !u!114 &8350059981962847808
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 3383354828365798028}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Navigation:
+ m_Mode: 3
+ m_WrapAround: 0
+ m_SelectOnUp: {fileID: 0}
+ m_SelectOnDown: {fileID: 0}
+ m_SelectOnLeft: {fileID: 0}
+ m_SelectOnRight: {fileID: 0}
+ m_Transition: 3
+ m_Colors:
+ m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+ m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+ m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+ m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+ m_ColorMultiplier: 1
+ m_FadeDuration: 0.1
+ m_SpriteState:
+ m_HighlightedSprite: {fileID: 0}
+ m_PressedSprite: {fileID: 0}
+ m_SelectedSprite: {fileID: 0}
+ m_DisabledSprite: {fileID: 0}
+ m_AnimationTriggers:
+ m_NormalTrigger: Normal
+ m_HighlightedTrigger: Highlighted
+ m_PressedTrigger: Pressed
+ m_SelectedTrigger: Selected
+ m_DisabledTrigger: Disabled
+ m_Interactable: 1
+ m_TargetGraphic: {fileID: 9068576939756357679}
+ m_OnClick:
+ m_PersistentCalls:
+ m_Calls: []
+--- !u!95 &800351318774919540
+Animator:
+ serializedVersion: 7
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 3383354828365798028}
+ m_Enabled: 1
+ m_Avatar: {fileID: 0}
+ m_Controller: {fileID: 9100000, guid: f6c1759d41da8c942acb67824989a5b8, type: 2}
+ m_CullingMode: 0
+ m_UpdateMode: 0
+ m_ApplyRootMotion: 0
+ m_LinearVelocityBlending: 0
+ m_StabilizeFeet: 0
+ m_AnimatePhysics: 0
+ m_WarningMessage:
+ m_HasTransformHierarchy: 1
+ m_AllowConstantClipSamplingOptimization: 1
+ m_KeepAnimatorStateOnDisable: 0
+ m_WriteDefaultValuesOnDisable: 0
+--- !u!114 &5402880947663824673
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 3383354828365798028}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 287a45a81e69cbf48845f88759cf7eb4, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ iconImage: {fileID: 8225599256848301212}
+ durationFill: {fileID: 3807928883176071825}
+ durationText: {fileID: 2584127467159023136}
+ effectNameText: {fileID: 0}
+ backgroundImage: {fileID: 6218527427496975808}
+ buffColor: {r: 0.2, g: 0.6, b: 0.2, a: 0.8}
+ debuffColor: {r: 0.6, g: 0.2, b: 0.2, a: 0.8}
+--- !u!1 &3546204093425322779
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 2830353451877067372}
+ - component: {fileID: 8318959168881738735}
+ - component: {fileID: 5659953853696642109}
+ - component: {fileID: 3039300877730597146}
+ m_Layer: 5
+ m_Name: SPR_Frame
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &2830353451877067372
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 3546204093425322779}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 8742265258977334277}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 1, y: 1}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &8318959168881738735
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 3546204093425322779}
+ m_CullTransparentMesh: 1
+--- !u!114 &5659953853696642109
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 3546204093425322779}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 0, g: 1, b: 0, a: 1}
+ m_RaycastTarget: 0
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 0
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_Sprite: {fileID: 21300000, guid: 976db4f04c3bd4e469e9b8eb2c20e1ca, type: 3}
+ m_Type: 0
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+ m_PixelsPerUnitMultiplier: 4
+--- !u!225 &3039300877730597146
+CanvasGroup:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 3546204093425322779}
+ m_Enabled: 1
+ m_Alpha: 1
+ m_Interactable: 0
+ m_BlocksRaycasts: 0
+ m_IgnoreParentGroups: 0
+--- !u!1 &4902539774281912895
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 2062133184972599418}
+ - component: {fileID: 5719122352651651396}
+ m_Layer: 5
+ m_Name: Item
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &2062133184972599418
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 4902539774281912895}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 1336485923641369346}
+ m_Father: {fileID: 2211778034640404479}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 1, y: 1}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!225 &5719122352651651396
+CanvasGroup:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 4902539774281912895}
+ m_Enabled: 1
+ m_Alpha: 1
+ m_Interactable: 0
+ m_BlocksRaycasts: 0
+ m_IgnoreParentGroups: 0
+--- !u!1 &5010645131502399754
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 441187093428371753}
+ - component: {fileID: 7014205823490043849}
+ m_Layer: 5
+ m_Name: Normal
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &441187093428371753
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 5010645131502399754}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 1901598294175631088}
+ m_Father: {fileID: 2211778034640404479}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 1, y: 1}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &7014205823490043849
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 5010645131502399754}
+ m_CullTransparentMesh: 1
+--- !u!1 &7471771060503184807
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1901598294175631088}
+ - component: {fileID: 2489496512246523176}
+ - component: {fileID: 6218527427496975808}
+ m_Layer: 5
+ m_Name: SPR_Background
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1901598294175631088
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 7471771060503184807}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 441187093428371753}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 1, y: 1}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &2489496512246523176
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 7471771060503184807}
+ m_CullTransparentMesh: 1
+--- !u!114 &6218527427496975808
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 7471771060503184807}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 0, g: 0.12990497, b: 0.23584908, a: 0.9019608}
+ m_RaycastTarget: 0
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_Sprite: {fileID: 21300000, guid: 626f1122650d7b344a394cf52ebb14ec, type: 3}
+ m_Type: 0
+ m_PreserveAspect: 0
+ m_FillCenter: 1
+ m_FillMethod: 4
+ m_FillAmount: 1
+ m_FillClockwise: 1
+ m_FillOrigin: 0
+ m_UseSpriteMesh: 0
+ m_PixelsPerUnitMultiplier: 2.6
+--- !u!1 &8154639474077861285
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 2211778034640404479}
+ m_Layer: 5
+ m_Name: MASK
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &2211778034640404479
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 8154639474077861285}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 441187093428371753}
+ - {fileID: 2062133184972599418}
+ m_Father: {fileID: 8742265258977334277}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 1, y: 1}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!1001 &3573928083118294605
+PrefabInstance:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_Modification:
+ serializedVersion: 3
+ m_TransformParent: {fileID: 2062133184972599418}
+ m_Modifications:
+ - target: {fileID: 378688860670387420, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_Type
+ value: 3
+ objectReference: {fileID: 0}
+ - target: {fileID: 378688860670387420, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_Color.a
+ value: 0.39215687
+ objectReference: {fileID: 0}
+ - target: {fileID: 378688860670387420, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_Color.b
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 378688860670387420, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_Color.g
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 378688860670387420, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_Color.r
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 378688860670387420, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_FillAmount
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 378688860670387420, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_FillMethod
+ value: 4
+ objectReference: {fileID: 0}
+ - target: {fileID: 378688860670387420, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_FillOrigin
+ value: 2
+ objectReference: {fileID: 0}
+ - target: {fileID: 378688860670387420, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_FillClockwise
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 1316615260321933421, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_text
+ value: 99
+ objectReference: {fileID: 0}
+ - target: {fileID: 1316615260321933421, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_fontSize
+ value: 16
+ objectReference: {fileID: 0}
+ - target: {fileID: 1316615260321933421, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_margin.x
+ value: -4.874298
+ objectReference: {fileID: 0}
+ - target: {fileID: 1316615260321933421, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_margin.z
+ value: -4.115387
+ objectReference: {fileID: 0}
+ - target: {fileID: 1316615260321933421, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_fontSizeBase
+ value: 16
+ objectReference: {fileID: 0}
+ - target: {fileID: 1316615260321933421, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_VerticalAlignment
+ value: 256
+ objectReference: {fileID: 0}
+ - target: {fileID: 1316615260321933421, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_HorizontalAlignment
+ value: 2
+ objectReference: {fileID: 0}
+ - target: {fileID: 1316615260321933421, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: 'm_ActiveFontFeatures.Array.data[0]'
+ value: 1801810542
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_Pivot.x
+ value: 0.5
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_Pivot.y
+ value: 0.5
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_RootOrder
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_AnchorMax.x
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_AnchorMin.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_SizeDelta.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_SizeDelta.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_LocalPosition.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_LocalPosition.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_LocalPosition.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_LocalRotation.w
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_LocalRotation.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_LocalRotation.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_LocalRotation.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 2889380205718597033, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_IsActive
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 3471770531181138231, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_SizeDelta.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 3471770531181138231, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_SizeDelta.y
+ value: 30
+ objectReference: {fileID: 0}
+ - target: {fileID: 3471770531181138231, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 3471770531181138231, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: 15
+ objectReference: {fileID: 0}
+ - target: {fileID: 4290268768443257266, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_CullTransparentMesh
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 6658490951639871620, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_Name
+ value: CooldownItem
+ objectReference: {fileID: 0}
+ - target: {fileID: 8431704748052656868, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ propertyPath: m_IsActive
+ value: 1
+ objectReference: {fileID: 0}
+ m_RemovedComponents: []
+ m_RemovedGameObjects: []
+ m_AddedGameObjects: []
+ m_AddedComponents: []
+ m_SourcePrefab: {fileID: 100100000, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+--- !u!224 &1336485923641369346 stripped
+RectTransform:
+ m_CorrespondingSourceObject: {fileID: 2527929489434551631, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ m_PrefabInstance: {fileID: 3573928083118294605}
+ m_PrefabAsset: {fileID: 0}
+--- !u!114 &2584127467159023136 stripped
+MonoBehaviour:
+ m_CorrespondingSourceObject: {fileID: 1316615260321933421, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ m_PrefabInstance: {fileID: 3573928083118294605}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+--- !u!114 &3807928883176071825 stripped
+MonoBehaviour:
+ m_CorrespondingSourceObject: {fileID: 378688860670387420, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ m_PrefabInstance: {fileID: 3573928083118294605}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+--- !u!114 &8225599256848301212 stripped
+MonoBehaviour:
+ m_CorrespondingSourceObject: {fileID: 4881363607392615121, guid: 76cc919941c27814fa50c37e4df08f89, type: 3}
+ m_PrefabInstance: {fileID: 3573928083118294605}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
diff --git a/Assets/External_Used/UI/UI_AbnormalitySlot.prefab.meta b/Assets/External_Used/UI/UI_AbnormalitySlot.prefab.meta
new file mode 100644
index 00000000..53e7502d
--- /dev/null
+++ b/Assets/External_Used/UI/UI_AbnormalitySlot.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 60d898ecea82b6c429850e04d2e95b7c
+PrefabImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Prefabs/Player/Player.prefab b/Assets/Prefabs/Player/Player.prefab
index 06d18887..98d30cc3 100644
--- a/Assets/Prefabs/Player/Player.prefab
+++ b/Assets/Prefabs/Player/Player.prefab
@@ -20,6 +20,7 @@ GameObject:
- component: {fileID: 6048740021537676210}
- component: {fileID: 6912018896034183004}
- component: {fileID: 6585367215453362640}
+ - component: {fileID: 7524694206394173403}
m_Layer: 0
m_Name: Player
m_TagString: Untagged
@@ -134,6 +135,7 @@ MonoBehaviour:
gravity: -9.81
jumpForce: 5
skillController: {fileID: 0}
+ animator: {fileID: 0}
--- !u!114 &194806265065691022
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -193,8 +195,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier: Colosseum.Game::Colosseum.Player.PlayerNetworkController
ShowTopMostFoldoutHeaderGroup: 1
- maxHealth: 100
- maxMana: 50
+ characterStats: {fileID: 0}
--- !u!114 &8606252901290138286
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -248,7 +249,10 @@ Animator:
m_LinearVelocityBlending: 0
m_StabilizeFeet: 0
m_AnimatePhysics: 0
- m_WarningMessage:
+ m_WarningMessage: "\nBinding warning: Some generic clip(s) animate transforms that
+ are already bound by a Humanoid avatar. These transforms can only be changed
+ by Humanoid clips.\n\tTransform 'Toes_R'\n\tTransform 'Toes_R'\n\tFrom animation
+ clip 'A_Idle_Base_Sword'\n\tFrom animation clip 'A_Attack_LightCombo01A_Sword'"
m_HasTransformHierarchy: 1
m_AllowConstantClipSamplingOptimization: 1
m_KeepAnimatorStateOnDisable: 0
@@ -287,6 +291,8 @@ MonoBehaviour:
baseController: {fileID: 9100000, guid: db718381bb2992e469c76c64015e065b, type: 2}
baseSkillClip: {fileID: -7717634560727564301, guid: 079bd00af1b92964d8973dcbf2dcd21f, type: 3}
debugMode: 1
+ showAreaDebug: 1
+ debugDrawDuration: 1
--- !u!114 &6585367215453362640
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -308,6 +314,22 @@ MonoBehaviour:
- {fileID: 0}
- {fileID: 0}
skillController: {fileID: 6912018896034183004}
+ networkController: {fileID: 0}
+--- !u!114 &7524694206394173403
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 6473031571298860035}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 1301e893694bcc741a7c4c9be05334ad, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: Colosseum.Game::Colosseum.StatusEffects.StatusEffectManager
+ ShowTopMostFoldoutHeaderGroup: 1
+ characterStats: {fileID: 0}
+ networkController: {fileID: 0}
--- !u!1001 &7705728874586931617
PrefabInstance:
m_ObjectHideFlags: 0
diff --git a/Assets/Scenes/Test.unity b/Assets/Scenes/Test.unity
index a038e085..6abc5bb5 100644
--- a/Assets/Scenes/Test.unity
+++ b/Assets/Scenes/Test.unity
@@ -250,6 +250,7 @@ RectTransform:
m_Children:
- {fileID: 1162990049}
- {fileID: 7078605117837265129}
+ - {fileID: 1269404371}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
@@ -1121,6 +1122,68 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI
+--- !u!1 &972424299
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 972424300}
+ - component: {fileID: 972424301}
+ m_Layer: 5
+ m_Name: Bad Abnormalities
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &972424300
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 972424299}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 1269404371}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 0, y: 0}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 400, y: 100}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &972424301
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 972424299}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.HorizontalLayoutGroup
+ m_Padding:
+ m_Left: 0
+ m_Right: 0
+ m_Top: 0
+ m_Bottom: 0
+ m_ChildAlignment: 0
+ m_Spacing: 0
+ m_ChildForceExpandWidth: 1
+ m_ChildForceExpandHeight: 1
+ m_ChildControlWidth: 0
+ m_ChildControlHeight: 0
+ m_ChildScaleWidth: 0
+ m_ChildScaleHeight: 0
+ m_ReverseArrangement: 0
--- !u!1 &998115954
GameObject:
m_ObjectHideFlags: 0
@@ -1328,6 +1391,88 @@ MonoBehaviour:
useColorTransition: 0
smoothTransition: 1
lerpSpeed: 15
+--- !u!1 &1269404370
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1269404371}
+ - component: {fileID: 1269404372}
+ - component: {fileID: 1269404373}
+ m_Layer: 5
+ m_Name: Abnormalities
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1269404371
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1269404370}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 1873670928}
+ - {fileID: 972424300}
+ m_Father: {fileID: 260528176}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0.5, y: 0}
+ m_AnchorMax: {x: 0.5, y: 0}
+ m_AnchoredPosition: {x: -520, y: 120}
+ m_SizeDelta: {x: 400, y: 200}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &1269404372
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1269404370}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.VerticalLayoutGroup
+ m_Padding:
+ m_Left: 0
+ m_Right: 0
+ m_Top: 0
+ m_Bottom: 0
+ m_ChildAlignment: 0
+ m_Spacing: 0
+ m_ChildForceExpandWidth: 1
+ m_ChildForceExpandHeight: 1
+ m_ChildControlWidth: 0
+ m_ChildControlHeight: 0
+ m_ChildScaleWidth: 0
+ m_ChildScaleHeight: 0
+ m_ReverseArrangement: 0
+--- !u!114 &1269404373
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1269404370}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 15447f4a4d271354fb52bbdf1a526c6e, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ buffContainer: {fileID: 1873670928}
+ debuffContainer: {fileID: 972424300}
+ slotPrefab: {fileID: 5402880947663824673, guid: 287a45a81e69cbf48845f88759cf7eb4, type: 3}
+ maxSlots: 10
+ autoFindPlayer: 1
--- !u!1 &1432187382
GameObject:
m_ObjectHideFlags: 0
@@ -1576,6 +1721,68 @@ Transform:
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &1873670927
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1873670928}
+ - component: {fileID: 1873670929}
+ m_Layer: 5
+ m_Name: Good Abnormalities
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1873670928
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1873670927}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 1269404371}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 0, y: 0}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 400, y: 100}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &1873670929
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1873670927}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.HorizontalLayoutGroup
+ m_Padding:
+ m_Left: 0
+ m_Right: 0
+ m_Top: 0
+ m_Bottom: 0
+ m_ChildAlignment: 0
+ m_Spacing: 0
+ m_ChildForceExpandWidth: 1
+ m_ChildForceExpandHeight: 1
+ m_ChildControlWidth: 0
+ m_ChildControlHeight: 0
+ m_ChildScaleWidth: 0
+ m_ChildScaleHeight: 0
+ m_ReverseArrangement: 0
--- !u!1 &2122318093
GameObject:
m_ObjectHideFlags: 0
diff --git a/Assets/Scripts/Abnormalities.meta b/Assets/Scripts/Abnormalities.meta
new file mode 100644
index 00000000..b055a845
--- /dev/null
+++ b/Assets/Scripts/Abnormalities.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: bc6434195fb88a443939a5a0b2747f0a
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/Abnormalities/AbnormalityData.cs b/Assets/Scripts/Abnormalities/AbnormalityData.cs
new file mode 100644
index 00000000..54504f42
--- /dev/null
+++ b/Assets/Scripts/Abnormalities/AbnormalityData.cs
@@ -0,0 +1,101 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+using Colosseum.Stats;
+
+namespace Colosseum.Abnormalities
+{
+ ///
+ /// 제어 효과 타입
+ ///
+ public enum ControlType
+ {
+ None, // 제어 효과 없음
+ Stun, // 기절 (이동, 스킬 사용 불가)
+ Silence, // 침묵 (스킬 사용 불가)
+ Slow // 둔화 (이동 속도 감소)
+ }
+
+ ///
+ /// 스탯 수정자 엔트리
+ ///
+ [Serializable]
+ public class AbnormalityStatModifier
+ {
+ [Tooltip("수정할 스탯 타입")]
+ public StatType statType;
+
+ [Tooltip("수정값")]
+ public float value;
+
+ [Tooltip("수정 타입 (Flat: 고정값, PercentAdd: 퍼센트 합산, PercentMult: 퍼센트 곱셈)")]
+ public StatModType modType;
+
+ public AbnormalityStatModifier() { }
+
+ public AbnormalityStatModifier(StatType statType, float value, StatModType modType)
+ {
+ this.statType = statType;
+ this.value = value;
+ this.modType = modType;
+ }
+ }
+
+ ///
+ /// 이상 상태 정의 ScriptableObject
+ /// 버프/디버프의 데이터를 정의합니다.
+ ///
+ [CreateAssetMenu(fileName = "AbnormalityData", menuName = "Colosseum/Abnormalities/Abnormality")]
+ public class AbnormalityData : ScriptableObject
+ {
+ [Header("기본 정보")]
+ [Tooltip("이상 상태 이름")]
+ public string abnormalityName = "Abnormality";
+
+ [Tooltip("아이콘")]
+ public Sprite icon;
+
+ [Tooltip("지속 시간 (초, 0 이하면 영구)")]
+ public float duration = 5f;
+
+ [Tooltip("효과 레벨 (중복 처리용, 높으면 우선)")]
+ public int level = 1;
+
+ [Tooltip("디버프 여부")]
+ public bool isDebuff = false;
+
+ [Header("스탯 수정자")]
+ [Tooltip("스탯에 적용할 수정자 목록")]
+ public List statModifiers = new List();
+
+ [Header("주기적 효과 (DoT/HoT)")]
+ [Tooltip("주기적 효과 간격 (초, 0이면 비활성)")]
+ public float periodicInterval = 0f;
+
+ [Tooltip("주기적 효과값 (양수=힐, 음수=데미지)")]
+ public float periodicValue = 0f;
+
+ [Header("제어 효과 (CC)")]
+ [Tooltip("제어 효과 타입")]
+ public ControlType controlType = ControlType.None;
+
+ [Tooltip("둔화 배율 (Slow일 때, 0.5 = 50% 감소)")]
+ [Range(0f, 1f)]
+ public float slowMultiplier = 0.5f;
+
+ ///
+ /// 영구 효과인지 확인
+ ///
+ public bool IsPermanent => duration <= 0f;
+
+ ///
+ /// 주기적 효과가 있는지 확인
+ ///
+ public bool HasPeriodicEffect => periodicInterval > 0f && periodicValue != 0f;
+
+ ///
+ /// 제어 효과가 있는지 확인
+ ///
+ public bool HasControlEffect => controlType != ControlType.None;
+ }
+}
diff --git a/Assets/Scripts/Abnormalities/AbnormalityData.cs.meta b/Assets/Scripts/Abnormalities/AbnormalityData.cs.meta
new file mode 100644
index 00000000..14de43d7
--- /dev/null
+++ b/Assets/Scripts/Abnormalities/AbnormalityData.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: b08cc671f858a3b409170a5356e960a0
\ No newline at end of file
diff --git a/Assets/Scripts/Abnormalities/AbnormalityManager.cs b/Assets/Scripts/Abnormalities/AbnormalityManager.cs
new file mode 100644
index 00000000..0a9503de
--- /dev/null
+++ b/Assets/Scripts/Abnormalities/AbnormalityManager.cs
@@ -0,0 +1,494 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+using Unity.Netcode;
+using Colosseum.Stats;
+using Colosseum.Player;
+
+namespace Colosseum.Abnormalities
+{
+ ///
+ /// 캐릭터에 부착되어 이상 상태를 관리하는 컴포넌트
+ /// 버프/디버프의 적용, 제거, 주기적 효과를 처리합니다.
+ ///
+ public class AbnormalityManager : NetworkBehaviour
+ {
+ [Header("References")]
+ [Tooltip("CharacterStats 컴포넌트 (없으면 자동 검색)")]
+ [SerializeField] private CharacterStats characterStats;
+
+ [Tooltip("PlayerNetworkController 컴포넌트 (HP/MP 관리용)")]
+ [SerializeField] private PlayerNetworkController networkController;
+
+ // 활성화된 이상 상태 목록
+ private readonly List activeAbnormalities = new List();
+
+ // 제어 효과 상태
+ private int stunCount;
+ private int silenceCount;
+ private float slowMultiplier = 1f;
+
+ // 네트워크 동기화용 데이터
+ private NetworkList syncedAbnormalities;
+
+ ///
+ /// 기절 상태 여부
+ ///
+ public bool IsStunned => stunCount > 0;
+
+ ///
+ /// 침묵 상태 여부
+ ///
+ public bool IsSilenced => silenceCount > 0;
+
+ ///
+ /// 이동 속도 배율 (1.0 = 기본, 0.5 = 50% 감소)
+ ///
+ public float MoveSpeedMultiplier => slowMultiplier;
+
+ ///
+ /// 행동 가능 여부 (기절이 아닐 때)
+ ///
+ public bool CanAct => !IsStunned;
+
+ ///
+ /// 스킬 사용 가능 여부
+ ///
+ public bool CanUseSkills => !IsStunned && !IsSilenced;
+
+ ///
+ /// 활성화된 이상 상태 목록 (읽기 전용)
+ ///
+ public IReadOnlyList ActiveAbnormalities => activeAbnormalities;
+
+ // 이벤트
+ public event Action OnAbnormalityAdded;
+ public event Action OnAbnormalityRemoved;
+ public event Action OnAbnormalitiesChanged;
+
+ ///
+ /// 네트워크 동기화용 이상 상태 데이터 구조체
+ ///
+ private struct AbnormalitySyncData : INetworkSerializable, IEquatable
+ {
+ public int AbnormalityId;
+ public float RemainingDuration;
+ public ulong SourceClientId;
+
+ public void NetworkSerialize(BufferSerializer serializer) where T : IReaderWriter
+ {
+ serializer.SerializeValue(ref AbnormalityId);
+ serializer.SerializeValue(ref RemainingDuration);
+ serializer.SerializeValue(ref SourceClientId);
+ }
+
+ public bool Equals(AbnormalitySyncData other)
+ {
+ return AbnormalityId == other.AbnormalityId;
+ }
+ }
+
+ private void Awake()
+ {
+ if (characterStats == null)
+ characterStats = GetComponent();
+
+ if (networkController == null)
+ networkController = GetComponent();
+
+ syncedAbnormalities = new NetworkList();
+ }
+
+ public override void OnNetworkSpawn()
+ {
+ syncedAbnormalities.OnListChanged += OnSyncedAbnormalitiesChanged;
+ }
+
+ public override void OnNetworkDespawn()
+ {
+ syncedAbnormalities.OnListChanged -= OnSyncedAbnormalitiesChanged;
+ }
+
+ private void Update()
+ {
+ if (!IsServer) return;
+
+ UpdateAbnormalities(Time.deltaTime);
+ }
+
+ ///
+ /// 이상 상태 적용
+ ///
+ /// 적용할 이상 상태 데이터
+ /// 효과 시전자
+ public void ApplyAbnormality(AbnormalityData data, GameObject source)
+ {
+ if (data == null)
+ {
+ Debug.LogWarning("[Abnormality] ApplyAbnormality called with null data");
+ return;
+ }
+
+ if (IsServer)
+ {
+ ApplyAbnormalityInternal(data, source);
+ }
+ else
+ {
+ var sourceNetId = source != null && source.TryGetComponent(out var netObj) ? netObj.NetworkObjectId : 0UL;
+ ApplyAbnormalityServerRpc(data.GetInstanceID(), sourceNetId);
+ }
+ }
+
+ [Rpc(SendTo.Server)]
+ private void ApplyAbnormalityServerRpc(int dataId, ulong sourceNetworkId)
+ {
+ var data = FindAbnormalityDataById(dataId);
+ if (data == null)
+ {
+ Debug.LogWarning($"[Abnormality] Could not find data with ID: {dataId}");
+ return;
+ }
+
+ GameObject source = null;
+ if (sourceNetworkId != 0UL && NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(sourceNetworkId, out var netObj))
+ {
+ source = netObj.gameObject;
+ }
+
+ ApplyAbnormalityInternal(data, source);
+ }
+
+ private void ApplyAbnormalityInternal(AbnormalityData data, GameObject source)
+ {
+ var existing = FindExistingAbnormality(data);
+
+ if (existing != null)
+ {
+ if (existing.Data == data)
+ {
+ existing.RefreshDuration();
+ UpdateSyncedAbnormalityDuration(existing);
+ Debug.Log($"[Abnormality] Refreshed {data.abnormalityName} on {gameObject.name}");
+ return;
+ }
+
+ if (data.level > existing.Data.level)
+ {
+ RemoveAbnormalityInternal(existing);
+ }
+ else
+ {
+ Debug.Log($"[Abnormality] Ignored {data.abnormalityName} (level {data.level}) - existing level {existing.Data.level} is higher or equal");
+ return;
+ }
+ }
+
+ var newAbnormality = new ActiveAbnormality(data, source);
+ activeAbnormalities.Add(newAbnormality);
+
+ ApplyStatModifiers(newAbnormality);
+ ApplyControlEffect(data);
+ SyncAbnormalityAdd(newAbnormality, source);
+
+ OnAbnormalityAdded?.Invoke(newAbnormality);
+ OnAbnormalitiesChanged?.Invoke();
+
+ Debug.Log($"[Abnormality] Applied {data.abnormalityName} (level {data.level}) to {gameObject.name} for {data.duration}s");
+ }
+
+ ///
+ /// 이상 상태 제거
+ ///
+ /// 제거할 이상 상태 데이터
+ public void RemoveAbnormality(AbnormalityData data)
+ {
+ if (data == null) return;
+
+ if (IsServer)
+ {
+ var abnormality = FindExistingAbnormality(data);
+ if (abnormality != null)
+ {
+ RemoveAbnormalityInternal(abnormality);
+ }
+ }
+ else
+ {
+ RemoveAbnormalityServerRpc(data.GetInstanceID());
+ }
+ }
+
+ [Rpc(SendTo.Server)]
+ private void RemoveAbnormalityServerRpc(int dataId)
+ {
+ var abnormality = activeAbnormalities.Find(a => a.Data.GetInstanceID() == dataId);
+ if (abnormality != null)
+ {
+ RemoveAbnormalityInternal(abnormality);
+ }
+ }
+
+ private void RemoveAbnormalityInternal(ActiveAbnormality abnormality)
+ {
+ RemoveStatModifiers(abnormality);
+ RemoveControlEffect(abnormality.Data);
+ SyncAbnormalityRemove(abnormality);
+ activeAbnormalities.Remove(abnormality);
+
+ OnAbnormalityRemoved?.Invoke(abnormality);
+ OnAbnormalitiesChanged?.Invoke();
+
+ Debug.Log($"[Abnormality] Removed {abnormality.Data.abnormalityName} from {gameObject.name}");
+ }
+
+ ///
+ /// 모든 이상 상태 제거
+ ///
+ public void RemoveAllAbnormalities()
+ {
+ if (!IsServer)
+ {
+ RemoveAllAbnormalitiesServerRpc();
+ return;
+ }
+
+ while (activeAbnormalities.Count > 0)
+ {
+ RemoveAbnormalityInternal(activeAbnormalities[0]);
+ }
+ }
+
+ [Rpc(SendTo.Server)]
+ private void RemoveAllAbnormalitiesServerRpc()
+ {
+ RemoveAllAbnormalities();
+ }
+
+ ///
+ /// 특정 출처의 모든 이상 상태 제거
+ ///
+ public void RemoveAbnormalitiesFromSource(GameObject source)
+ {
+ if (!IsServer)
+ {
+ var sourceNetId = source != null && source.TryGetComponent(out var netObj) ? netObj.NetworkObjectId : 0UL;
+ RemoveAbnormalitiesFromSourceServerRpc(sourceNetId);
+ return;
+ }
+
+ for (int i = activeAbnormalities.Count - 1; i >= 0; i--)
+ {
+ if (activeAbnormalities[i].Source == source)
+ {
+ RemoveAbnormalityInternal(activeAbnormalities[i]);
+ }
+ }
+ }
+
+ [Rpc(SendTo.Server)]
+ private void RemoveAbnormalitiesFromSourceServerRpc(ulong sourceNetworkId)
+ {
+ for (int i = activeAbnormalities.Count - 1; i >= 0; i--)
+ {
+ var abnormality = activeAbnormalities[i];
+ var sourceNetId = abnormality.Source != null && abnormality.Source.TryGetComponent(out var netObj) ? netObj.NetworkObjectId : 0UL;
+ if (sourceNetId == sourceNetworkId)
+ {
+ RemoveAbnormalityInternal(abnormality);
+ }
+ }
+ }
+
+ private void UpdateAbnormalities(float deltaTime)
+ {
+ for (int i = activeAbnormalities.Count - 1; i >= 0; i--)
+ {
+ var abnormality = activeAbnormalities[i];
+
+ if (abnormality.CanTriggerPeriodic())
+ {
+ TriggerPeriodicEffect(abnormality);
+ }
+
+ if (abnormality.Tick(deltaTime))
+ {
+ RemoveAbnormalityInternal(abnormality);
+ }
+ }
+ }
+
+ private void TriggerPeriodicEffect(ActiveAbnormality abnormality)
+ {
+ if (networkController == null) return;
+
+ float value = abnormality.Data.periodicValue;
+
+ if (value > 0)
+ {
+ networkController.RestoreHealthRpc(value);
+ Debug.Log($"[Abnormality] Periodic heal: +{value} HP from {abnormality.Data.abnormalityName}");
+ }
+ else if (value < 0)
+ {
+ networkController.TakeDamageRpc(-value);
+ Debug.Log($"[Abnormality] Periodic damage: {-value} HP from {abnormality.Data.abnormalityName}");
+ }
+ }
+
+ private ActiveAbnormality FindExistingAbnormality(AbnormalityData data)
+ {
+ return activeAbnormalities.Find(a => a.Data.abnormalityName == data.abnormalityName);
+ }
+
+ private void ApplyStatModifiers(ActiveAbnormality abnormality)
+ {
+ if (characterStats == null) return;
+
+ foreach (var entry in abnormality.Data.statModifiers)
+ {
+ var stat = characterStats.GetStat(entry.statType);
+ if (stat != null)
+ {
+ var modifier = new StatModifier(entry.value, entry.modType, abnormality);
+ abnormality.AppliedModifiers.Add(modifier);
+ stat.AddModifier(modifier);
+ }
+ }
+ }
+
+ private void RemoveStatModifiers(ActiveAbnormality abnormality)
+ {
+ if (characterStats == null) return;
+
+ foreach (StatType statType in Enum.GetValues(typeof(StatType)))
+ {
+ var stat = characterStats.GetStat(statType);
+ stat?.RemoveAllModifiersFromSource(abnormality);
+ }
+
+ abnormality.AppliedModifiers.Clear();
+ }
+
+ private void ApplyControlEffect(AbnormalityData data)
+ {
+ switch (data.controlType)
+ {
+ case ControlType.Stun:
+ stunCount++;
+ break;
+
+ case ControlType.Silence:
+ silenceCount++;
+ break;
+
+ case ControlType.Slow:
+ slowMultiplier = Mathf.Min(slowMultiplier, data.slowMultiplier);
+ break;
+ }
+ }
+
+ private void RemoveControlEffect(AbnormalityData data)
+ {
+ switch (data.controlType)
+ {
+ case ControlType.Stun:
+ stunCount = Mathf.Max(0, stunCount - 1);
+ break;
+
+ case ControlType.Silence:
+ silenceCount = Mathf.Max(0, silenceCount - 1);
+ break;
+
+ case ControlType.Slow:
+ RecalculateSlowMultiplier();
+ break;
+ }
+ }
+
+ private void RecalculateSlowMultiplier()
+ {
+ slowMultiplier = 1f;
+
+ foreach (var abnormality in activeAbnormalities)
+ {
+ if (abnormality.Data.controlType == ControlType.Slow)
+ {
+ slowMultiplier = Mathf.Min(slowMultiplier, abnormality.Data.slowMultiplier);
+ }
+ }
+ }
+
+ private void SyncAbnormalityAdd(ActiveAbnormality abnormality, GameObject source)
+ {
+ var sourceClientId = source != null && source.TryGetComponent(out var netObj) ? netObj.OwnerClientId : 0UL;
+
+ var syncData = new AbnormalitySyncData
+ {
+ AbnormalityId = abnormality.Data.GetInstanceID(),
+ RemainingDuration = abnormality.RemainingDuration,
+ SourceClientId = sourceClientId
+ };
+
+ syncedAbnormalities.Add(syncData);
+ }
+
+ private void UpdateSyncedAbnormalityDuration(ActiveAbnormality abnormality)
+ {
+ for (int i = 0; i < syncedAbnormalities.Count; i++)
+ {
+ if (syncedAbnormalities[i].AbnormalityId == abnormality.Data.GetInstanceID())
+ {
+ var syncData = syncedAbnormalities[i];
+ syncData.RemainingDuration = abnormality.RemainingDuration;
+ syncedAbnormalities[i] = syncData;
+ break;
+ }
+ }
+ }
+
+ private void SyncAbnormalityRemove(ActiveAbnormality abnormality)
+ {
+ for (int i = 0; i < syncedAbnormalities.Count; i++)
+ {
+ if (syncedAbnormalities[i].AbnormalityId == abnormality.Data.GetInstanceID())
+ {
+ syncedAbnormalities.RemoveAt(i);
+ break;
+ }
+ }
+ }
+
+ private void OnSyncedAbnormalitiesChanged(NetworkListEvent changeEvent)
+ {
+ OnAbnormalitiesChanged?.Invoke();
+ }
+
+ private AbnormalityData FindAbnormalityDataById(int instanceId)
+ {
+ var allData = Resources.FindObjectsOfTypeAll();
+ foreach (var data in allData)
+ {
+ if (data.GetInstanceID() == instanceId)
+ return data;
+ }
+ return null;
+ }
+
+ ///
+ /// 특정 이름의 이상 상태가 활성화되어 있는지 확인
+ ///
+ public bool HasAbnormality(string name)
+ {
+ return activeAbnormalities.Exists(a => a.Data.abnormalityName == name);
+ }
+
+ ///
+ /// 특정 데이터의 이상 상태가 활성화되어 있는지 확인
+ ///
+ public bool HasAbnormality(AbnormalityData data)
+ {
+ return activeAbnormalities.Exists(a => a.Data.abnormalityName == data.abnormalityName);
+ }
+ }
+}
diff --git a/Assets/Scripts/Abnormalities/AbnormalityManager.cs.meta b/Assets/Scripts/Abnormalities/AbnormalityManager.cs.meta
new file mode 100644
index 00000000..d66c5774
--- /dev/null
+++ b/Assets/Scripts/Abnormalities/AbnormalityManager.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 7a766b6ab825c1445a3385079bb32cc5
\ No newline at end of file
diff --git a/Assets/Scripts/Abnormalities/ActiveAbnormality.cs b/Assets/Scripts/Abnormalities/ActiveAbnormality.cs
new file mode 100644
index 00000000..744b2594
--- /dev/null
+++ b/Assets/Scripts/Abnormalities/ActiveAbnormality.cs
@@ -0,0 +1,134 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+using Colosseum.Stats;
+
+namespace Colosseum.Abnormalities
+{
+ ///
+ /// 런타임 활성 이상 상태 인스턴스
+ /// AbnormalityData의 인스턴스로, 실제 적용 중인 이상 상태를 관리합니다.
+ ///
+ public class ActiveAbnormality
+ {
+ ///
+ /// 이상 상태 데이터
+ ///
+ public AbnormalityData Data { get; }
+
+ ///
+ /// 효과를 건 대상 (버프/디버프 시전자)
+ ///
+ public GameObject Source { get; }
+
+ ///
+ /// 남은 지속 시간
+ ///
+ public float RemainingDuration { get; set; }
+
+ ///
+ /// 적용된 스탯 수정자 목록
+ ///
+ public List AppliedModifiers { get; }
+
+ ///
+ /// 주기적 효과 타이머
+ ///
+ public float PeriodicTimer { get; set; }
+
+ ///
+ /// 고유 식별자 (네트워크 동기화용)
+ ///
+ public Guid Id { get; }
+
+ ///
+ /// 활성 이상 상태 생성
+ ///
+ /// 이상 상태 데이터
+ /// 효과 시전자
+ public ActiveAbnormality(AbnormalityData data, GameObject source)
+ {
+ Data = data;
+ Source = source;
+ RemainingDuration = data.duration;
+ PeriodicTimer = 0f;
+ Id = Guid.NewGuid();
+ AppliedModifiers = new List();
+ }
+
+ ///
+ /// 지속 시간 갱신
+ ///
+ public void RefreshDuration()
+ {
+ RemainingDuration = Data.duration;
+ PeriodicTimer = 0f;
+ }
+
+ ///
+ /// 시간 경과 처리
+ ///
+ /// 경과 시간
+ /// 효과가 만료되었으면 true
+ public bool Tick(float deltaTime)
+ {
+ // 영구 효과는 시간 감소 없음
+ if (Data.IsPermanent)
+ return false;
+
+ RemainingDuration -= deltaTime;
+
+ // 주기적 효과 타이머 업데이트
+ if (Data.HasPeriodicEffect)
+ {
+ PeriodicTimer += deltaTime;
+ }
+
+ return RemainingDuration <= 0f;
+ }
+
+ ///
+ /// 주기적 효과 발동 가능 여부 확인
+ ///
+ /// 발동 가능하면 true
+ public bool CanTriggerPeriodic()
+ {
+ if (!Data.HasPeriodicEffect)
+ return false;
+
+ if (PeriodicTimer >= Data.periodicInterval)
+ {
+ PeriodicTimer -= Data.periodicInterval;
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// 진행률 (0~1)
+ ///
+ public float Progress
+ {
+ get
+ {
+ if (Data.IsPermanent)
+ return 1f;
+ return Mathf.Clamp01(1f - (RemainingDuration / Data.duration));
+ }
+ }
+
+ ///
+ /// 남은 시간 비율 (1~0, UI 표시용)
+ ///
+ public float RemainingRatio
+ {
+ get
+ {
+ if (Data.IsPermanent)
+ return 1f;
+ return Mathf.Clamp01(RemainingDuration / Data.duration);
+ }
+ }
+ }
+}
diff --git a/Assets/Scripts/Abnormalities/ActiveAbnormality.cs.meta b/Assets/Scripts/Abnormalities/ActiveAbnormality.cs.meta
new file mode 100644
index 00000000..bdc8a0fc
--- /dev/null
+++ b/Assets/Scripts/Abnormalities/ActiveAbnormality.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: b90fb3ef8cb13be4383eb397857cfa2b
\ No newline at end of file
diff --git a/Assets/Scripts/Skills/Effects/AbnormalityEffect.cs b/Assets/Scripts/Skills/Effects/AbnormalityEffect.cs
new file mode 100644
index 00000000..ad0082c1
--- /dev/null
+++ b/Assets/Scripts/Skills/Effects/AbnormalityEffect.cs
@@ -0,0 +1,46 @@
+using UnityEngine;
+using Colosseum.Abnormalities;
+
+namespace Colosseum.Skills.Effects
+{
+ ///
+ /// 이상 상태 효과
+ /// AbnormalityManager를 통해 대상에게 이상 상태를 적용합니다.
+ ///
+ [CreateAssetMenu(fileName = "AbnormalityEffect", menuName = "Colosseum/Skills/Effects/Abnormality")]
+ public class AbnormalityEffect : SkillEffect
+ {
+ [Header("Abnormality")]
+ [Tooltip("적용할 이상 상태 데이터")]
+ [SerializeField] private AbnormalityData abnormalityData;
+
+ protected override void ApplyEffect(GameObject caster, GameObject target)
+ {
+ if (target == null) return;
+
+ if (abnormalityData == null)
+ {
+ Debug.LogWarning($"[AbnormalityEffect] AbnormalityData is not assigned");
+ return;
+ }
+
+ var abnormalityManager = target.GetComponent();
+ if (abnormalityManager == null)
+ {
+ Debug.LogWarning($"[AbnormalityEffect] Target {target.name} has no AbnormalityManager");
+ return;
+ }
+
+ abnormalityManager.ApplyAbnormality(abnormalityData, caster);
+ Debug.Log($"[AbnormalityEffect] Applied {abnormalityData.abnormalityName} to {target.name} from {caster?.name ?? "unknown"}");
+ }
+
+ ///
+ /// 이상 상태 데이터 설정 (런타임용)
+ ///
+ public void SetAbnormalityData(AbnormalityData data)
+ {
+ abnormalityData = data;
+ }
+ }
+}
diff --git a/Assets/Scripts/Skills/Effects/AbnormalityEffect.cs.meta b/Assets/Scripts/Skills/Effects/AbnormalityEffect.cs.meta
new file mode 100644
index 00000000..ad528061
--- /dev/null
+++ b/Assets/Scripts/Skills/Effects/AbnormalityEffect.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: bf750718c64c4bd48af905d2927351de
\ No newline at end of file
diff --git a/Assets/Scripts/Skills/Effects/BuffEffect.cs b/Assets/Scripts/Skills/Effects/BuffEffect.cs
deleted file mode 100644
index 4e3c265b..00000000
--- a/Assets/Scripts/Skills/Effects/BuffEffect.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using UnityEngine;
-
-namespace Colosseum.Skills.Effects
-{
- ///
- /// 버프/디버프 효과
- ///
- [CreateAssetMenu(fileName = "BuffEffect", menuName = "Colosseum/Skills/Effects/Buff")]
- public class BuffEffect : SkillEffect
- {
- [Header("Buff Settings")]
- [SerializeField] private string buffName = "Buff";
- [Min(0f)] [SerializeField] private float duration = 5f;
-
- [Header("Stat Modifiers")]
- [Range(0f, 10f)] [SerializeField] private float moveSpeedMultiplier = 1f;
- [Range(0f, 10f)] [SerializeField] private float attackPowerMultiplier = 1f;
- [Range(0f, 10f)] [SerializeField] private float defenseMultiplier = 1f;
-
- protected override void ApplyEffect(GameObject caster, GameObject target)
- {
- if (target == null) return;
-
- // TODO: 실제 버프 시스템 연동
- // var buffSystem = target.GetComponent();
- // buffSystem?.ApplyBuff(new BuffData(buffName, duration, moveSpeedMultiplier, attackPowerMultiplier, defenseMultiplier));
-
- Debug.Log($"[Buff] {buffName} on {target.name} for {duration}s " +
- $"(Speed: {moveSpeedMultiplier}x, ATK: {attackPowerMultiplier}x, DEF: {defenseMultiplier}x)");
- }
- }
-}
diff --git a/Assets/Scripts/Skills/Effects/BuffEffect.cs.meta b/Assets/Scripts/Skills/Effects/BuffEffect.cs.meta
deleted file mode 100644
index 49a2451d..00000000
--- a/Assets/Scripts/Skills/Effects/BuffEffect.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: 32bab3b586da0d7469f63e03f18ee29f
\ No newline at end of file
diff --git a/Assets/Scripts/StatusEffects.meta b/Assets/Scripts/StatusEffects.meta
new file mode 100644
index 00000000..75200698
--- /dev/null
+++ b/Assets/Scripts/StatusEffects.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 148d81d9974baed45b212857d96aed37
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/UI/AbnormalityListUI.cs b/Assets/Scripts/UI/AbnormalityListUI.cs
new file mode 100644
index 00000000..ca3a3a12
--- /dev/null
+++ b/Assets/Scripts/UI/AbnormalityListUI.cs
@@ -0,0 +1,279 @@
+using System.Collections.Generic;
+using UnityEngine;
+using Colosseum.Abnormalities;
+
+namespace Colosseum.UI
+{
+ ///
+ /// 이상 상태 목록 UI 관리자
+ /// 버프/디버프 목록을 표시하고 관리합니다.
+ ///
+ public class AbnormalityListUI : MonoBehaviour
+ {
+ [Header("Containers")]
+ [Tooltip("버프 컨테이너")]
+ [SerializeField] private Transform buffContainer;
+
+ [Tooltip("디버프 컨테이너")]
+ [SerializeField] private Transform debuffContainer;
+
+ [Header("Prefab")]
+ [Tooltip("이상 상태 슬롯 프리팹")]
+ [SerializeField] private AbnormalitySlotUI slotPrefab;
+
+ [Header("Settings")]
+ [Tooltip("최대 표시 개수")]
+ [SerializeField] private int maxSlots = 10;
+
+ [Tooltip("자동으로 플레이어 추적")]
+ [SerializeField] private bool autoFindPlayer = true;
+
+ // 추적 중인 AbnormalityManager
+ private AbnormalityManager targetManager;
+
+ // 생성된 슬롯 풀
+ private readonly List slotPool = new List();
+
+ // 현재 활성화된 슬롯 목록
+ private readonly List activeSlots = new List();
+
+ // 이전 프레임의 효과 수 (변경 감지용)
+ private int lastAbnormalityCount = -1;
+
+ private void Start()
+ {
+ if (autoFindPlayer)
+ {
+ // 로컬 플레이어 찾기
+ FindLocalPlayer();
+ }
+
+ // 슬롯 풀 초기화
+ InitializeSlotPool();
+ }
+
+ private void OnDestroy()
+ {
+ // 이벤트 구독 해제
+ if (targetManager != null)
+ {
+ targetManager.OnAbnormalityAdded -= OnAbnormalityAdded;
+ targetManager.OnAbnormalityRemoved -= OnAbnormalityRemoved;
+ targetManager.OnAbnormalitiesChanged -= OnAbnormalitiesChanged;
+ }
+ }
+
+ private void Update()
+ {
+ // 주기적으로 UI 갱신 (성능 최적화를 위해 매 프레임이 아닌 일정 간격으로)
+ if (Time.frameCount % 10 == 0) // 10프레임마다 한 번
+ {
+ RefreshUI();
+ }
+ }
+
+ ///
+ /// 로컬 플레이어 찾기
+ ///
+ private void FindLocalPlayer()
+ {
+ var playerObjects = FindObjectsByType(FindObjectsSortMode.None);
+
+ foreach (var manager in playerObjects)
+ {
+ // 네트워크 오브젝트인 경우 로컬 플레이어 확인
+ if (manager.TryGetComponent(out var netObj) && netObj.IsOwner)
+ {
+ SetTarget(manager);
+ return;
+ }
+ }
+
+ // 네트워크 오브젝트가 없거나 로컬 플레이어를 찾지 못한 경우
+ // 첫 번째 플레이어 사용 (싱글플레이어용)
+ if (playerObjects.Length > 0)
+ {
+ SetTarget(playerObjects[0]);
+ }
+ }
+
+ ///
+ /// 추적 대상 설정
+ ///
+ /// 추적할 AbnormalityManager
+ public void SetTarget(AbnormalityManager manager)
+ {
+ // 기존 구독 해제
+ if (targetManager != null)
+ {
+ targetManager.OnAbnormalityAdded -= OnAbnormalityAdded;
+ targetManager.OnAbnormalityRemoved -= OnAbnormalityRemoved;
+ targetManager.OnAbnormalitiesChanged -= OnAbnormalitiesChanged;
+ }
+
+ targetManager = manager;
+
+ // 새로운 대상 구독
+ if (targetManager != null)
+ {
+ targetManager.OnAbnormalityAdded += OnAbnormalityAdded;
+ targetManager.OnAbnormalityRemoved += OnAbnormalityRemoved;
+ targetManager.OnAbnormalitiesChanged += OnAbnormalitiesChanged;
+ }
+
+ // 즉시 UI 갱신
+ ForceRefreshUI();
+ }
+
+ ///
+ /// 슬롯 풀 초기화
+ ///
+ private void InitializeSlotPool()
+ {
+ if (slotPrefab == null)
+ {
+ Debug.LogWarning("[AbnormalityListUI] Slot prefab is not assigned");
+ return;
+ }
+
+ // 필요한 만큼 슬롯 미리 생성
+ for (int i = 0; i < maxSlots; i++)
+ {
+ var slot = CreateSlot();
+ slot.gameObject.SetActive(false);
+ slotPool.Add(slot);
+ }
+ }
+
+ ///
+ /// 새 슬롯 생성
+ ///
+ private AbnormalitySlotUI CreateSlot()
+ {
+ var go = Instantiate(slotPrefab.gameObject, transform);
+ return go.GetComponent();
+ }
+
+ ///
+ /// 슬롯 가져오기 (풀에서 또는 새로 생성)
+ ///
+ private AbnormalitySlotUI GetSlot()
+ {
+ // 풀에서 비활성화된 슬롯 찾기
+ foreach (var slot in slotPool)
+ {
+ if (!slot.gameObject.activeSelf)
+ {
+ return slot;
+ }
+ }
+
+ // 풀에 없으면 새로 생성
+ if (slotPool.Count < maxSlots)
+ {
+ var newSlot = CreateSlot();
+ slotPool.Add(newSlot);
+ return newSlot;
+ }
+
+ return null;
+ }
+
+ ///
+ /// 슬롯 반환 (비활성화)
+ ///
+ private void ReturnSlot(AbnormalitySlotUI slot)
+ {
+ slot.gameObject.SetActive(false);
+ activeSlots.Remove(slot);
+ }
+
+ ///
+ /// 이상 상태 추가 시 호출
+ ///
+ private void OnAbnormalityAdded(ActiveAbnormality abnormality)
+ {
+ ForceRefreshUI();
+ }
+
+ ///
+ /// 이상 상태 제거 시 호출
+ ///
+ private void OnAbnormalityRemoved(ActiveAbnormality abnormality)
+ {
+ ForceRefreshUI();
+ }
+
+ ///
+ /// 이상 상태 변경 시 호출
+ ///
+ private void OnAbnormalitiesChanged()
+ {
+ ForceRefreshUI();
+ }
+
+ ///
+ /// UI 강제 갱신
+ ///
+ public void ForceRefreshUI()
+ {
+ if (targetManager == null) return;
+
+ // 모든 슬롯 반환
+ foreach (var slot in activeSlots.ToArray())
+ {
+ ReturnSlot(slot);
+ }
+
+ activeSlots.Clear();
+
+ // 활성화된 이상 상태 표시
+ var abnormalities = targetManager.ActiveAbnormalities;
+ foreach (var abnormality in abnormalities)
+ {
+ var slot = GetSlot();
+ if (slot == null) continue;
+
+ // 버프/디버프에 따라 적절한 컨테이너에 배치
+ Transform container = abnormality.Data.isDebuff ? debuffContainer : buffContainer;
+ if (container == null) container = transform;
+
+ slot.transform.SetParent(container, false);
+ slot.Initialize(abnormality);
+ slot.gameObject.SetActive(true);
+ activeSlots.Add(slot);
+ }
+
+ lastAbnormalityCount = abnormalities.Count;
+ }
+
+ ///
+ /// UI 주기적 갱신 (변경 감지 시에만)
+ ///
+ private void RefreshUI()
+ {
+ if (targetManager == null) return;
+
+ int currentCount = targetManager.ActiveAbnormalities.Count;
+
+ // 이상 상태 수가 변경되었으면 갱신
+ if (currentCount != lastAbnormalityCount)
+ {
+ ForceRefreshUI();
+ }
+ }
+
+ ///
+ /// 모든 슬롯 숨기기
+ ///
+ public void HideAll()
+ {
+ foreach (var slot in activeSlots.ToArray())
+ {
+ ReturnSlot(slot);
+ }
+
+ activeSlots.Clear();
+ }
+ }
+}
diff --git a/Assets/Scripts/UI/AbnormalityListUI.cs.meta b/Assets/Scripts/UI/AbnormalityListUI.cs.meta
new file mode 100644
index 00000000..5b6f2b2d
--- /dev/null
+++ b/Assets/Scripts/UI/AbnormalityListUI.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 15447f4a4d271354fb52bbdf1a526c6e
\ No newline at end of file
diff --git a/Assets/Scripts/UI/AbnormalitySlotUI.cs b/Assets/Scripts/UI/AbnormalitySlotUI.cs
new file mode 100644
index 00000000..34225359
--- /dev/null
+++ b/Assets/Scripts/UI/AbnormalitySlotUI.cs
@@ -0,0 +1,182 @@
+using UnityEngine;
+using UnityEngine.UI;
+using TMPro;
+using Colosseum.Abnormalities;
+
+namespace Colosseum.UI
+{
+ ///
+ /// 개별 이상 상태 UI 슬롯
+ /// 버프/디버프 아이콘, 지속 시간 등을 표시합니다.
+ ///
+ public class AbnormalitySlotUI : MonoBehaviour
+ {
+ [Header("UI References")]
+ [Tooltip("이상 상태 아이콘")]
+ [SerializeField] private Image iconImage;
+
+ [Tooltip("지속 시간 채우기 이미지 (시계 방향)")]
+ [SerializeField] private Image durationFill;
+
+ [Tooltip("남은 시간 텍스트")]
+ [SerializeField] private TMP_Text durationText;
+
+ [Tooltip("효과 이름 텍스트")]
+ [SerializeField] private TMP_Text effectNameText;
+
+ [Tooltip("배경 이미지 (버프/디버프 구분용)")]
+ [SerializeField] private Image backgroundImage;
+
+ [Header("Colors")]
+ [Tooltip("버프 배경 색상")]
+ [SerializeField] private Color buffColor = new Color(0.2f, 0.6f, 0.2f, 0.8f);
+
+ [Tooltip("디버프 배경 색상")]
+ [SerializeField] private Color debuffColor = new Color(0.6f, 0.2f, 0.2f, 0.8f);
+
+ private ActiveAbnormality trackedAbnormality;
+
+ ///
+ /// 추적 중인 활성 이상 상태
+ ///
+ public ActiveAbnormality TrackedAbnormality => trackedAbnormality;
+
+ ///
+ /// UI 초기화
+ ///
+ /// 표시할 활성 이상 상태
+ public void Initialize(ActiveAbnormality abnormality)
+ {
+ trackedAbnormality = abnormality;
+
+ if (abnormality?.Data == null)
+ {
+ Debug.LogWarning("[AbnormalitySlotUI] Initialize called with null abnormality or data");
+ return;
+ }
+
+ // 아이콘 설정
+ if (iconImage != null)
+ {
+ iconImage.sprite = abnormality.Data.icon;
+ iconImage.enabled = abnormality.Data.icon != null;
+ }
+
+ // 이름 설정
+ if (effectNameText != null)
+ {
+ effectNameText.text = abnormality.Data.abnormalityName;
+ }
+
+ // 배경 색상 설정 (버프/디버프 구분)
+ if (backgroundImage != null)
+ {
+ backgroundImage.color = abnormality.Data.isDebuff ? debuffColor : buffColor;
+ }
+
+ // 초기 상태 업데이트
+ UpdateDisplay(abnormality.RemainingDuration, abnormality.Data.duration);
+ }
+
+ ///
+ /// 화면 표시 업데이트
+ ///
+ /// 남은 시간
+ /// 전체 시간
+ public void UpdateDisplay(float remainingDuration, float totalDuration)
+ {
+ // 지속 시간 채우기 업데이트
+ if (durationFill != null)
+ {
+ if (totalDuration > 0f)
+ {
+ float fillAmount = Mathf.Clamp01(remainingDuration / totalDuration);
+ durationFill.fillAmount = fillAmount;
+ durationFill.enabled = true;
+ }
+ else
+ {
+ // 영구 효과
+ durationFill.fillAmount = 1f;
+ }
+ }
+
+ // 남은 시간 텍스트 업데이트
+ if (durationText != null)
+ {
+ if (totalDuration > 0f)
+ {
+ if (remainingDuration >= 60f)
+ {
+ durationText.text = $"{remainingDuration / 60f:F0}m";
+ }
+ else if (remainingDuration >= 1f)
+ {
+ durationText.text = $"{remainingDuration:F0}s";
+ }
+ else
+ {
+ durationText.text = $"{remainingDuration:F1}s";
+ }
+ }
+ else
+ {
+ // 영구 효과
+ durationText.text = "∞";
+ }
+ }
+ }
+
+ ///
+ /// 프레임마다 호출하여 추적 중인 효과 업데이트
+ ///
+ private void Update()
+ {
+ if (trackedAbnormality == null)
+ {
+ gameObject.SetActive(false);
+ return;
+ }
+
+ UpdateDisplay(trackedAbnormality.RemainingDuration, trackedAbnormality.Data.duration);
+ }
+
+ ///
+ /// 툴팁 표시용 정보 반환
+ ///
+ public string GetTooltipText()
+ {
+ if (trackedAbnormality?.Data == null) return string.Empty;
+
+ var data = trackedAbnormality.Data;
+ string tooltip = $"{data.abnormalityName}\n";
+
+ if (!data.IsPermanent)
+ {
+ tooltip += $"지속 시간: {trackedAbnormality.RemainingDuration:F1}초\n";
+ }
+ else
+ {
+ tooltip += "영구 효과\n";
+ }
+
+ if (data.HasPeriodicEffect)
+ {
+ tooltip += $"주기적 효과: {data.periodicValue:+0}/ {data.periodicInterval}초\n";
+ }
+
+ if (data.HasControlEffect)
+ {
+ tooltip += $"제어 효과: {data.controlType}\n";
+ }
+
+ foreach (var mod in data.statModifiers)
+ {
+ string sign = mod.value >= 0 ? "+" : "";
+ tooltip += $"{mod.statType}: {sign}{mod.value}\n";
+ }
+
+ return tooltip;
+ }
+ }
+}
diff --git a/Assets/Scripts/UI/AbnormalitySlotUI.cs.meta b/Assets/Scripts/UI/AbnormalitySlotUI.cs.meta
new file mode 100644
index 00000000..b9910edd
--- /dev/null
+++ b/Assets/Scripts/UI/AbnormalitySlotUI.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 287a45a81e69cbf48845f88759cf7eb4
\ No newline at end of file
diff --git a/Assets/Scripts/UI/AbnormalitySystemTest.cs b/Assets/Scripts/UI/AbnormalitySystemTest.cs
new file mode 100644
index 00000000..3c0a4655
--- /dev/null
+++ b/Assets/Scripts/UI/AbnormalitySystemTest.cs
@@ -0,0 +1,116 @@
+using UnityEngine;
+using Colosseum.Abnormalities;
+
+namespace Colosseum.UI
+{
+ ///
+ /// 이상 상태 시스템 테스트 스크립트
+ /// Q 키: 버프 적용, E 키: 디버프 적용
+ /// 로그를 통해 OnEffect 이벤트 호출 및 이상 상태 적용 과정을 추적합니다.
+ ///
+ public class AbnormalitySystemTest : MonoBehaviour
+ {
+ private AbnormalityManager abnormalityManager;
+ private AbnormalityData testBuff;
+ private AbnormalityData testDebuff;
+
+ private float testTimer;
+
+ void Start()
+ {
+ // 플레이어에서 AbnormalityManager 찾기
+ abnormalityManager = GetComponent();
+ if (abnormalityManager == null)
+ {
+ Debug.LogError("[AbnormalitySystemTest] AbnormalityManager not found on player!");
+ return;
+ }
+
+ // 테스트용 이상 상태 데이터 생성 (에셋 생성)
+ testBuff = ScriptableObject.CreateInstance();
+ testBuff.abnormalityName = "Test Buff";
+ testBuff.duration = 5f;
+ testBuff.isDebuff = false;
+
+ testDebuff = ScriptableObject.CreateInstance();
+ testDebuff.abnormalityName = "Test Debuff";
+ testDebuff.duration = 5f;
+ testDebuff.isDebuff = true;
+
+ // 이벤트 구독
+ abnormalityManager.OnAbnormalityAdded += OnAbnormalityAdded;
+ abnormalityManager.OnAbnormalityRemoved += OnAbnormalityRemoved;
+
+ Debug.Log("=== Abnormality System Test Started ===");
+ Debug.Log("Press Q to apply buff, Press E to apply debuff");
+ Debug.Log($"Initial Active Abnormalities Count: {abnormalityManager.ActiveAbnormalities.Count}");
+ }
+
+ void Update()
+ {
+ testTimer += Time.deltaTime;
+
+ // Q 키로 버프 적용 (3초마다 1회만)
+ if (Input.GetKeyDown(KeyCode.Q) && testTimer >= 3f)
+ {
+ testTimer = 0f;
+ ApplyTestBuff();
+ }
+
+ // E 키로 디버프 적용 (3초마다 1회만)
+ if (Input.GetKeyDown(KeyCode.E) && testTimer >= 3f)
+ {
+ testTimer = 0f;
+ ApplyTestDebuff();
+ }
+ }
+
+ private void ApplyTestBuff()
+ {
+ if (testBuff == null || abnormalityManager == null)
+ {
+ Debug.LogWarning("[AbnormalitySystemTest] Cannot apply buff - data or manager is null");
+ return;
+ }
+
+ Debug.Log($"[AbnormalitySystemTest] >>> Applying BUFF: {testBuff.abnormalityName} to {gameObject.name}");
+ abnormalityManager.ApplyAbnormality(testBuff, gameObject);
+ }
+
+ private void ApplyTestDebuff()
+ {
+ if (testDebuff == null || abnormalityManager == null)
+ {
+ Debug.LogWarning("[AbnormalitySystemTest] Cannot apply debuff - data or manager is null");
+ return;
+ }
+
+ Debug.Log($"[AbnormalitySystemTest] >>> Applying DEBUFF: {testDebuff.abnormalityName} to {gameObject.name}");
+ abnormalityManager.ApplyAbnormality(testDebuff, gameObject);
+ }
+
+ private void OnAbnormalityAdded(ActiveAbnormality abnormality)
+ {
+ Debug.Log($"[AbnormalitySystemTest] <<< ABNORMALITY ADDED: {abnormality.Data.abnormalityName} | isDebuff: {abnormality.Data.isDebuff} | Duration: {abnormality.Data.duration}s | Remaining: {abnormality.RemainingDuration:F1}s");
+ }
+
+ private void OnAbnormalityRemoved(ActiveAbnormality abnormality)
+ {
+ Debug.Log($"[AbnormalitySystemTest] <<< ABNORMALITY REMOVED: {abnormality.Data.abnormalityName}");
+ }
+
+ void OnDestroy()
+ {
+ // 이벤트 구독 해제
+ if (abnormalityManager != null)
+ {
+ abnormalityManager.OnAbnormalityAdded -= OnAbnormalityAdded;
+ abnormalityManager.OnAbnormalityRemoved -= OnAbnormalityRemoved;
+ }
+
+ // 정리
+ if (testBuff != null) Destroy(testBuff);
+ if (testDebuff != null) Destroy(testDebuff);
+ }
+ }
+}
diff --git a/Assets/Scripts/UI/AbnormalitySystemTest.cs.meta b/Assets/Scripts/UI/AbnormalitySystemTest.cs.meta
new file mode 100644
index 00000000..d99bf342
--- /dev/null
+++ b/Assets/Scripts/UI/AbnormalitySystemTest.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: a1b2c3d4e5f6a7b8c9a0d1e5e3
diff --git a/Assets/Skills/Effects/Melee_Slash_1.asset b/Assets/Skills/Effects/Melee_Slash_1.asset
new file mode 100644
index 00000000..d1844233
--- /dev/null
+++ b/Assets/Skills/Effects/Melee_Slash_1.asset
@@ -0,0 +1,26 @@
+%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: bf750718c64c4bd48af905d2927351de, type: 3}
+ m_Name: Melee_Slash_1
+ m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.Effects.AbnormalityEffect
+ targetType: 0
+ targetTeam: 0
+ areaCenter: 0
+ areaShape: 0
+ targetLayers:
+ serializedVersion: 2
+ m_Bits: 0
+ areaRadius: 3
+ fanOriginDistance: 0
+ fanRadius: 3
+ fanHalfAngle: 45
+ abnormalityData: {fileID: 11400000, guid: da5a38e4e2c383940a34d9d8080fbbe0, type: 2}
diff --git a/Assets/Skills/Effects/Melee_Slash_1.asset.meta b/Assets/Skills/Effects/Melee_Slash_1.asset.meta
new file mode 100644
index 00000000..596f0947
--- /dev/null
+++ b/Assets/Skills/Effects/Melee_Slash_1.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 75bac55a016a0da46899806f58b76ce3
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Skills/Effects/Melee_Slash_2.asset b/Assets/Skills/Effects/Melee_Slash_2.asset
new file mode 100644
index 00000000..a3cc7c03
--- /dev/null
+++ b/Assets/Skills/Effects/Melee_Slash_2.asset
@@ -0,0 +1,26 @@
+%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: bf750718c64c4bd48af905d2927351de, type: 3}
+ m_Name: Melee_Slash_2
+ m_EditorClassIdentifier: Colosseum.Game::Colosseum.Skills.Effects.AbnormalityEffect
+ targetType: 0
+ targetTeam: 0
+ areaCenter: 0
+ areaShape: 0
+ targetLayers:
+ serializedVersion: 2
+ m_Bits: 0
+ areaRadius: 3
+ fanOriginDistance: 0
+ fanRadius: 3
+ fanHalfAngle: 45
+ abnormalityData: {fileID: 11400000, guid: c4abb0f89779f294ab99562e085e8f3b, type: 2}
diff --git a/Assets/Skills/Effects/Melee_Slash_2.asset.meta b/Assets/Skills/Effects/Melee_Slash_2.asset.meta
new file mode 100644
index 00000000..69e616ee
--- /dev/null
+++ b/Assets/Skills/Effects/Melee_Slash_2.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 0e496b26a1dbf40488ce54cb4fe9c27b
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant: