diff --git a/Assets/Fantasy Skybox FREE/Panoramics/FS002/FS002_Night.mat b/Assets/Fantasy Skybox FREE/Panoramics/FS002/FS002_Night.mat
index 1753aa7d..3dde5691 100644
--- a/Assets/Fantasy Skybox FREE/Panoramics/FS002/FS002_Night.mat
+++ b/Assets/Fantasy Skybox FREE/Panoramics/FS002/FS002_Night.mat
@@ -78,7 +78,7 @@ Material:
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- - _Rotation: 6.6876717
+ - _Rotation: 7.162766
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/AbilityMigrationHelper.cs b/Assets/Scripts/AbilitySystem/AbilityInstance/AbilityMigrationHelper.cs
new file mode 100644
index 00000000..20fae4f1
--- /dev/null
+++ b/Assets/Scripts/AbilitySystem/AbilityInstance/AbilityMigrationHelper.cs
@@ -0,0 +1,52 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+// ============================================================================
+// 5. EASY MIGRATION HELPER - Update Your Existing Components
+// ============================================================================
+
+///
+/// Helper to easily convert your existing ability references
+/// Just change "BaseAbility" to "RuntimeAbilityInstance" in your existing scripts
+///
+public static class AbilityMigrationHelper
+{
+ ///
+ /// Convert a BaseAbility to RuntimeAbilityInstance
+ ///
+ public static RuntimeAbilityInstance ToRuntime(this BaseAbility ability)
+ {
+ return new RuntimeAbilityInstance(ability);
+ }
+
+ ///
+ /// Create a modified version of an ability
+ ///
+ public static RuntimeAbilityInstance CreateModifiedVersion(BaseAbility baseAbility, params AbilityModifier[] modifiers)
+ {
+ var runtime = new RuntimeAbilityInstance(baseAbility);
+
+ foreach (var modifier in modifiers)
+ {
+ runtime.AddModifier(modifier);
+ }
+
+ return runtime;
+ }
+
+ ///
+ /// Create legendary version with special behaviors
+ ///
+ public static RuntimeAbilityInstance CreateLegendaryVersion(BaseAbility baseAbility, params RuntimeBehavior[] behaviors)
+ {
+ var runtime = new RuntimeAbilityInstance(baseAbility);
+
+ foreach (var behavior in behaviors)
+ {
+ runtime.AddBehavior(behavior);
+ }
+
+ return runtime;
+ }
+}
\ No newline at end of file
diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/AbilityMigrationHelper.cs.meta b/Assets/Scripts/AbilitySystem/AbilityInstance/AbilityMigrationHelper.cs.meta
new file mode 100644
index 00000000..9fd2322a
--- /dev/null
+++ b/Assets/Scripts/AbilitySystem/AbilityInstance/AbilityMigrationHelper.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: fddd81fa3189fcf43a2207ea59bdae95
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/AbilityModifier.cs b/Assets/Scripts/AbilitySystem/AbilityInstance/AbilityModifier.cs
new file mode 100644
index 00000000..9e87ae2f
--- /dev/null
+++ b/Assets/Scripts/AbilitySystem/AbilityInstance/AbilityModifier.cs
@@ -0,0 +1,60 @@
+// ============================================================================
+// 2. ABILITY MODIFIER SYSTEM
+// ============================================================================
+
+using UnityEngine;
+
+[System.Serializable]
+public class AbilityModifier
+{
+ [Header("Resource Cost Modifiers")]
+ public float manaCostMultiplier = 1f;
+ public float manaCostFlat = 0f;
+ public float healthCostMultiplier = 1f;
+ public float healthCostFlat = 0f;
+ public float classResourceCostMultiplier = 1f;
+ public float classResourceCostFlat = 0f;
+
+ [Header("Timing Modifiers")]
+ public float castTimeMultiplier = 1f;
+ public float cooldownMultiplier = 1f;
+
+ [Header("Effect Modifiers")]
+ public float damageMultiplier = 1f;
+ public float healingMultiplier = 1f;
+ public float durationMultiplier = 1f;
+ public float rangeMultiplier = 1f;
+
+ [Header("Meta Info")]
+ public string modifierName = "Unnamed Modifier";
+ public string description = "";
+ public float duration = -1f; // -1 = permanent
+
+ // Factory methods for common modifiers
+ public static AbilityModifier CreateDamageBoost(float multiplier, string name = "Damage Boost")
+ {
+ return new AbilityModifier
+ {
+ damageMultiplier = multiplier,
+ modifierName = name
+ };
+ }
+
+ public static AbilityModifier CreateCooldownReduction(float reductionPercent, string name = "Cooldown Reduction")
+ {
+ return new AbilityModifier
+ {
+ cooldownMultiplier = 1f - (reductionPercent / 100f),
+ modifierName = name
+ };
+ }
+
+ public static AbilityModifier CreateManaCostReduction(float reductionPercent, string name = "Mana Cost Reduction")
+ {
+ return new AbilityModifier
+ {
+ manaCostMultiplier = 1f - (reductionPercent / 100f),
+ modifierName = name
+ };
+ }
+}
\ No newline at end of file
diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/AbilityModifier.cs.meta b/Assets/Scripts/AbilitySystem/AbilityInstance/AbilityModifier.cs.meta
new file mode 100644
index 00000000..6433510b
--- /dev/null
+++ b/Assets/Scripts/AbilitySystem/AbilityInstance/AbilityModifier.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 759877a48198a3549b2a51623fe20a7c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/AbilityUsageExamples.cs b/Assets/Scripts/AbilitySystem/AbilityInstance/AbilityUsageExamples.cs
new file mode 100644
index 00000000..e6637caf
--- /dev/null
+++ b/Assets/Scripts/AbilitySystem/AbilityInstance/AbilityUsageExamples.cs
@@ -0,0 +1,59 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+// ============================================================================
+// 6. USAGE EXAMPLES - How to Use in Your Existing Code
+// ============================================================================
+
+public class AbilityUsageExamples : MonoBehaviour
+{
+ [Header("Your Existing Abilities")]
+ public BaseAbility fireballAbility;
+ public BaseAbility healingAbility;
+
+ // These can now be RuntimeAbilityInstances!
+ private RuntimeAbilityInstance runtimeFireball;
+ private RuntimeAbilityInstance runtimeHealing;
+
+ private void Start()
+ {
+ // Convert your existing abilities
+ runtimeFireball = fireballAbility.ToRuntime();
+ runtimeHealing = healingAbility.ToRuntime();
+
+ // Example: Add legendary item effect
+ AddLegendaryFireballEffect();
+ }
+
+ private void AddLegendaryFireballEffect()
+ {
+ // This is how you'd handle your legendary item!
+ var explosionBehavior = new ExplodeOnHitBehavior
+ {
+ explosionRadius = 5f,
+ explosionDamage = 50f
+ };
+
+ runtimeFireball.AddBehavior(explosionBehavior);
+
+ // Also add a damage boost
+ var damageBoost = AbilityModifier.CreateDamageBoost(1.5f, "Legendary Damage");
+ runtimeFireball.AddModifier(damageBoost);
+ }
+
+ // Your existing ability usage code works exactly the same!
+ public void CastFireball()
+ {
+ var user = GetComponent();
+
+ // This works exactly like your old BaseAbility.Execute()
+ runtimeFireball.Execute(user);
+ }
+
+ public void CastFireballAtTarget(Transform target)
+ {
+ var user = GetComponent();
+ runtimeFireball.Execute(user, target);
+ }
+}
\ No newline at end of file
diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/AbilityUsageExamples.cs.meta b/Assets/Scripts/AbilitySystem/AbilityInstance/AbilityUsageExamples.cs.meta
new file mode 100644
index 00000000..37a37df9
--- /dev/null
+++ b/Assets/Scripts/AbilitySystem/AbilityInstance/AbilityUsageExamples.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d1d5a488d66722a468d8af337e46e1e1
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions.meta b/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions.meta
new file mode 100644
index 00000000..60f65cc0
--- /dev/null
+++ b/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 30b6d22e7928d8047a51992b3fda64b6
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions/ChainLightningBehavior.cs b/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions/ChainLightningBehavior.cs
new file mode 100644
index 00000000..06e7178a
--- /dev/null
+++ b/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions/ChainLightningBehavior.cs
@@ -0,0 +1,74 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+public class ChainLightningBehavior : RuntimeBehavior
+{
+ public int maxChains = 3;
+ public float chainRange = 8f;
+ public float damageMultiplier = 0.5f; // Each chain does 50% of original damage
+
+ public ChainLightningBehavior()
+ {
+ Trigger = BehaviorTrigger.OnHit;
+ BehaviorName = "Chain Lightning";
+ }
+
+ public override void Execute(RuntimeAbilityInstance ability, Taggable user, Transform target, Vector3 point)
+ {
+ if (target == null) return;
+
+ var currentTarget = target.GetComponent();
+ var chainedTargets = new List { currentTarget };
+
+ for (int i = 0; i < maxChains; i++)
+ {
+ var nextTarget = FindNextChainTarget(currentTarget.transform.position, chainedTargets);
+ if (nextTarget == null) break;
+
+ chainedTargets.Add(nextTarget);
+
+ // Apply reduced damage
+ var health = nextTarget.GetComponent();
+ if (health != null)
+ {
+ float chainDamage = CalculateChainDamage(ability, i + 1);
+ health.ChangeValue(-chainDamage);
+ }
+
+ currentTarget = nextTarget;
+ }
+ }
+
+ private Taggable FindNextChainTarget(Vector3 position, List excludeTargets)
+ {
+ var colliders = Physics.OverlapSphere(position, chainRange);
+
+ foreach (var collider in colliders)
+ {
+ var target = collider.GetComponent();
+ if (target != null && !excludeTargets.Contains(target))
+ {
+ return target;
+ }
+ }
+
+ return null;
+ }
+
+ private float CalculateChainDamage(RuntimeAbilityInstance ability, int chainNumber)
+ {
+ // This would need to be adapted to your damage system
+ // For now, just return a reduced amount
+ return 50f * Mathf.Pow(damageMultiplier, chainNumber);
+ }
+
+ public override RuntimeBehavior Clone()
+ {
+ return new ChainLightningBehavior
+ {
+ maxChains = this.maxChains,
+ chainRange = this.chainRange,
+ damageMultiplier = this.damageMultiplier
+ };
+ }
+}
\ No newline at end of file
diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions/ChainLightningBehavior.cs.meta b/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions/ChainLightningBehavior.cs.meta
new file mode 100644
index 00000000..8311b6c8
--- /dev/null
+++ b/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions/ChainLightningBehavior.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3d7ec80971f1d2d4b93d7395e6dcf78c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions/ExplodeOnHitBehavior.cs b/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions/ExplodeOnHitBehavior.cs
new file mode 100644
index 00000000..fa6dad15
--- /dev/null
+++ b/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions/ExplodeOnHitBehavior.cs
@@ -0,0 +1,58 @@
+// ============================================================================
+// 4. COMMON RUNTIME BEHAVIORS - Your Legendary Item Effects!
+// ============================================================================
+
+using UnityEngine;
+
+public class ExplodeOnHitBehavior : RuntimeBehavior
+{
+ public GameObject explosionPrefab;
+ public float explosionRadius = 5f;
+ public float explosionDamage = 30f;
+ public LayerMask targetLayers = -1;
+
+ public ExplodeOnHitBehavior()
+ {
+ Trigger = BehaviorTrigger.OnHit;
+ BehaviorName = "Explode on Hit";
+ }
+
+ public override void Execute(RuntimeAbilityInstance ability, Taggable user, Transform target, Vector3 point)
+ {
+ Vector3 explosionPoint = target != null ? target.position : point;
+
+ // Spawn explosion visual if prefab exists
+ if (explosionPrefab != null)
+ {
+ Object.Instantiate(explosionPrefab, explosionPoint, Quaternion.identity);
+ }
+
+ // Find targets in explosion radius
+ var colliders = Physics.OverlapSphere(explosionPoint, explosionRadius, targetLayers);
+
+ foreach (var collider in colliders)
+ {
+ var explosionTarget = collider.GetComponent();
+ if (explosionTarget != null && explosionTarget != user)
+ {
+ // Apply explosion damage
+ var health = explosionTarget.GetComponent();
+ if (health != null)
+ {
+ health.ChangeValue(-explosionDamage);
+ }
+ }
+ }
+ }
+
+ public override RuntimeBehavior Clone()
+ {
+ return new ExplodeOnHitBehavior
+ {
+ explosionPrefab = this.explosionPrefab,
+ explosionRadius = this.explosionRadius,
+ explosionDamage = this.explosionDamage,
+ targetLayers = this.targetLayers
+ };
+ }
+}
\ No newline at end of file
diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions/ExplodeOnHitBehavior.cs.meta b/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions/ExplodeOnHitBehavior.cs.meta
new file mode 100644
index 00000000..c042a187
--- /dev/null
+++ b/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions/ExplodeOnHitBehavior.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7b92d75ddf02f444fa969dcb95660e60
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions/LifeStealBehavior.cs b/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions/LifeStealBehavior.cs
new file mode 100644
index 00000000..a905bc9e
--- /dev/null
+++ b/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions/LifeStealBehavior.cs
@@ -0,0 +1,34 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+public class LifeStealBehavior : RuntimeBehavior
+{
+ public float lifeStealPercent = 0.15f; // 15% life steal
+
+ public LifeStealBehavior()
+ {
+ Trigger = BehaviorTrigger.OnHit;
+ BehaviorName = "Life Steal";
+ }
+
+ public override void Execute(RuntimeAbilityInstance ability, Taggable user, Transform target, Vector3 point)
+ {
+ // This would need to track the damage dealt to calculate life steal
+ // For now, just heal a fixed amount
+ var userHealth = user.GetComponent();
+ if (userHealth != null)
+ {
+ float healAmount = 20f * lifeStealPercent; // Placeholder calculation
+ userHealth.ChangeValue(healAmount);
+ }
+ }
+
+ public override RuntimeBehavior Clone()
+ {
+ return new LifeStealBehavior
+ {
+ lifeStealPercent = this.lifeStealPercent
+ };
+ }
+}
\ No newline at end of file
diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions/LifeStealBehavior.cs.meta b/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions/LifeStealBehavior.cs.meta
new file mode 100644
index 00000000..479d7e4c
--- /dev/null
+++ b/Assets/Scripts/AbilitySystem/AbilityInstance/Extensions/LifeStealBehavior.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 091400d6a45eaac4782ee5636a0f0d1f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/RuntimeAbilityInstance.cs b/Assets/Scripts/AbilitySystem/AbilityInstance/RuntimeAbilityInstance.cs
new file mode 100644
index 00000000..d1586ed2
--- /dev/null
+++ b/Assets/Scripts/AbilitySystem/AbilityInstance/RuntimeAbilityInstance.cs
@@ -0,0 +1,308 @@
+// ============================================================================
+// RUNTIME ABILITY WRAPPER - DROP-IN REPLACEMENT FOR BaseAbility
+// ============================================================================
+
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+// ============================================================================
+// 1. RUNTIME ABILITY INSTANCE - Wraps Your Existing BaseAbility
+// ============================================================================
+
+///
+/// Runtime wrapper for BaseAbility that adds modifiers and behaviors
+/// Can be used anywhere you currently use BaseAbility references
+///
+public class RuntimeAbilityInstance
+{
+ // ========================================================================
+ // CORE DATA - Wraps your existing ScriptableObject
+ // ========================================================================
+
+ [SerializeField] private BaseAbility sourceAbility;
+ private List activeModifiers = new List();
+ private List runtimeBehaviors = new List();
+
+ // Runtime state
+ private float lastUsedTime;
+ private int currentCharges;
+
+ // ========================================================================
+ // CONSTRUCTOR
+ // ========================================================================
+
+ public RuntimeAbilityInstance(BaseAbility source)
+ {
+ sourceAbility = source;
+ currentCharges = GetMaxCharges(); // In case you add charges later
+ RecalculateModifiedValues();
+ }
+
+ // ========================================================================
+ // PROPERTIES - Direct access to original + modified values
+ // ========================================================================
+
+ // Original values (unchanged)
+ public BaseAbility SourceAbility => sourceAbility;
+ public string displayName => sourceAbility.displayName;
+ public Sprite Icon => sourceAbility.Icon;
+ public List targettingTags => sourceAbility.targettingTags;
+ public List tags => sourceAbility.tags;
+ public List abilityEffects => sourceAbility.abilityEffects;
+ public bool castableWhileMoving => sourceAbility.castableWhileMoving;
+ public AbilityAnimationType animationType => sourceAbility.animationType;
+
+ // Modified values (affected by modifiers)
+ public float manaCost { get; private set; }
+ public float healthCost { get; private set; }
+ public float classResourceCost { get; private set; }
+ public float spiritPowerReserveCost { get; private set; }
+ public float percentMaxManaCost { get; private set; }
+ public float percentMaxHealthCost { get; private set; }
+ public float castTime { get; private set; }
+ public float cooldown { get; private set; }
+
+ // Runtime state properties
+ public float LastUsedTime => lastUsedTime;
+ public bool IsOnCooldown => Time.time < lastUsedTime + cooldown;
+ public float CooldownRemaining => Mathf.Max(0f, (lastUsedTime + cooldown) - Time.time);
+ public List ActiveModifiers => new List(activeModifiers);
+ public List RuntimeBehaviors => new List(runtimeBehaviors);
+
+ // ========================================================================
+ // EXECUTION METHODS - Same signature as your BaseAbility
+ // ========================================================================
+
+ public virtual void Execute(Taggable user)
+ {
+ if (!CanExecute(user)) return;
+
+ // Execute pre-cast behaviors
+ ExecuteBehaviors(BehaviorTrigger.PreCast, user, null, Vector3.zero);
+
+ // Execute original ability
+ sourceAbility.Execute(user);
+
+ // Execute post-cast behaviors
+ ExecuteBehaviors(BehaviorTrigger.PostCast, user, null, Vector3.zero);
+
+ // Update runtime state
+ lastUsedTime = Time.time;
+ }
+
+ public virtual void Execute(Taggable user, Vector3 point)
+ {
+ if (!CanExecute(user)) return;
+
+ ExecuteBehaviors(BehaviorTrigger.PreCast, user, null, point);
+ sourceAbility.Execute(user, point);
+ ExecuteBehaviors(BehaviorTrigger.PostCast, user, null, point);
+
+ lastUsedTime = Time.time;
+ }
+
+ public virtual void Execute(Taggable user, Transform target)
+ {
+ if (!CanExecute(user)) return;
+
+ ExecuteBehaviors(BehaviorTrigger.PreCast, user, target, target.position);
+ sourceAbility.Execute(user, target);
+ ExecuteBehaviors(BehaviorTrigger.PostCast, user, target, target.position);
+
+ lastUsedTime = Time.time;
+ }
+
+ // ========================================================================
+ // ABILITY STATE CHECKS
+ // ========================================================================
+
+ public bool CanExecute(Taggable user)
+ {
+ // Check cooldown
+ if (IsOnCooldown) return false;
+
+ // Check resources using modified costs
+ return CanAffordResources(user);
+ }
+
+ private bool CanAffordResources(Taggable user)
+ {
+ // Use the modified costs, not original
+ var userMana = user.GetComponent();
+ if (userMana != null)
+ {
+ float finalManaCost = manaCost + userMana.GetMaxValue() * percentMaxManaCost;
+ if (!userMana.EnoughMana(finalManaCost)) return false;
+ }
+
+ var userHealth = user.GetComponent();
+ if (userHealth != null)
+ {
+ float finalHealthCost = healthCost + userHealth.GetMaxValue() * percentMaxHealthCost;
+ if (userHealth.GetCurrentValue() <= finalHealthCost) return false;
+ }
+
+ var userClassResource = user.GetComponent();
+ if (userClassResource != null && classResourceCost > 0)
+ {
+ if (userClassResource.GetCurrentValue() < classResourceCost) return false;
+ }
+
+ return true;
+ }
+
+ public float GetFinalManaCost(Mana userMana)
+ {
+ return manaCost + userMana.GetMaxValue() * percentMaxManaCost;
+ }
+
+ public float GetFinalHealthCost(Health userHealth)
+ {
+ return healthCost + userHealth.GetMaxValue() * percentMaxHealthCost;
+ }
+
+ // ========================================================================
+ // MODIFIER SYSTEM
+ // ========================================================================
+
+ public void AddModifier(AbilityModifier modifier)
+ {
+ activeModifiers.Add(modifier);
+ RecalculateModifiedValues();
+ }
+
+ public void RemoveModifier(AbilityModifier modifier)
+ {
+ activeModifiers.Remove(modifier);
+ RecalculateModifiedValues();
+ }
+
+ public void RemoveAllModifiers()
+ {
+ activeModifiers.Clear();
+ RecalculateModifiedValues();
+ }
+
+ private void RecalculateModifiedValues()
+ {
+ // Start with original values
+ manaCost = sourceAbility.manaCost;
+ healthCost = sourceAbility.healthCost;
+ classResourceCost = sourceAbility.classResourceCost;
+ spiritPowerReserveCost = sourceAbility.spiritPowerReserveCost;
+ percentMaxManaCost = sourceAbility.percentMaxManaCost;
+ percentMaxHealthCost = sourceAbility.percentMaxHealthCost;
+ castTime = sourceAbility.castTime;
+ cooldown = sourceAbility.cooldown;
+
+ // Apply all modifiers
+ foreach (var modifier in activeModifiers)
+ {
+ ApplyModifier(modifier);
+ }
+ }
+
+ private void ApplyModifier(AbilityModifier modifier)
+ {
+ // Resource cost modifiers
+ manaCost = manaCost * modifier.manaCostMultiplier + modifier.manaCostFlat;
+ healthCost = healthCost * modifier.healthCostMultiplier + modifier.healthCostFlat;
+ classResourceCost = classResourceCost * modifier.classResourceCostMultiplier + modifier.classResourceCostFlat;
+
+ // Timing modifiers
+ castTime *= modifier.castTimeMultiplier;
+ cooldown *= modifier.cooldownMultiplier;
+
+ // Ensure values don't go negative
+ manaCost = Mathf.Max(0f, manaCost);
+ healthCost = Mathf.Max(0f, healthCost);
+ classResourceCost = Mathf.Max(0f, classResourceCost);
+ castTime = Mathf.Max(0f, castTime);
+ cooldown = Mathf.Max(0f, cooldown);
+ }
+
+ // ========================================================================
+ // RUNTIME BEHAVIOR SYSTEM
+ // ========================================================================
+
+ public void AddBehavior(RuntimeBehavior behavior)
+ {
+ runtimeBehaviors.Add(behavior);
+ }
+
+ public void RemoveBehavior(RuntimeBehavior behavior)
+ {
+ runtimeBehaviors.Remove(behavior);
+ }
+
+ public T GetBehavior() where T : RuntimeBehavior
+ {
+ return runtimeBehaviors.Find(b => b is T) as T;
+ }
+
+ public void RemoveBehavior() where T : RuntimeBehavior
+ {
+ for (int i = runtimeBehaviors.Count - 1; i >= 0; i--)
+ {
+ if (runtimeBehaviors[i] is T)
+ {
+ runtimeBehaviors.RemoveAt(i);
+ }
+ }
+ }
+
+ private void ExecuteBehaviors(BehaviorTrigger trigger, Taggable user, Transform target, Vector3 point)
+ {
+ foreach (var behavior in runtimeBehaviors)
+ {
+ if (behavior.Trigger == trigger)
+ {
+ behavior.Execute(this, user, target, point);
+ }
+ }
+ }
+
+ // ========================================================================
+ // UTILITY METHODS
+ // ========================================================================
+
+ public RuntimeAbilityInstance Clone()
+ {
+ var clone = new RuntimeAbilityInstance(sourceAbility);
+
+ // Copy modifiers
+ foreach (var modifier in activeModifiers)
+ {
+ clone.AddModifier(modifier);
+ }
+
+ // Copy behaviors
+ foreach (var behavior in runtimeBehaviors)
+ {
+ clone.AddBehavior(behavior.Clone());
+ }
+
+ return clone;
+ }
+
+ private int GetMaxCharges()
+ {
+ // Future: add charge system
+ return 1;
+ }
+
+ // ========================================================================
+ // IMPLICIT CONVERSION - Makes it work seamlessly
+ // ========================================================================
+
+ public static implicit operator BaseAbility(RuntimeAbilityInstance instance)
+ {
+ return instance.sourceAbility;
+ }
+
+ public static implicit operator RuntimeAbilityInstance(BaseAbility ability)
+ {
+ return new RuntimeAbilityInstance(ability);
+ }
+}
\ No newline at end of file
diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/RuntimeAbilityInstance.cs.meta b/Assets/Scripts/AbilitySystem/AbilityInstance/RuntimeAbilityInstance.cs.meta
new file mode 100644
index 00000000..99b31578
--- /dev/null
+++ b/Assets/Scripts/AbilitySystem/AbilityInstance/RuntimeAbilityInstance.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 63ca0a6b1e4e799418c4e8dd0cf4ace5
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/RuntimeBehavior.cs b/Assets/Scripts/AbilitySystem/AbilityInstance/RuntimeBehavior.cs
new file mode 100644
index 00000000..7e5f2d16
--- /dev/null
+++ b/Assets/Scripts/AbilitySystem/AbilityInstance/RuntimeBehavior.cs
@@ -0,0 +1,19 @@
+using UnityEngine;
+
+public enum BehaviorTrigger
+{
+ PreCast, // Before ability executes
+ PostCast, // After ability executes
+ OnHit, // When ability hits target
+ OnKill, // When ability kills target
+ OnCrit // When ability crits
+}
+
+public abstract class RuntimeBehavior
+{
+ public BehaviorTrigger Trigger { get; set; }
+ public string BehaviorName { get; set; }
+
+ public abstract void Execute(RuntimeAbilityInstance ability, Taggable user, Transform target, Vector3 point);
+ public abstract RuntimeBehavior Clone();
+}
diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/RuntimeBehavior.cs.meta b/Assets/Scripts/AbilitySystem/AbilityInstance/RuntimeBehavior.cs.meta
new file mode 100644
index 00000000..421cd5f0
--- /dev/null
+++ b/Assets/Scripts/AbilitySystem/AbilityInstance/RuntimeBehavior.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0a8f3389f97c1f343ba02dc9b50a1848
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant: