diff --git a/Assets/Fantasy Skybox FREE/Panoramics/FS002/FS002_Night.mat b/Assets/Fantasy Skybox FREE/Panoramics/FS002/FS002_Night.mat index e12f787b..0e29b86d 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.1873918 + - _Rotation: 6.1601553 - _SmoothnessTextureChannel: 0 - _SpecularHighlights: 1 - _SrcBlend: 1 diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/Refactor/AbilityBehaviours.meta b/Assets/Scripts/AbilitySystem/AbilityInstance/Refactor/AbilityBehaviours.meta new file mode 100644 index 00000000..fa6285f0 --- /dev/null +++ b/Assets/Scripts/AbilitySystem/AbilityInstance/Refactor/AbilityBehaviours.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b8fc798226bf8b24e9bcefd5efa43c31 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/Refactor/AbilityBehaviours/ProjectileExecutionBehavior.cs b/Assets/Scripts/AbilitySystem/AbilityInstance/Refactor/AbilityBehaviours/ProjectileExecutionBehavior.cs new file mode 100644 index 00000000..fb161347 --- /dev/null +++ b/Assets/Scripts/AbilitySystem/AbilityInstance/Refactor/AbilityBehaviours/ProjectileExecutionBehavior.cs @@ -0,0 +1,181 @@ +using UnityEngine; + +public class ProjectileExecutionBehavior : RuntimeBehavior +{ + [Header("Projectile Settings")] + public GameObject projectilePrefab; + public float projectileSpeed = 15f; + public float lifeSpan = 1.5f; + public bool canPierce = false; + public bool canHitSelf = false; + + [Header("Movement Behaviour")] + public AnimationCurve speedOverLifetime = AnimationCurve.Linear(0, 1, 1, 1); + public bool useSpeedCurve = false; + public bool enableCurving = false; + public Vector3 curveAxis = Vector3.up; + public float curveStrength = 1f; + public float curveAmplitude = 45f; + + public bool enableRicochet = false; + public int maxRicochets = 1; + public float ricochetSpread = 10f; + + public ProjectileExecutionBehavior() + { + Trigger = BehaviorTrigger.Execute; // This replaces your Execute() override + BehaviorName = "Projectile Execution"; + } + + public override void Execute(RuntimeAbilityInstance ability, Taggable user, Transform target, Vector3 point) + { + // This is your old ProjectileAbility.Execute() logic! + + // Get spawn location + var spawnController = user.GetComponentInChildren(); + Vector3 spawnPos = spawnController?.transform.position ?? user.transform.position; + Quaternion spawnRot = spawnController?.transform.rotation ?? user.transform.rotation; + + // Spawn projectile + var projectileGO = Object.Instantiate(projectilePrefab, spawnPos, spawnRot); + + // Setup projectile + var networkedProjectile = projectileGO.GetComponent(); + if (networkedProjectile != null) + { + SetupProjectileInstance(ability, networkedProjectile, user); + + networkedProjectile.Init(); + } + } + + protected virtual void SetupProjectileInstance(RuntimeAbilityInstance ability, NetworkedProjectile networkedProjectile, Taggable user) + { + networkedProjectile.speed = projectileSpeed; + networkedProjectile.ownerTag = user; + networkedProjectile.ability = ability.SourceAbility; + networkedProjectile.lifeSpan = lifeSpan; + networkedProjectile.canPierce = canPierce; + networkedProjectile.canHitSelf = canHitSelf; + networkedProjectile.speedOverLifetime = speedOverLifetime; + networkedProjectile.useSpeedCurve = useSpeedCurve; + networkedProjectile.enableCurving = enableCurving; + networkedProjectile.curveAxis = curveAxis; + networkedProjectile.curveStrength = curveStrength; + networkedProjectile.curveAmplitude = curveAmplitude; + networkedProjectile.enableRicochet = enableRicochet; + networkedProjectile.maxRicochets = maxRicochets; + networkedProjectile.ricochetSpread = ricochetSpread; + } + + public override RuntimeBehavior Clone() + { + return new ProjectileExecutionBehavior + { + // Basic settings + projectilePrefab = this.projectilePrefab, + projectileSpeed = this.projectileSpeed, + lifeSpan = this.lifeSpan, + canPierce = this.canPierce, + canHitSelf = this.canHitSelf, + + // Movement behavior + speedOverLifetime = this.speedOverLifetime, + useSpeedCurve = this.useSpeedCurve, + enableCurving = this.enableCurving, + curveAxis = this.curveAxis, + curveStrength = this.curveStrength, + curveAmplitude = this.curveAmplitude, + enableRicochet = this.enableRicochet, + maxRicochets = this.maxRicochets, + ricochetSpread = this.ricochetSpread + }; + } + + // ======================================================================== + // FACTORY METHODS - Easy Creation of Common Projectile Types + // ======================================================================== + + /// + /// Create a simple straight projectile + /// + public static ProjectileExecutionBehavior CreateSimple(GameObject prefab, float speed = 15f, float lifeSpan = 5f) + { + return new ProjectileExecutionBehavior + { + projectilePrefab = prefab, + projectileSpeed = speed, + lifeSpan = lifeSpan + }; + } + + /// + /// Create a piercing projectile + /// + public static ProjectileExecutionBehavior CreatePiercing(GameObject prefab, float speed = 15f, float lifeSpan = 5f) + { + return new ProjectileExecutionBehavior + { + projectilePrefab = prefab, + projectileSpeed = speed, + lifeSpan = lifeSpan, + canPierce = true + }; + } + + /// + /// Create a curved projectile (like magic missile) + /// + public static ProjectileExecutionBehavior CreateCurved(GameObject prefab, float speed = 12f, float curveStrength = 2f) + { + return new ProjectileExecutionBehavior + { + projectilePrefab = prefab, + projectileSpeed = speed, + enableCurving = true, + curveStrength = curveStrength, + curveAmplitude = 30f + }; + } + + /// + /// Create a ricochet projectile + /// + public static ProjectileExecutionBehavior CreateRicochet(GameObject prefab, int maxBounces = 3, float speed = 15f) + { + return new ProjectileExecutionBehavior + { + projectilePrefab = prefab, + projectileSpeed = speed, + enableRicochet = true, + maxRicochets = maxBounces, + ricochetSpread = 15f + }; + } + + /// + /// Create a projectile with speed curve (accelerating/decelerating) + /// + public static ProjectileExecutionBehavior CreateWithSpeedCurve(GameObject prefab, AnimationCurve curve, float baseSpeed = 15f) + { + return new ProjectileExecutionBehavior + { + projectilePrefab = prefab, + projectileSpeed = baseSpeed, + useSpeedCurve = true, + speedOverLifetime = curve + }; + } + + public static ProjectileExecutionBehavior CreateIceshardLikeWithCurve(GameObject prefab, float baseSpeed = 15f) + { + return new ProjectileExecutionBehavior + { + projectilePrefab = prefab, + projectileSpeed = baseSpeed, + useSpeedCurve = true, + lifeSpan = 1f, + speedOverLifetime = GameConstants.BehaviorUtils.GetIceshardProjectileCurve() + }; + } +} \ No newline at end of file diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/Refactor/AbilityBehaviours/ProjectileExecutionBehavior.cs.meta b/Assets/Scripts/AbilitySystem/AbilityInstance/Refactor/AbilityBehaviours/ProjectileExecutionBehavior.cs.meta new file mode 100644 index 00000000..c626ed37 --- /dev/null +++ b/Assets/Scripts/AbilitySystem/AbilityInstance/Refactor/AbilityBehaviours/ProjectileExecutionBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ae360e58fae69584f9a3a850f466195f +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 index 5a9f5cb9..9104f0ca 100644 --- a/Assets/Scripts/AbilitySystem/AbilityInstance/RuntimeAbilityInstance.cs +++ b/Assets/Scripts/AbilitySystem/AbilityInstance/RuntimeAbilityInstance.cs @@ -191,6 +191,8 @@ public class RuntimeAbilityInstance Health userHealth; public virtual void SpendResourcesNecessary(Taggable user) { + if (userMana == null) userMana = user.GetComponent(); + if (userHealth == null) userHealth = user.GetComponent(); userMana.ChangeValue(-GetFinalManaCost(user)); userHealth.ChangeValue(-GetFinalHealthCost(user)); @@ -202,8 +204,10 @@ public class RuntimeAbilityInstance if (!CanExecute(user)) return; ExecuteBehaviors(BehaviorTrigger.PreCast, user, null, Vector3.zero); + SpendResourcesNecessary(user); - sourceAbility.Execute(user); + ExecuteBehaviors(BehaviorTrigger.Execute, user, null, Vector3.zero); + ExecuteBehaviors(BehaviorTrigger.PostCast, user, null, Vector3.zero); lastUsedTime = Time.time; @@ -214,8 +218,10 @@ public class RuntimeAbilityInstance if (!CanExecute(user)) return; ExecuteBehaviors(BehaviorTrigger.PreCast, user, null, point); + SpendResourcesNecessary(user); - sourceAbility.Execute(user, point); + ExecuteBehaviors(BehaviorTrigger.Execute, user, null, point); + ExecuteBehaviors(BehaviorTrigger.PostCast, user, null, point); lastUsedTime = Time.time; @@ -226,8 +232,10 @@ public class RuntimeAbilityInstance if (!CanExecute(user)) return; ExecuteBehaviors(BehaviorTrigger.PreCast, user, target, target.position); + SpendResourcesNecessary(user); - sourceAbility.Execute(user, target); + ExecuteBehaviors(BehaviorTrigger.Execute, user, target, target.position); + ExecuteBehaviors(BehaviorTrigger.PostCast, user, target, target.position); lastUsedTime = Time.time; diff --git a/Assets/Scripts/AbilitySystem/AbilityInstance/RuntimeBehavior.cs b/Assets/Scripts/AbilitySystem/AbilityInstance/RuntimeBehavior.cs index 46d0b4c0..3a7a7928 100644 --- a/Assets/Scripts/AbilitySystem/AbilityInstance/RuntimeBehavior.cs +++ b/Assets/Scripts/AbilitySystem/AbilityInstance/RuntimeBehavior.cs @@ -2,12 +2,15 @@ using UnityEngine; public enum BehaviorTrigger { - PreCast, // Before ability executes - Execute, // MAIN EXECUTION - replaces your override Execute() - PostCast, // After ability executes - OnHit, // When ability hits target - OnKill, // When ability kills target - OnCrit // When ability crits + PreCast, // Before ability executes + Execute, // MAIN EXECUTION - replaces your override Execute() + PostCast, // After ability executes + OnHit, // When ability hits target + OnKill, // When ability kills target + OnCrit, // When ability crits + OnMiss, // When ability misses + OnChannelTick, // During channeling + OnChannelEnd // When channeling ends } public abstract class RuntimeBehavior diff --git a/Assets/Scripts/Game/GameConstants.cs b/Assets/Scripts/Game/GameConstants.cs index 81dac888..fbb034ff 100644 --- a/Assets/Scripts/Game/GameConstants.cs +++ b/Assets/Scripts/Game/GameConstants.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; using static GameConstants.EnemySpawning; public static class GameConstants @@ -408,4 +408,24 @@ public static class GameConstants return HuntersInn; } } + + public static class BehaviorUtils + { + public static AnimationCurve GetIceshardProjectileCurve() + { + var keyframes = new Keyframe[] + { + // time, value, inTangent, outTangent + new Keyframe(0.0f, 0.0f, -0.0635979f, -0.0635979f), + new Keyframe(0.6008623f, 1.0058026f, 3.168166f, 3.168166f), // ← This steep tangent creates the sharp rise! + new Keyframe(0.9846547f, 1.3325472f, 0.3161671f, 0.3161671f) + }; + + var curve = new AnimationCurve(keyframes); + curve.preWrapMode = WrapMode.PingPong; + curve.postWrapMode = WrapMode.PingPong; + + return curve; + } + } } \ No newline at end of file diff --git a/Assets/Scripts/Networking/NetworkedProjectile.cs b/Assets/Scripts/Networking/NetworkedProjectile.cs index d5b9cf2d..0c285c99 100644 --- a/Assets/Scripts/Networking/NetworkedProjectile.cs +++ b/Assets/Scripts/Networking/NetworkedProjectile.cs @@ -11,7 +11,7 @@ public class NetworkedProjectile : MonoBehaviour [Header("Set by code")] public Taggable ownerTag; - public ProjectileAbility ability; + public BaseAbility ability; public float speed; public float lifeSpan; public bool canPierce; @@ -79,6 +79,7 @@ public class NetworkedProjectile : MonoBehaviour float lifetimeFraction = Mathf.Clamp01(timeAlive / lifeSpan); float currentSpeed = useSpeedCurve ? speed * speedOverLifetime.Evaluate(lifetimeFraction) : speed; + // Curving logic if (enableCurving) { diff --git a/Assets/Scripts/Player/AbilityKeyBinder.cs b/Assets/Scripts/Player/AbilityKeyBinder.cs index e076063a..30e5e073 100644 --- a/Assets/Scripts/Player/AbilityKeyBinder.cs +++ b/Assets/Scripts/Player/AbilityKeyBinder.cs @@ -185,6 +185,11 @@ public class AbilityKeyBinder : MonoBehaviour [ContextMenu("debug Add manacost reduction")] public void AddManaCostModifierDebug() { + if(abilityInstance.SourceAbility is ProjectileAbility projectileAbility) + { + abilityInstance.AddBehavior(ProjectileExecutionBehavior.CreateIceshardLikeWithCurve(projectileAbility.projectilePrefab, 50f)); + } + abilityInstance.AddModifier(AbilityModifier.CreateManaCostReduction(100f)); }