commit ca6888dcdb2c0f736ecebad7f703f9778641e135 Author: cursor Date: Thu May 28 19:41:27 2026 +0800 feat: initial Survivors-like roguelike core (runtime scripts + ScriptableObject configs) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..826060a --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# Unity generated +[Ll]ibrary/ +[Tt]emp/ +[Oo]bj/ +[Bb]uild/ +[Bb]uilds/ +[Ll]ogs/ +[Mm]emoryCaptures/ +[Uu]ser[Ss]ettings/ + +# Visual Studio / Rider / VSCode +.vs/ +.idea/ +.vscode/ +*.csproj +*.unityproj +*.sln +*.suo +*.tmp +*.user +*.userprefs +*.pidb +*.booproj +*.svd +*.pdb +*.mdb +*.opendb +*.VC.db + +# Mac / Win artifacts +.DS_Store +Thumbs.db diff --git a/Assets/Common/Scriptables/Abilities.meta b/Assets/Common/Scriptables/Abilities.meta new file mode 100644 index 0000000..a53a8b0 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d2d8e8dbe1dbcf543ae91e9a1fb3e10c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Abilities Database.asset b/Assets/Common/Scriptables/Abilities/Abilities Database.asset new file mode 100644 index 0000000..dae936e --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Abilities Database.asset @@ -0,0 +1,60 @@ +%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: 2f769f2d35f4a354ab98600d8c1dbb7d, type: 3} + m_Name: Abilities Database + m_EditorClassIdentifier: + activeAbilitiesCapacity: 5 + passiveAbilitiesCapacity: 5 + firstLevelsActiveAbilityWeightMultiplier: 1.3 + aquiredAbilityWeightMultiplier: 1.2 + lessAbilitiesOfTypeWeightMultiplier: 1.1 + evolutionAbilityWeightMultiplier: 100 + requiredForEvolutionWeightMultiplier: 1.2 + abilities: + - {fileID: 11400000, guid: 17b419b3688adff418fafed2eb9f2f65, type: 2} + - {fileID: 11400000, guid: 8f7fe624f38159e41b282ad9af85dda0, type: 2} + - {fileID: 11400000, guid: b6e5ed8f600b20e42a5e984cecc14007, type: 2} + - {fileID: 11400000, guid: 01683b4df1f2df741bade2fcfb760c25, type: 2} + - {fileID: 11400000, guid: 81f53358e8dd08a40975bc2878b4158d, type: 2} + - {fileID: 11400000, guid: ead779c451f81f64a89db19886d5b37d, type: 2} + - {fileID: 11400000, guid: e6b8c86ab9c26e745811baae9b6aa84e, type: 2} + - {fileID: 11400000, guid: 90e23cc696c2b93439f7821c9a20c4b1, type: 2} + - {fileID: 11400000, guid: 29fecd0e6b7486c4f8159cf20a4ce053, type: 2} + - {fileID: 11400000, guid: b78ac4f102c39054ca6d376c82b818c0, type: 2} + - {fileID: 11400000, guid: e2e912d0319d0294d970714e454973f4, type: 2} + - {fileID: 11400000, guid: 4e3ec23ddf3546540a91ee20406d5e23, type: 2} + - {fileID: 11400000, guid: 303b35ed2fe1775489371e462afeba90, type: 2} + - {fileID: 11400000, guid: 68bf2ddb340e23e42ba85d719a8d00cc, type: 2} + - {fileID: 11400000, guid: 206aa8a212976cf4dab94c9a90ea7669, type: 2} + - {fileID: 11400000, guid: a275a7d5150ef554e9c5a3bd803a1b06, type: 2} + - {fileID: 11400000, guid: 73cc0fc0393904447b2f03c569a66560, type: 2} + - {fileID: 11400000, guid: df2f06ecdaeed194784b46508baa8bf4, type: 2} + - {fileID: 11400000, guid: 3da9b537208fdea4aafe4336fb9fc095, type: 2} + - {fileID: 11400000, guid: d444d795f98c5d645b82592f227bf2e7, type: 2} + - {fileID: 11400000, guid: 7f98fa6689940d54e820a5c62dc94643, type: 2} + - {fileID: 11400000, guid: 17544eb3b9ef7b4488338169d6ba2435, type: 2} + - {fileID: 11400000, guid: 8f88486c784281d4c928ddb0096ec25c, type: 2} + - {fileID: 11400000, guid: 31908ed3d6273e240adbe04400b5ce8e, type: 2} + - {fileID: 11400000, guid: 834df31f9b7b4d94cbc14473515c5a20, type: 2} + - {fileID: 11400000, guid: 32ad250b89ed5bc43916d37d311f9169, type: 2} + - {fileID: 11400000, guid: 8be61207359b9414ca0b29385b10fdc4, type: 2} + - {fileID: 11400000, guid: 6cf8b3a62989f6845a032fb2d91e67ac, type: 2} + - {fileID: 11400000, guid: 67276880eecf0844f8aa8103c961994c, type: 2} + - {fileID: 11400000, guid: 23bb3bcb8f644004fa03a63f6da83f20, type: 2} + - {fileID: 11400000, guid: 7012f7a45b17ee44ca872ea3f1d6f16f, type: 2} + - {fileID: 11400000, guid: e5aef831ee372c54b8b45fc5c6c3fa3b, type: 2} + - {fileID: 11400000, guid: 522560204eb32d34aa67b1e797b7fbff, type: 2} + - {fileID: 11400000, guid: bc68c616d5b0c8a43b746f4bd1d6d5e1, type: 2} + - {fileID: 11400000, guid: d401b79ae48e63a42af24f9c2ba0046c, type: 2} + - {fileID: 11400000, guid: b20706c7fd909aa4a98f7556c43be9c8, type: 2} + - {fileID: 11400000, guid: 02f5acbbbf0052c43a72e6e0a0faecb3, type: 2} + - {fileID: 11400000, guid: 932cd3900cec3574493ce2137e745ac8, type: 2} diff --git a/Assets/Common/Scriptables/Abilities/Abilities Database.asset.meta b/Assets/Common/Scriptables/Abilities/Abilities Database.asset.meta new file mode 100644 index 0000000..02aa76c --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Abilities Database.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0647b23f7b3015041b61926ed80fbbe4 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities.meta b/Assets/Common/Scriptables/Abilities/Active Abilities.meta new file mode 100644 index 0000000..1deb1e3 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 25e846ec651e76a4bb0597178c6dfa6b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Boomerang Ability Data.asset b/Assets/Common/Scriptables/Abilities/Active Abilities/Boomerang Ability Data.asset new file mode 100644 index 0000000..11a7ba8 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Boomerang Ability Data.asset @@ -0,0 +1,59 @@ +%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: 6a60f52c2a6bf3b4a81b89d34e2fe101, type: 3} + m_Name: Boomerang Ability Data + m_EditorClassIdentifier: + type: 7 + title: Boomerang + description: Throw a sharp and swift boomerang + icon: {fileID: 21300000, guid: afd43a1a1c0dff84a8155a44de0022ff, type: 3} + prefab: {fileID: 7692142567880169807, guid: 348e519951a23e84c9d86c5c1f89387f, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - projectileCount: 1 + projectileLifetime: 2 + timeBetweenProjectiles: 0.3 + abilityCooldown: 5 + projectileTravelDistance: 3 + damage: 12 + projectileSize: 0.75 + - projectileCount: 1 + projectileLifetime: 2 + timeBetweenProjectiles: 0.3 + abilityCooldown: 5 + projectileTravelDistance: 3 + damage: 15 + projectileSize: 1 + - projectileCount: 2 + projectileLifetime: 2 + timeBetweenProjectiles: 0.3 + abilityCooldown: 5 + projectileTravelDistance: 3 + damage: 20 + projectileSize: 1 + - projectileCount: 2 + projectileLifetime: 2 + timeBetweenProjectiles: 0.3 + abilityCooldown: 5 + projectileTravelDistance: 3.5 + damage: 30 + projectileSize: 1.25 + - projectileCount: 3 + projectileLifetime: 2 + timeBetweenProjectiles: 0.3 + abilityCooldown: 5 + projectileTravelDistance: 3.5 + damage: 35 + projectileSize: 1.25 diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Boomerang Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Active Abilities/Boomerang Ability Data.asset.meta new file mode 100644 index 0000000..7612446 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Boomerang Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 90e23cc696c2b93439f7821c9a20c4b1 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Fireball Ability Data.asset b/Assets/Common/Scriptables/Abilities/Active Abilities/Fireball Ability Data.asset new file mode 100644 index 0000000..a0cf8e2 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Fireball Ability Data.asset @@ -0,0 +1,64 @@ +%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: 1586f7d6c44294444ad7f5dcc23f4e22, type: 3} + m_Name: Fireball Ability Data + m_EditorClassIdentifier: + type: 6 + title: Fireball + description: Fires a projectile that strikes nearby enemies + icon: {fileID: 21300000, guid: 577e39ea3e885f548bb3b57738bf8084, type: 3} + prefab: {fileID: 8666185439850298685, guid: 9baadb2220f82de488e6d4d5eb4ba662, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - projectilesCount: 1 + timeBetweenFireballs: 0.2 + abilityCooldown: 5 + fireballLifetime: 5 + speed: 3 + damage: 15 + projectileSize: 1 + explosionRadius: 1 + - projectilesCount: 2 + timeBetweenFireballs: 0.2 + abilityCooldown: 5 + fireballLifetime: 5 + speed: 3 + damage: 15 + projectileSize: 1 + explosionRadius: 1 + - projectilesCount: 2 + timeBetweenFireballs: 0.2 + abilityCooldown: 5 + fireballLifetime: 5 + speed: 4 + damage: 15 + projectileSize: 1 + explosionRadius: 1.5 + - projectilesCount: 3 + timeBetweenFireballs: 0.2 + abilityCooldown: 5 + fireballLifetime: 5 + speed: 4 + damage: 20 + projectileSize: 1 + explosionRadius: 1.5 + - projectilesCount: 3 + timeBetweenFireballs: 0.2 + abilityCooldown: 5 + fireballLifetime: 5 + speed: 5 + damage: 20 + projectileSize: 1.25 + explosionRadius: 1.75 diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Fireball Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Active Abilities/Fireball Ability Data.asset.meta new file mode 100644 index 0000000..41d2c5b --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Fireball Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e6b8c86ab9c26e745811baae9b6aa84e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Flying Dagger Ability Data.asset b/Assets/Common/Scriptables/Abilities/Active Abilities/Flying Dagger Ability Data.asset new file mode 100644 index 0000000..33df997 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Flying Dagger Ability Data.asset @@ -0,0 +1,64 @@ +%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: ca844530d09d39247b276cdc829f2c85, type: 3} + m_Name: Flying Dagger Ability Data + m_EditorClassIdentifier: + type: 8 + title: Flying Daggers + description: Launches a spinning spectral dagger + icon: {fileID: 21300000, guid: b24b88b28c170c541bd1ba7328631066, type: 3} + prefab: {fileID: 2508247732540034436, guid: 96b489f6283cc1f4a8f703293f1c971b, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - projectileCount: 1 + projectileLifetime: 4 + timeBetweenProjectiles: 0.2 + abilityCooldown: 5 + throwingForce: 8 + spread: 20 + damage: 15 + projectileSize: 1 + - projectileCount: 2 + projectileLifetime: 4 + timeBetweenProjectiles: 0.2 + abilityCooldown: 5 + throwingForce: 8 + spread: 20 + damage: 15 + projectileSize: 1 + - projectileCount: 2 + projectileLifetime: 4 + timeBetweenProjectiles: 0.2 + abilityCooldown: 5 + throwingForce: 8 + spread: 20 + damage: 20 + projectileSize: 1.2 + - projectileCount: 3 + projectileLifetime: 4 + timeBetweenProjectiles: 0.2 + abilityCooldown: 5 + throwingForce: 8 + spread: 20 + damage: 20 + projectileSize: 1.2 + - projectileCount: 3 + projectileLifetime: 4 + timeBetweenProjectiles: 0.2 + abilityCooldown: 5 + throwingForce: 8 + spread: 20 + damage: 25 + projectileSize: 1.4 diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Flying Dagger Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Active Abilities/Flying Dagger Ability Data.asset.meta new file mode 100644 index 0000000..9fe4e8a --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Flying Dagger Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7012f7a45b17ee44ca872ea3f1d6f16f +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Guardian Eye Ability Data.asset b/Assets/Common/Scriptables/Abilities/Active Abilities/Guardian Eye Ability Data.asset new file mode 100644 index 0000000..11e8743 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Guardian Eye Ability Data.asset @@ -0,0 +1,39 @@ +%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: cee9e708d20778f40be895baad2b4eee, type: 3} + m_Name: Guardian Eye Ability Data + m_EditorClassIdentifier: + type: 1 + title: Guardian Eye + description: Deals damage in a small area around + icon: {fileID: 21300000, guid: 43e89f4117adb7543a2adcc4e982d470, type: 3} + prefab: {fileID: 6046089768498997805, guid: 7788118687ac2254e9574b5bcaf6d2ff, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - fieldRadius: 0.8 + damage: 5 + damageCooldown: 1 + - fieldRadius: 1 + damage: 10 + damageCooldown: 1 + - fieldRadius: 1.2 + damage: 15 + damageCooldown: 1 + - fieldRadius: 1.4 + damage: 15 + damageCooldown: 1 + - fieldRadius: 1.6 + damage: 20 + damageCooldown: 1 diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Guardian Eye Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Active Abilities/Guardian Eye Ability Data.asset.meta new file mode 100644 index 0000000..8da1d44 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Guardian Eye Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8f7fe624f38159e41b282ad9af85dda0 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Ice Shard Data.asset b/Assets/Common/Scriptables/Abilities/Active Abilities/Ice Shard Data.asset new file mode 100644 index 0000000..98a7ebe --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Ice Shard Data.asset @@ -0,0 +1,54 @@ +%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: a6efdef0c11be664597b6b3c59fb6057, type: 3} + m_Name: Ice Shard Data + m_EditorClassIdentifier: + type: 4 + title: Ice Shard + description: Casts a sharp icicle that pierces enemies + icon: {fileID: 21300000, guid: 0700ef6a20c782f49927467fc59fe412, type: 3} + prefab: {fileID: 5201831521697468584, guid: 5e520e21ec743914684cec0903e7c54f, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - abilityCooldown: 10 + projectileSpeed: 5 + damage: 20 + projectileSize: 1 + projectilesCount: 1 + projectileLifetime: 7 + - abilityCooldown: 10 + projectileSpeed: 6 + damage: 20 + projectileSize: 1 + projectilesCount: 2 + projectileLifetime: 7 + - abilityCooldown: 10 + projectileSpeed: 7 + damage: 25 + projectileSize: 1 + projectilesCount: 2 + projectileLifetime: 7 + - abilityCooldown: 10 + projectileSpeed: 8 + damage: 25 + projectileSize: 1 + projectilesCount: 3 + projectileLifetime: 7 + - abilityCooldown: 10 + projectileSpeed: 9 + damage: 25 + projectileSize: 1.25 + projectilesCount: 3 + projectileLifetime: 7 diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Ice Shard Data.asset.meta b/Assets/Common/Scriptables/Abilities/Active Abilities/Ice Shard Data.asset.meta new file mode 100644 index 0000000..3a4ce0d --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Ice Shard Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 81f53358e8dd08a40975bc2878b4158d +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Lightning Amulet Ability Data.asset b/Assets/Common/Scriptables/Abilities/Active Abilities/Lightning Amulet Ability Data.asset new file mode 100644 index 0000000..df836b8 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Lightning Amulet Ability Data.asset @@ -0,0 +1,54 @@ +%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: 42aa83e6078ee1941b2f913d17e7c367, type: 3} + m_Name: Lightning Amulet Ability Data + m_EditorClassIdentifier: + type: 2 + title: Lightning Amulet + description: Strikes with lightning from above + icon: {fileID: 21300000, guid: dee88c54be51e674fb9e4078c61d3cd9, type: 3} + prefab: {fileID: 4750932732856416329, guid: c37d6662bf5c9b14cbd31a3cf83221c5, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - damage: 20 + additionalDamage: 5 + additionalDamageRadius: 0.5 + lightningsCount: 1 + abilityCooldown: 5 + durationBetweenHits: 0.2 + - damage: 20 + additionalDamage: 5 + additionalDamageRadius: 0.5 + lightningsCount: 2 + abilityCooldown: 5 + durationBetweenHits: 0.2 + - damage: 20 + additionalDamage: 5 + additionalDamageRadius: 0.5 + lightningsCount: 3 + abilityCooldown: 5 + durationBetweenHits: 0.2 + - damage: 25 + additionalDamage: 7 + additionalDamageRadius: 0.5 + lightningsCount: 4 + abilityCooldown: 5 + durationBetweenHits: 0.2 + - damage: 30 + additionalDamage: 10 + additionalDamageRadius: 0.5 + lightningsCount: 5 + abilityCooldown: 5 + durationBetweenHits: 0.2 diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Lightning Amulet Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Active Abilities/Lightning Amulet Ability Data.asset.meta new file mode 100644 index 0000000..d7c801e --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Lightning Amulet Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b6e5ed8f600b20e42a5e984cecc14007 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Magic Rune Ability Data.asset b/Assets/Common/Scriptables/Abilities/Active Abilities/Magic Rune Ability Data.asset new file mode 100644 index 0000000..24f16ea --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Magic Rune Ability Data.asset @@ -0,0 +1,64 @@ +%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: 89c22678ba1bc0d46aea067da436741b, type: 3} + m_Name: Magic Rune Ability Data + m_EditorClassIdentifier: + type: 5 + title: Magic Rune + description: Leaves an explosive symbol on the floor + icon: {fileID: 21300000, guid: 41b11da08bfbd71468e55b3dc58c105d, type: 3} + prefab: {fileID: 6119386174245202466, guid: 460c16e3997ff1d43b013c9b00f6ec69, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - minesCount: 2 + abilityCooldown: 5 + mineSpawnRadius: 2 + mineLifetime: 5 + damage: 20 + mineSize: 1 + mineTriggerRadius: 0.3 + mineDamageRadius: 1 + - minesCount: 2 + abilityCooldown: 5 + mineSpawnRadius: 2 + mineLifetime: 6 + damage: 20 + mineSize: 1.2 + mineTriggerRadius: 0.35 + mineDamageRadius: 1.2 + - minesCount: 3 + abilityCooldown: 5 + mineSpawnRadius: 2.5 + mineLifetime: 7 + damage: 25 + mineSize: 1.4 + mineTriggerRadius: 0.4 + mineDamageRadius: 1.4 + - minesCount: 3 + abilityCooldown: 5 + mineSpawnRadius: 2.5 + mineLifetime: 8 + damage: 25 + mineSize: 1.6 + mineTriggerRadius: 0.45 + mineDamageRadius: 1.6 + - minesCount: 3 + abilityCooldown: 5 + mineSpawnRadius: 2.5 + mineLifetime: 9 + damage: 30 + mineSize: 1.8 + mineTriggerRadius: 0.5 + mineDamageRadius: 1.8 diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Magic Rune Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Active Abilities/Magic Rune Ability Data.asset.meta new file mode 100644 index 0000000..1bf9620 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Magic Rune Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ead779c451f81f64a89db19886d5b37d +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Rolling Stone Data.asset b/Assets/Common/Scriptables/Abilities/Active Abilities/Rolling Stone Data.asset new file mode 100644 index 0000000..c54019f --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Rolling Stone Data.asset @@ -0,0 +1,44 @@ +%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: 44ab41556cf462c409841060a869521f, type: 3} + m_Name: Rolling Stone Data + m_EditorClassIdentifier: + type: 3 + title: Rolling Stone + description: Rolling friend + icon: {fileID: 21300000, guid: 5d17e3fe7deb3c449b42f69343d16183, type: 3} + prefab: {fileID: 3128169338053202466, guid: 565cc53bad5258c4984210d9f55ab7b2, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - speed: 1 + angularSpeed: 180 + damage: 20 + size: 0.5 + - speed: 1 + angularSpeed: 180 + damage: 20 + size: 0.5 + - speed: 1 + angularSpeed: 180 + damage: 25 + size: 0.75 + - speed: 1 + angularSpeed: 180 + damage: 30 + size: 0.75 + - speed: 1 + angularSpeed: 180 + damage: 35 + size: 1 diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Rolling Stone Data.asset.meta b/Assets/Common/Scriptables/Abilities/Active Abilities/Rolling Stone Data.asset.meta new file mode 100644 index 0000000..4e0b6d4 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Rolling Stone Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 01683b4df1f2df741bade2fcfb760c25 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Shooting Star Ability Data.asset b/Assets/Common/Scriptables/Abilities/Active Abilities/Shooting Star Ability Data.asset new file mode 100644 index 0000000..ce2d4a5 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Shooting Star Ability Data.asset @@ -0,0 +1,54 @@ +%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: b5c5b94e0f62c8c4aa563be6b3ce9c7b, type: 3} + m_Name: Shooting Star Ability Data + m_EditorClassIdentifier: + type: 0 + title: Shooting Star + description: Orbits around, damaging enemies + icon: {fileID: 21300000, guid: 8142a6c24c1cc7149a27153a8e0d8c2f, type: 3} + prefab: {fileID: 8808691205632778037, guid: 84c63e5479c7eae46bf3db3b9662f6ca, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - damage: 5 + abilityCooldown: 6 + projectileLifetime: 3 + projectilesCount: 2 + radius: 1.5 + angularSpeed: -200 + - damage: 10 + abilityCooldown: 6 + projectileLifetime: 3 + projectilesCount: 3 + radius: 1.5 + angularSpeed: -200 + - damage: 10 + abilityCooldown: 6 + projectileLifetime: 3 + projectilesCount: 4 + radius: 1.5 + angularSpeed: -200 + - damage: 15 + abilityCooldown: 6 + projectileLifetime: 3 + projectilesCount: 5 + radius: 1.5 + angularSpeed: -250 + - damage: 20 + abilityCooldown: 6 + projectileLifetime: 3 + projectilesCount: 6 + radius: 1.5 + angularSpeed: -300 diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Shooting Star Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Active Abilities/Shooting Star Ability Data.asset.meta new file mode 100644 index 0000000..0a0d7d4 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Shooting Star Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 17b419b3688adff418fafed2eb9f2f65 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Solar Magnifier Ability Data.asset b/Assets/Common/Scriptables/Abilities/Active Abilities/Solar Magnifier Ability Data.asset new file mode 100644 index 0000000..3c9d7be --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Solar Magnifier Ability Data.asset @@ -0,0 +1,69 @@ +%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: bb78b06ae98fb384483dcb5b4aa8b89c, type: 3} + m_Name: Solar Magnifier Ability Data + m_EditorClassIdentifier: + type: 9 + title: Solar Magnifier + description: Projects a powerful sun ray + icon: {fileID: 21300000, guid: c4ac29c7394f6bf47a67cdfb92999b25, type: 3} + prefab: {fileID: 3459857695509158651, guid: dca1e126c4f292044898a3114e53ce78, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - abilityCooldown: 10 + projectileLifetime: 5 + timeBetweenProjectiles: 1 + projectileCount: 1 + damagePerSecond: 7 + damageRate: 5 + additionalDamagePerSecond: 3 + additionalDamageRadius: 0.4 + projectileSpeed: 5 + - abilityCooldown: 10 + projectileLifetime: 5 + timeBetweenProjectiles: 1 + projectileCount: 2 + damagePerSecond: 9 + damageRate: 5 + additionalDamagePerSecond: 4 + additionalDamageRadius: 0.4 + projectileSpeed: 6 + - abilityCooldown: 10 + projectileLifetime: 7 + timeBetweenProjectiles: 1 + projectileCount: 2 + damagePerSecond: 11 + damageRate: 5 + additionalDamagePerSecond: 5 + additionalDamageRadius: 0.4 + projectileSpeed: 6 + - abilityCooldown: 10 + projectileLifetime: 7 + timeBetweenProjectiles: 1 + projectileCount: 3 + damagePerSecond: 13 + damageRate: 5 + additionalDamagePerSecond: 6 + additionalDamageRadius: 0.4 + projectileSpeed: 7 + - abilityCooldown: 10 + projectileLifetime: 8 + timeBetweenProjectiles: 1 + projectileCount: 3 + damagePerSecond: 16 + damageRate: 5 + additionalDamagePerSecond: 7 + additionalDamageRadius: 0.4 + projectileSpeed: 7 diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Solar Magnifier Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Active Abilities/Solar Magnifier Ability Data.asset.meta new file mode 100644 index 0000000..94cf57e --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Solar Magnifier Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 67276880eecf0844f8aa8103c961994c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Steel Sword Data.asset b/Assets/Common/Scriptables/Abilities/Active Abilities/Steel Sword Data.asset new file mode 100644 index 0000000..cdb5ec5 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Steel Sword Data.asset @@ -0,0 +1,49 @@ +%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: 5bafa157c553fd74398db8cc932d5cda, type: 3} + m_Name: Steel Sword Data + m_EditorClassIdentifier: + type: 1001 + title: Steel Sword + description: Slashes enemies in front of you + icon: {fileID: 21300000, guid: f75bf02f0e4a26946a94de1178ad1352, type: 3} + prefab: {fileID: 5349004258488764192, guid: 1fb009b476592b649aae6523123f1897, type: 3} + isActiveAbility: 1 + isWeaponAbility: 1 + isEvolution: 0 + evolutionRequirements: [] + levels: + - abilityCooldown: 2 + slashesCount: 1 + damage: 10 + slashSize: 1 + timeBetweenSlashes: 0.2 + - abilityCooldown: 2 + slashesCount: 2 + damage: 10 + slashSize: 1 + timeBetweenSlashes: 0.2 + - abilityCooldown: 2 + slashesCount: 3 + damage: 15 + slashSize: 1.2 + timeBetweenSlashes: 0.2 + - abilityCooldown: 2 + slashesCount: 4 + damage: 15 + slashSize: 1.2 + timeBetweenSlashes: 0.2 + - abilityCooldown: 2 + slashesCount: 5 + damage: 15 + slashSize: 1.4 + timeBetweenSlashes: 0.2 diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Steel Sword Data.asset.meta b/Assets/Common/Scriptables/Abilities/Active Abilities/Steel Sword Data.asset.meta new file mode 100644 index 0000000..0189d05 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Steel Sword Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d401b79ae48e63a42af24f9c2ba0046c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Wooden Wand Data.asset b/Assets/Common/Scriptables/Abilities/Active Abilities/Wooden Wand Data.asset new file mode 100644 index 0000000..ddf6c11 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Wooden Wand Data.asset @@ -0,0 +1,49 @@ +%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: 30b7a9b80971a9e4d8f8a1c92b676589, type: 3} + m_Name: Wooden Wand Data + m_EditorClassIdentifier: + type: 1000 + title: Wooden Wand + description: Shoots a magic projectile in nearby enemy + icon: {fileID: 21300000, guid: 0d11faf1f53fabf458ed6205557339c5, type: 3} + prefab: {fileID: 8295970409944387311, guid: fef53c88fbaf9b74d8f8b7ace6957279, type: 3} + isActiveAbility: 1 + isWeaponAbility: 1 + isEvolution: 0 + evolutionRequirements: [] + levels: + - abilityCooldown: 1 + projectileSpeed: 5 + damage: 10 + projectileSize: 1 + projectileLifetime: 5 + - abilityCooldown: 0.5 + projectileSpeed: 6 + damage: 10 + projectileSize: 1 + projectileLifetime: 5 + - abilityCooldown: 0.4 + projectileSpeed: 7 + damage: 15 + projectileSize: 1 + projectileLifetime: 5 + - abilityCooldown: 0.35 + projectileSpeed: 8 + damage: 20 + projectileSize: 1 + projectileLifetime: 5 + - abilityCooldown: 0.25 + projectileSpeed: 8 + damage: 20 + projectileSize: 1 + projectileLifetime: 5 diff --git a/Assets/Common/Scriptables/Abilities/Active Abilities/Wooden Wand Data.asset.meta b/Assets/Common/Scriptables/Abilities/Active Abilities/Wooden Wand Data.asset.meta new file mode 100644 index 0000000..880542a --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Active Abilities/Wooden Wand Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 522560204eb32d34aa67b1e797b7fbff +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Evolution.meta b/Assets/Common/Scriptables/Abilities/Evolution.meta new file mode 100644 index 0000000..6443ed6 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3ef7e770ed4d3bd4aa84b53423e1e9f6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Lunar Projector Ability Data.asset b/Assets/Common/Scriptables/Abilities/Evolution/Lunar Projector Ability Data.asset new file mode 100644 index 0000000..9fd67a5 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Lunar Projector Ability Data.asset @@ -0,0 +1,36 @@ +%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: 10f85165c00ab52478088ba91528ee1f, type: 3} + m_Name: Lunar Projector Ability Data + m_EditorClassIdentifier: + type: 209 + title: Lunar Projector + description: Projects several orbiting light beams + icon: {fileID: 21300000, guid: 541dccf93836cd94e9c6898448aafb42, type: 3} + prefab: {fileID: 1516608455621187079, guid: ac96fd12e1451bf4ebdd339628978cce, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 1 + evolutionRequirements: + - abilityType: 9 + requiredAbilityLevel: 4 + shouldRemoveAfterEvolution: 1 + - abilityType: 106 + requiredAbilityLevel: 0 + shouldRemoveAfterEvolution: 0 + levels: + - projectileCount: 18 + projectileLifetime: 2.5 + abilityCooldown: 5 + initialRadius: 2.5 + angularSpeed: 200 + damage: 4 diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Lunar Projector Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Evolution/Lunar Projector Ability Data.asset.meta new file mode 100644 index 0000000..903a92d --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Lunar Projector Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 23bb3bcb8f644004fa03a63f6da83f20 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Mace Ball Ability Data.asset b/Assets/Common/Scriptables/Abilities/Evolution/Mace Ball Ability Data.asset new file mode 100644 index 0000000..7fd45b0 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Mace Ball Ability Data.asset @@ -0,0 +1,34 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4bbb4463f118f3d4bb9544bfbd915f0c, type: 3} + m_Name: Mace Ball Ability Data + m_EditorClassIdentifier: + type: 203 + title: Mace Ball + description: Cute spiky friend + icon: {fileID: 21300000, guid: afbccac59abb33247bb68223c8626582, type: 3} + prefab: {fileID: 3128169338053202466, guid: e9c46b08cd0ab8d42822b40310707f9b, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 1 + evolutionRequirements: + - abilityType: 3 + requiredAbilityLevel: 4 + shouldRemoveAfterEvolution: 1 + - abilityType: 102 + requiredAbilityLevel: 0 + shouldRemoveAfterEvolution: 0 + levels: + - speed: 2 + angularSpeed: 270 + damage: 50 + size: 1.25 diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Mace Ball Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Evolution/Mace Ball Ability Data.asset.meta new file mode 100644 index 0000000..2025b59 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Mace Ball Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 834df31f9b7b4d94cbc14473515c5a20 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Meteor Ability Data.asset b/Assets/Common/Scriptables/Abilities/Evolution/Meteor Ability Data.asset new file mode 100644 index 0000000..586f6be --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Meteor Ability Data.asset @@ -0,0 +1,35 @@ +%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: 7ef84cc4bbaf71b47bb750531b36ab2f, type: 3} + m_Name: Meteor Ability Data + m_EditorClassIdentifier: + type: 206 + title: Meteor + description: Launches a meteor shower from above + icon: {fileID: 21300000, guid: 96133003953070b4abc7f3ae2a6e4cdb, type: 3} + prefab: {fileID: 8666185439850298685, guid: aeefd65d7a29fed4a96e4f711db3fc7b, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 1 + evolutionRequirements: + - abilityType: 6 + requiredAbilityLevel: 4 + shouldRemoveAfterEvolution: 1 + - abilityType: 109 + requiredAbilityLevel: 0 + shouldRemoveAfterEvolution: 0 + levels: + - projectilesCount: 4 + timeBetweenProjectiles: 0.5 + abilityCooldown: 6 + damage: 30 + explosionRadius: 1.5 diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Meteor Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Evolution/Meteor Ability Data.asset.meta new file mode 100644 index 0000000..18357e0 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Meteor Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8be61207359b9414ca0b29385b10fdc4 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Recoiler Ability Data.asset b/Assets/Common/Scriptables/Abilities/Evolution/Recoiler Ability Data.asset new file mode 100644 index 0000000..fae7e4f --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Recoiler Ability Data.asset @@ -0,0 +1,36 @@ +%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: 6b45cb7027aba0e42a578f2da7fde9b6, type: 3} + m_Name: Recoiler Ability Data + m_EditorClassIdentifier: + type: 207 + title: Recoiler + description: Throws an upgraded swift boomerang + icon: {fileID: 21300000, guid: 94d5132492f5d6a43899713c4cf1e666, type: 3} + prefab: {fileID: 2769290797171051951, guid: dcb08d2e8637f2b4988c1c7a8c18c9ca, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 1 + evolutionRequirements: + - abilityType: 7 + requiredAbilityLevel: 4 + shouldRemoveAfterEvolution: 1 + - abilityType: 100 + requiredAbilityLevel: 0 + shouldRemoveAfterEvolution: 0 + levels: + - projectileLifetime: 4 + abilityCooldown: 5 + projectileTravelDistance: 4 + angularSpeed: -300 + damage: 30 + projectileSize: 1.2 diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Recoiler Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Evolution/Recoiler Ability Data.asset.meta new file mode 100644 index 0000000..57f4201 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Recoiler Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6cf8b3a62989f6845a032fb2d91e67ac +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Sacred Blade Data.asset b/Assets/Common/Scriptables/Abilities/Evolution/Sacred Blade Data.asset new file mode 100644 index 0000000..547c75e --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Sacred Blade Data.asset @@ -0,0 +1,36 @@ +%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: 22d1e1571be5cc64f8e081e56acef858, type: 3} + m_Name: Sacred Blade Data + m_EditorClassIdentifier: + type: 1101 + title: Sacred Blade + description: Slashes enemies with a golden wave of terror + icon: {fileID: 21300000, guid: 02c0d6f7c0ea188409e71d7d27d28349, type: 3} + prefab: {fileID: 5349004258488764192, guid: d540abc1bc5b9654b8c75bfb2ecc2210, type: 3} + isActiveAbility: 1 + isWeaponAbility: 1 + isEvolution: 1 + evolutionRequirements: + - abilityType: 1001 + requiredAbilityLevel: 4 + shouldRemoveAfterEvolution: 1 + - abilityType: 111 + requiredAbilityLevel: 0 + shouldRemoveAfterEvolution: 0 + levels: + - abilityCooldown: 2 + slashesCount: 5 + damage: 30 + waveDamage: 5 + slashSize: 1.4 + timeBetweenSlashes: 0.2 diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Sacred Blade Data.asset.meta b/Assets/Common/Scriptables/Abilities/Evolution/Sacred Blade Data.asset.meta new file mode 100644 index 0000000..a644d85 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Sacred Blade Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b20706c7fd909aa4a98f7556c43be9c8 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Scepter Data.asset b/Assets/Common/Scriptables/Abilities/Evolution/Scepter Data.asset new file mode 100644 index 0000000..340e40e --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Scepter Data.asset @@ -0,0 +1,35 @@ +%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: b3a5414a78c464949a585f13729ee1f0, type: 3} + m_Name: Scepter Data + m_EditorClassIdentifier: + type: 1100 + title: Ancient Scepter + description: Launches a powerful barrage of projectiles + icon: {fileID: 21300000, guid: 93e9dd16346d3b449977187799b746e6, type: 3} + prefab: {fileID: 2827894307271079447, guid: 9dca4a3aab571e34985d1cc530a9387b, type: 3} + isActiveAbility: 1 + isWeaponAbility: 1 + isEvolution: 1 + evolutionRequirements: + - abilityType: 1000 + requiredAbilityLevel: 4 + shouldRemoveAfterEvolution: 1 + - abilityType: 104 + requiredAbilityLevel: 0 + shouldRemoveAfterEvolution: 0 + levels: + - abilityCooldown: 0.2 + projectileSpeed: 10 + damage: 15 + projectileSize: 1 + projectileLifetime: 5 diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Scepter Data.asset.meta b/Assets/Common/Scriptables/Abilities/Evolution/Scepter Data.asset.meta new file mode 100644 index 0000000..c5b3d1e --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Scepter Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bc68c616d5b0c8a43b746f4bd1d6d5e1 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Silver Stakes Data.asset b/Assets/Common/Scriptables/Abilities/Evolution/Silver Stakes Data.asset new file mode 100644 index 0000000..2e23c4b --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Silver Stakes Data.asset @@ -0,0 +1,34 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a3f0c3b47c29b524683086d39bed3a7d, type: 3} + m_Name: Silver Stakes Data + m_EditorClassIdentifier: + type: 204 + title: Silver Stakes + description: Throws several sharp piercing stakes + icon: {fileID: 21300000, guid: 2185583ed30e543468b82c69c813548f, type: 3} + prefab: {fileID: 5201831521697468584, guid: 1068f86203714a44b8b4576239130948, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 1 + evolutionRequirements: + - abilityType: 4 + requiredAbilityLevel: 4 + shouldRemoveAfterEvolution: 1 + - abilityType: 107 + requiredAbilityLevel: 0 + shouldRemoveAfterEvolution: 0 + levels: + - projectileSpeed: 12 + damage: 30 + projectileSize: 0.75 + projectilesCount: 5 diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Silver Stakes Data.asset.meta b/Assets/Common/Scriptables/Abilities/Evolution/Silver Stakes Data.asset.meta new file mode 100644 index 0000000..08d44b1 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Silver Stakes Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 32ad250b89ed5bc43916d37d311f9169 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Spiky Trap Ability Data.asset b/Assets/Common/Scriptables/Abilities/Evolution/Spiky Trap Ability Data.asset new file mode 100644 index 0000000..be0ca6f --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Spiky Trap Ability Data.asset @@ -0,0 +1,40 @@ +%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: dd2ff9c5e3dc05c43a421319f81de6d2, type: 3} + m_Name: Spiky Trap Ability Data + m_EditorClassIdentifier: + type: 205 + title: Spiky Trap + description: Draws an explosive rune with spikes + icon: {fileID: 21300000, guid: 8cc8ee46f71f2854b998534652d2b27b, type: 3} + prefab: {fileID: 6787047396129160972, guid: 07a978f1fd9649748bee8c864bf04d4d, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 1 + evolutionRequirements: + - abilityType: 5 + requiredAbilityLevel: 4 + shouldRemoveAfterEvolution: 1 + - abilityType: 108 + requiredAbilityLevel: 0 + shouldRemoveAfterEvolution: 0 + levels: + - minesCount: 4 + spikesCount: 10 + abilityCooldown: 6 + mineSpawnRadius: 3 + mineLifetime: 10 + damage: 50 + spikeDamage: 10 + mineSize: 2 + mineTriggerRadius: 0.6 + mineDamageRadius: 2 diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Spiky Trap Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Evolution/Spiky Trap Ability Data.asset.meta new file mode 100644 index 0000000..250e7a1 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Spiky Trap Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8f88486c784281d4c928ddb0096ec25c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Thunder Ring Ability Data.asset b/Assets/Common/Scriptables/Abilities/Evolution/Thunder Ring Ability Data.asset new file mode 100644 index 0000000..238e45e --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Thunder Ring Ability Data.asset @@ -0,0 +1,36 @@ +%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: dea7316e62ac85f4a8da77488f201efb, type: 3} + m_Name: Thunder Ring Ability Data + m_EditorClassIdentifier: + type: 202 + title: Thunder Ring + description: Strikes from above with devastating ball lighning projectiles + icon: {fileID: 21300000, guid: 446ab47c09d6ec245bfd467a6de26e52, type: 3} + prefab: {fileID: 924860060412471070, guid: 43f0ac2cddc68e54a94d3713d3a8dcf5, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 1 + evolutionRequirements: + - abilityType: 2 + requiredAbilityLevel: 4 + shouldRemoveAfterEvolution: 1 + - abilityType: 103 + requiredAbilityLevel: 0 + shouldRemoveAfterEvolution: 0 + levels: + - damage: 50 + ballDamage: 10 + lightningsCount: 6 + ballLightningCount: 6 + abilityCooldown: 4 + durationBetweenHits: 0.25 diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Thunder Ring Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Evolution/Thunder Ring Ability Data.asset.meta new file mode 100644 index 0000000..0a88458 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Thunder Ring Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 17544eb3b9ef7b4488338169d6ba2435 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Time Gazer Ability Data.asset b/Assets/Common/Scriptables/Abilities/Evolution/Time Gazer Ability Data.asset new file mode 100644 index 0000000..7697ece --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Time Gazer Ability Data.asset @@ -0,0 +1,34 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 991052d635f55094a817218699c72c87, type: 3} + m_Name: Time Gazer Ability Data + m_EditorClassIdentifier: + type: 201 + title: Time Gazer + description: Slows enemies around, dealing additional damage + icon: {fileID: 21300000, guid: 0e8ebf204dcfe9949a467596fabdc98a, type: 3} + prefab: {fileID: 6046089768498997805, guid: 473f90e1159fc6b409da8240069f7934, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 1 + evolutionRequirements: + - abilityType: 1 + requiredAbilityLevel: 4 + shouldRemoveAfterEvolution: 1 + - abilityType: 105 + requiredAbilityLevel: 0 + shouldRemoveAfterEvolution: 0 + levels: + - fieldRadius: 1.75 + slowDownMultiplier: 0.5 + damage: 15 + damageCooldown: 1 diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Time Gazer Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Evolution/Time Gazer Ability Data.asset.meta new file mode 100644 index 0000000..8fe7612 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Time Gazer Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 31908ed3d6273e240adbe04400b5ce8e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Twin Daggers Ability Data.asset b/Assets/Common/Scriptables/Abilities/Evolution/Twin Daggers Ability Data.asset new file mode 100644 index 0000000..10b55d5 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Twin Daggers Ability Data.asset @@ -0,0 +1,33 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1159afb2b20d9cf4381fdee01a422901, type: 3} + m_Name: Twin Daggers Ability Data + m_EditorClassIdentifier: + type: 208 + title: Twin Daggers + description: Whats better than one? Two, of course + icon: {fileID: 21300000, guid: 79c2e3db778351a4884e6c2605de53cb, type: 3} + prefab: {fileID: 482132489447778548, guid: affb1c21d7e652040afe995b59f5b42e, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 1 + evolutionRequirements: + - abilityType: 8 + requiredAbilityLevel: 4 + shouldRemoveAfterEvolution: 1 + - abilityType: 101 + requiredAbilityLevel: 0 + shouldRemoveAfterEvolution: 0 + levels: + - projectileCount: 10 + abilityCooldown: 5 + damage: 25 diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Twin Daggers Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Evolution/Twin Daggers Ability Data.asset.meta new file mode 100644 index 0000000..3388039 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Twin Daggers Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e5aef831ee372c54b8b45fc5c6c3fa3b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Void Star Ability Data.asset b/Assets/Common/Scriptables/Abilities/Evolution/Void Star Ability Data.asset new file mode 100644 index 0000000..6de8c0d --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Void Star Ability Data.asset @@ -0,0 +1,34 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9ad898821363a1e4bb8b98ccf9592d63, type: 3} + m_Name: Void Star Ability Data + m_EditorClassIdentifier: + type: 200 + title: Void Star + description: Endlessly orbits around, dealing increased damage + icon: {fileID: 21300000, guid: 994260112a138d7429ef45abb62a600a, type: 3} + prefab: {fileID: 8699148400794714863, guid: 217852fdde3768b44aa28fa5977785dc, type: 3} + isActiveAbility: 1 + isWeaponAbility: 0 + isEvolution: 1 + evolutionRequirements: + - abilityType: 0 + requiredAbilityLevel: 4 + shouldRemoveAfterEvolution: 1 + - abilityType: 110 + requiredAbilityLevel: 0 + shouldRemoveAfterEvolution: 0 + levels: + - damage: 35 + projectilesCount: 6 + radius: 1.5 + angularSpeed: -300 diff --git a/Assets/Common/Scriptables/Abilities/Evolution/Void Star Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Evolution/Void Star Ability Data.asset.meta new file mode 100644 index 0000000..db894d3 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Evolution/Void Star Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7f98fa6689940d54e820a5c62dc94643 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities.meta b/Assets/Common/Scriptables/Abilities/Passive Abilities.meta new file mode 100644 index 0000000..917581c --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e9b4ecf8b0e36e742bb4e2f02aa68cf1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Cooldown Ability Data.asset b/Assets/Common/Scriptables/Abilities/Passive Abilities/Cooldown Ability Data.asset new file mode 100644 index 0000000..ba35346 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Cooldown Ability Data.asset @@ -0,0 +1,29 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4993d821a20ea2e45a1f02d5edff9cd4, type: 3} + m_Name: Cooldown Ability Data + m_EditorClassIdentifier: + type: 105 + title: Hourglass + description: Reduces ability cooldowns + icon: {fileID: 21300000, guid: 0d8a147d40baeee40b67492d75694437, type: 3} + prefab: {fileID: 6529486900185581019, guid: 8515069691b5ce04ab0103bcd493c550, type: 3} + isActiveAbility: 0 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - cooldownMultiplier: 0.92 + - cooldownMultiplier: 0.84 + - cooldownMultiplier: 0.76 + - cooldownMultiplier: 0.68 + - cooldownMultiplier: 0.6 diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Cooldown Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Passive Abilities/Cooldown Ability Data.asset.meta new file mode 100644 index 0000000..7e6049f --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Cooldown Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 68bf2ddb340e23e42ba85d719a8d00cc +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Damage Ability Data.asset b/Assets/Common/Scriptables/Abilities/Passive Abilities/Damage Ability Data.asset new file mode 100644 index 0000000..aeccf4e --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Damage Ability Data.asset @@ -0,0 +1,29 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 27811a4e1e5345c49af3035cf61ce11a, type: 3} + m_Name: Damage Ability Data + m_EditorClassIdentifier: + type: 102 + title: Power Gauntlet + description: Increases overall damage + icon: {fileID: 21300000, guid: c26cc51a8aa4c13408c720657c599338, type: 3} + prefab: {fileID: 2334075227648824738, guid: ead69ec3e02cc2e449a67317299703df, type: 3} + isActiveAbility: 0 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - damageMultiplier: 1.1 + - damageMultiplier: 1.2 + - damageMultiplier: 1.3 + - damageMultiplier: 1.4 + - damageMultiplier: 1.5 diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Damage Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Passive Abilities/Damage Ability Data.asset.meta new file mode 100644 index 0000000..2ee65b1 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Damage Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e2e912d0319d0294d970714e454973f4 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Damage Reduction Ability Data.asset b/Assets/Common/Scriptables/Abilities/Passive Abilities/Damage Reduction Ability Data.asset new file mode 100644 index 0000000..1c6230b --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Damage Reduction Ability Data.asset @@ -0,0 +1,29 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 80567d708e2a27c42b25f3bc909504ed, type: 3} + m_Name: Damage Reduction Ability Data + m_EditorClassIdentifier: + type: 107 + title: Titan Shield + description: Reduces incoming damage + icon: {fileID: 21300000, guid: 64917bb6cfcc63a4495308648c35a137, type: 3} + prefab: {fileID: 9093015508192957762, guid: 14873e52654f8d74cb06443e5f7a6a5e, type: 3} + isActiveAbility: 0 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - damageReductionPercent: 10 + - damageReductionPercent: 20 + - damageReductionPercent: 30 + - damageReductionPercent: 40 + - damageReductionPercent: 50 diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Damage Reduction Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Passive Abilities/Damage Reduction Ability Data.asset.meta new file mode 100644 index 0000000..b674539 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Damage Reduction Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a275a7d5150ef554e9c5a3bd803a1b06 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Duration Ability Data.asset b/Assets/Common/Scriptables/Abilities/Passive Abilities/Duration Ability Data.asset new file mode 100644 index 0000000..38ed901 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Duration Ability Data.asset @@ -0,0 +1,29 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ddcefea9e6c1a38469cce16fcdd79c04, type: 3} + m_Name: Duration Ability Data + m_EditorClassIdentifier: + type: 110 + title: Space Orb + description: Increases duration of active abilities + icon: {fileID: 21300000, guid: b3ada9c4069470e4f93e0582cd68958b, type: 3} + prefab: {fileID: 5914348009851691356, guid: dda15d7e41b15c94e9bff3cf62765105, type: 3} + isActiveAbility: 0 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - durationMultiplier: 1.1 + - durationMultiplier: 1.2 + - durationMultiplier: 1.3 + - durationMultiplier: 1.4 + - durationMultiplier: 1.5 diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Duration Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Passive Abilities/Duration Ability Data.asset.meta new file mode 100644 index 0000000..43140a3 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Duration Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3da9b537208fdea4aafe4336fb9fc095 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Gold Ability Data.asset b/Assets/Common/Scriptables/Abilities/Passive Abilities/Gold Ability Data.asset new file mode 100644 index 0000000..db70e3c --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Gold Ability Data.asset @@ -0,0 +1,30 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2e293eb14a87432429512420c3c8ac6a, type: 3} + m_Name: Gold Ability Data + m_EditorClassIdentifier: + type: 111 + title: Golden Chalice + description: Increases incoming gold + icon: {fileID: 21300000, guid: b4e7b46556a43e446a743d70e4e2d178, type: 3} + prefab: {fileID: 122745898579924258, guid: 04f1283494bebfe479049653dcf5d87a, type: 3} + isActiveAbility: 0 + isWeaponAbility: 0 + isEndgameAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - goldMultiplier: 1.1 + - goldMultiplier: 1.2 + - goldMultiplier: 1.3 + - goldMultiplier: 1.4 + - goldMultiplier: 1.5 diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Gold Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Passive Abilities/Gold Ability Data.asset.meta new file mode 100644 index 0000000..2eb87ff --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Gold Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d444d795f98c5d645b82592f227bf2e7 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Gold Endgame Ability Data.asset b/Assets/Common/Scriptables/Abilities/Passive Abilities/Gold Endgame Ability Data.asset new file mode 100644 index 0000000..da08adc --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Gold Endgame Ability Data.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: 61300d54e4355ed4cae8799f8c4d9c26, type: 3} + m_Name: Gold Endgame Ability Data + m_EditorClassIdentifier: + type: 2002 + title: Gold + description: Have some gold! + icon: {fileID: 21300000, guid: c12e57be36f9dc244a7fbd2a51657677, type: 3} + prefab: {fileID: 7203766295210942642, guid: c66b22e19152c8e4898c7b1f00e36357, type: 3} + isActiveAbility: 0 + isWeaponAbility: 0 + isEndgameAbility: 1 + isEvolution: 0 + evolutionRequirements: [] + levels: + - goldAmount: 40 diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Gold Endgame Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Passive Abilities/Gold Endgame Ability Data.asset.meta new file mode 100644 index 0000000..07b6d2f --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Gold Endgame Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 02f5acbbbf0052c43a72e6e0a0faecb3 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Heal Endgame Ability Data.asset b/Assets/Common/Scriptables/Abilities/Passive Abilities/Heal Endgame Ability Data.asset new file mode 100644 index 0000000..5086491 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Heal Endgame Ability Data.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: 0d4428a2a0945e7429675f5c6a7cf695, type: 3} + m_Name: Heal Endgame Ability Data + m_EditorClassIdentifier: + type: 2001 + title: Heal + description: Restore some of your health + icon: {fileID: 21300000, guid: 28c3cbc02ecf99d45b8092c5628bf0bf, type: 3} + prefab: {fileID: 7203766295210942642, guid: b9a895d952c9ba442a54bbfbb727a482, type: 3} + isActiveAbility: 0 + isWeaponAbility: 0 + isEndgameAbility: 1 + isEvolution: 0 + evolutionRequirements: [] + levels: + - healPersentage: 40 diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Heal Endgame Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Passive Abilities/Heal Endgame Ability Data.asset.meta new file mode 100644 index 0000000..d4d4053 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Heal Endgame Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 932cd3900cec3574493ce2137e745ac8 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Magnet Ability Data.asset b/Assets/Common/Scriptables/Abilities/Passive Abilities/Magnet Ability Data.asset new file mode 100644 index 0000000..8c71014 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Magnet Ability Data.asset @@ -0,0 +1,29 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 69a603a3e05b0a14e81aad0ae1e51e6a, type: 3} + m_Name: Magnet Ability Data + m_EditorClassIdentifier: + type: 100 + title: Magnet + description: Draws gems from further away + icon: {fileID: 21300000, guid: 10a34bcdcaa3ea04991549779670e23e, type: 3} + prefab: {fileID: 7251880435604865545, guid: f009c8b4f624b304abe17863117b97de, type: 3} + isActiveAbility: 0 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - radiusMultiplier: 2 + - radiusMultiplier: 3 + - radiusMultiplier: 4 + - radiusMultiplier: 5 + - radiusMultiplier: 6 diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Magnet Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Passive Abilities/Magnet Ability Data.asset.meta new file mode 100644 index 0000000..0dade98 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Magnet Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 29fecd0e6b7486c4f8159cf20a4ce053 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Max HP Ability Data.asset b/Assets/Common/Scriptables/Abilities/Passive Abilities/Max HP Ability Data.asset new file mode 100644 index 0000000..f668429 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Max HP Ability Data.asset @@ -0,0 +1,29 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 836da791dfdd51a43b63a8106936ab66, type: 3} + m_Name: Max HP Ability Data + m_EditorClassIdentifier: + type: 103 + title: Heart Charm + description: Increases maximum HP + icon: {fileID: 21300000, guid: dcba4ec680d52404a854f60f363ec036, type: 3} + prefab: {fileID: 5795888989804479914, guid: 2f1a6ab57a918ed498acc33a711c2c27, type: 3} + isActiveAbility: 0 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - maxHPMultiplier: 1.2 + - maxHPMultiplier: 1.4 + - maxHPMultiplier: 1.6 + - maxHPMultiplier: 1.8 + - maxHPMultiplier: 2 diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Max HP Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Passive Abilities/Max HP Ability Data.asset.meta new file mode 100644 index 0000000..cefdf52 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Max HP Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4e3ec23ddf3546540a91ee20406d5e23 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Move Speed Ability Data.asset b/Assets/Common/Scriptables/Abilities/Passive Abilities/Move Speed Ability Data.asset new file mode 100644 index 0000000..d8de57a --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Move Speed Ability Data.asset @@ -0,0 +1,29 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a76f2259899b0db46a67c9cea309929d, type: 3} + m_Name: Move Speed Ability Data + m_EditorClassIdentifier: + type: 101 + title: Wings + description: Increases move speed + icon: {fileID: 21300000, guid: 0c964e5ab41c81b4cab78731d89649b6, type: 3} + prefab: {fileID: 3978403754796854433, guid: d12261c054d3d8b4eb9c812d48a838d0, type: 3} + isActiveAbility: 0 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - speedMultiplier: 1.1 + - speedMultiplier: 1.2 + - speedMultiplier: 1.3 + - speedMultiplier: 1.4 + - speedMultiplier: 1.5 diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Move Speed Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Passive Abilities/Move Speed Ability Data.asset.meta new file mode 100644 index 0000000..976deba --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Move Speed Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b78ac4f102c39054ca6d376c82b818c0 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Projectile Speed Ability Data.asset b/Assets/Common/Scriptables/Abilities/Passive Abilities/Projectile Speed Ability Data.asset new file mode 100644 index 0000000..77858d4 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Projectile Speed Ability Data.asset @@ -0,0 +1,29 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e7071a3204d49c545801f25ffb445d84, type: 3} + m_Name: Projectile Speed Ability Data + m_EditorClassIdentifier: + type: 108 + title: Wind Fan + description: Increases projectile speed + icon: {fileID: 21300000, guid: e26748d24d9d3704680e4675d0140c19, type: 3} + prefab: {fileID: 7816908637222287925, guid: c8481d262ca76214ebe5bd7a6d538b28, type: 3} + isActiveAbility: 0 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - projectileSpeedMultiplier: 1.1 + - projectileSpeedMultiplier: 1.2 + - projectileSpeedMultiplier: 1.3 + - projectileSpeedMultiplier: 1.4 + - projectileSpeedMultiplier: 1.5 diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Projectile Speed Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Passive Abilities/Projectile Speed Ability Data.asset.meta new file mode 100644 index 0000000..e686288 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Projectile Speed Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 73cc0fc0393904447b2f03c569a66560 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Restore HP Ability Data.asset b/Assets/Common/Scriptables/Abilities/Passive Abilities/Restore HP Ability Data.asset new file mode 100644 index 0000000..adda89b --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Restore HP Ability Data.asset @@ -0,0 +1,34 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d9fe18c54c4716e48be4d22e29ffe7a0, type: 3} + m_Name: Restore HP Ability Data + m_EditorClassIdentifier: + type: 106 + title: Vitality Potion + description: Restores HP over time + icon: {fileID: 21300000, guid: 74bd4eda37a1586489c2e5ffb2986fa6, type: 3} + prefab: {fileID: 1574058401009310863, guid: 141088cc56070244d84dccf079efb43d, type: 3} + isActiveAbility: 0 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - restoredHPPercent: 1 + cooldown: 5 + - restoredHPPercent: 2 + cooldown: 5 + - restoredHPPercent: 3 + cooldown: 5 + - restoredHPPercent: 4 + cooldown: 5 + - restoredHPPercent: 5 + cooldown: 5 diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Restore HP Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Passive Abilities/Restore HP Ability Data.asset.meta new file mode 100644 index 0000000..4289989 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Restore HP Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 206aa8a212976cf4dab94c9a90ea7669 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Size Ability Data.asset b/Assets/Common/Scriptables/Abilities/Passive Abilities/Size Ability Data.asset new file mode 100644 index 0000000..64f7aed --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Size Ability Data.asset @@ -0,0 +1,29 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 42eac6d655d395e42bd4c18409d47a17, type: 3} + m_Name: Size Ability Data + m_EditorClassIdentifier: + type: 109 + title: Grow Bean + description: Increases size of abilities + icon: {fileID: 21300000, guid: f8cf4cf051469dd4890f673607a63503, type: 3} + prefab: {fileID: 2691010005890854320, guid: 3f094f4ad417f0140b8f7d116b0e58de, type: 3} + isActiveAbility: 0 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - sizeMultiplier: 1.1 + - sizeMultiplier: 1.2 + - sizeMultiplier: 1.3 + - sizeMultiplier: 1.4 + - sizeMultiplier: 1.5 diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/Size Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Passive Abilities/Size Ability Data.asset.meta new file mode 100644 index 0000000..cbf0212 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/Size Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: df2f06ecdaeed194784b46508baa8bf4 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/XP Ability Data.asset b/Assets/Common/Scriptables/Abilities/Passive Abilities/XP Ability Data.asset new file mode 100644 index 0000000..c98cc9d --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/XP Ability Data.asset @@ -0,0 +1,29 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f352f4c5114321b47afd027220a77c40, type: 3} + m_Name: XP Ability Data + m_EditorClassIdentifier: + type: 104 + title: Book Of Wisdom + description: Grants more XP + icon: {fileID: 21300000, guid: d8c332b5450ad8443bc54b77e73548d3, type: 3} + prefab: {fileID: 7001007762752852440, guid: b3b57b2d5c9bf354fa2d159bde15c25c, type: 3} + isActiveAbility: 0 + isWeaponAbility: 0 + isEvolution: 0 + evolutionRequirements: [] + levels: + - xpMultiplier: 1.1 + - xpMultiplier: 1.2 + - xpMultiplier: 1.3 + - xpMultiplier: 1.4 + - xpMultiplier: 1.5 diff --git a/Assets/Common/Scriptables/Abilities/Passive Abilities/XP Ability Data.asset.meta b/Assets/Common/Scriptables/Abilities/Passive Abilities/XP Ability Data.asset.meta new file mode 100644 index 0000000..de3a0b8 --- /dev/null +++ b/Assets/Common/Scriptables/Abilities/Passive Abilities/XP Ability Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 303b35ed2fe1775489371e462afeba90 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Audio Database.asset b/Assets/Common/Scriptables/Audio Database.asset new file mode 100644 index 0000000..26f46bf --- /dev/null +++ b/Assets/Common/Scriptables/Audio Database.asset @@ -0,0 +1,298 @@ +%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: 95531853c36d2984a9a689e5bba6f689, type: 3} + m_Name: Audio Database + m_EditorClassIdentifier: + sounds: + - name: Button Click + cooldown: 0 + audioClip: + audioClip: {fileID: 8300000, guid: 409959954a076534893c9b15fbc1cf3e, type: 3} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Chest Ability Popup + cooldown: 0 + audioClip: + audioClip: {fileID: 8300000, guid: 8cf2e4429702f7b47b92994cacc7ad94, type: 3} + volume: {x: 0.3, y: 0.3} + pitch: {x: 1, y: 1} + - name: Chest Window Popup + cooldown: 0 + audioClip: + audioClip: {fileID: 8300000, guid: 3ecc253b71770624397271cbb644656e, type: 3} + volume: {x: 0.4, y: 0.4} + pitch: {x: 1, y: 1} + - name: Chest In Progress + cooldown: 0 + audioClip: + audioClip: {fileID: 8300000, guid: d9e87b657521ce543b43a6a478573d05, type: 3} + volume: {x: 0.4, y: 0.4} + pitch: {x: 1, y: 1} + - name: Stage Complete + cooldown: 0 + audioClip: + audioClip: {fileID: 8300000, guid: 07413473d6486354eb213f8acef381f6, type: 3} + volume: {x: 0.5, y: 0.5} + pitch: {x: 1, y: 1} + - name: Coin Pick Up + cooldown: 0 + audioClip: + audioClip: {fileID: 8300000, guid: 113f8d23b2ade2944a050d7321b6da13, type: 3} + volume: {x: 0.15, y: 0.15} + pitch: {x: 1, y: 1} + - name: Chest Pick Up + cooldown: 0 + audioClip: + audioClip: {fileID: 8300000, guid: 113f8d23b2ade2944a050d7321b6da13, type: 3} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Gem Pick Up + cooldown: 0.08 + audioClip: + audioClip: {fileID: 8300000, guid: e54f26a9a7a846a4aa9dea88e2a7311d, type: 3} + volume: {x: 0.05, y: 0.1} + pitch: {x: 1.6, y: 1.6} + - name: Heal Pick Up + cooldown: 0 + audioClip: + audioClip: {fileID: 8300000, guid: 8d2cf402deb4bfd4a9ea3335b860b9c5, type: 3} + volume: {x: 0.25, y: 0.25} + pitch: {x: 1, y: 1} + - name: Bomb Pick Up + cooldown: 0 + audioClip: + audioClip: {fileID: 8300000, guid: 13501cab7503f004b8dbb78f5cd24e43, type: 3} + volume: {x: 0.2, y: 0.3} + pitch: {x: 1, y: 1} + - name: Magnet Pick Up + cooldown: 0 + audioClip: + audioClip: {fileID: 8300000, guid: a2ab213b5a95bb944a8db94bab5b927d, type: 3} + volume: {x: 0.05, y: 0.15} + pitch: {x: 1, y: 1} + - name: Level Up + cooldown: 0 + audioClip: + audioClip: {fileID: 8300000, guid: 6b10aaf61edcb7242a370eff1b7c32a8, type: 3} + volume: {x: 0.25, y: 0.25} + pitch: {x: 1, y: 1} + - name: Hit + cooldown: 0.05 + audioClip: + audioClip: {fileID: 8300000, guid: d6b6886efec7c5443ae9451a515fb34b, type: 3} + volume: {x: 0.06, y: 0.085} + pitch: {x: 1.3, y: 1.6} + - name: Death + cooldown: 0 + audioClip: + audioClip: {fileID: 8300000, guid: 4dbd0ef392363ae438e2ed005fa048c0, type: 3} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Revive + cooldown: 0 + audioClip: + audioClip: {fileID: 8300000, guid: d569f57fc99c2bb48b2e52d84466d24d, type: 3} + volume: {x: 0.5, y: 0.5} + pitch: {x: 1, y: 1} + - name: Receiving Damage + cooldown: 0 + audioClip: + audioClip: {fileID: 8300000, guid: 57c2650ccfbbcc547b99c9315654ed44, type: 3} + volume: {x: 1, y: 1} + pitch: {x: 0.9, y: 1.1} + - name: Boomerang Throw + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Fireball Launch + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Fireball Explosion + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Flying Dagger Launch + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Guardian Eye + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Ice Shard Launch + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Lightning Amulet + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Magic Rune Setup + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Magic Rune Explosion + cooldown: 0.1 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Rolling Stone Launch + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Shooting Stars Launch + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Solar Magnifier Launch + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Steel Sword Attack + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Wand Projectile Launch + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Eclipse Ray Launch + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Mace Ball Launch + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Meteor Launch + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Meteor Impact + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Recoiler Launch + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Sacred Blade Attack + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Septer Projectile Launch + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Silver Stakes Launch + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Spiky Trap Set Up + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Spiky Trap Explosion + cooldown: 0.1 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Thunder Ring Strike + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Time Gazer + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Twin Daggers Launch + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Void Stars Launch + cooldown: 0 + audioClip: + audioClip: {fileID: 0} + volume: {x: 1, y: 1} + pitch: {x: 1, y: 1} + - name: Main Menu Music + cooldown: 0 + audioClip: + audioClip: {fileID: 8300000, guid: 629b67973afe85640b8c153ae1502f6c, type: 3} + volume: {x: 0.07, y: 0.07} + pitch: {x: 0.9, y: 0.9} + - name: Stage Music + cooldown: 0 + audioClip: + audioClip: {fileID: 8300000, guid: 629b67973afe85640b8c153ae1502f6c, type: 3} + volume: {x: 0.07, y: 0.07} + pitch: {x: 1, y: 1} + music: + name: Music + cooldown: 0 + audioClip: + audioClip: {fileID: 8300000, guid: 629b67973afe85640b8c153ae1502f6c, type: 3} + volume: {x: 0.07, y: 0.07} + pitch: {x: 0.9, y: 0.9} diff --git a/Assets/Common/Scriptables/Audio Database.asset.meta b/Assets/Common/Scriptables/Audio Database.asset.meta new file mode 100644 index 0000000..e3b41f9 --- /dev/null +++ b/Assets/Common/Scriptables/Audio Database.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c70a0a8a3f7be62468eda4dcd0607c9a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Bossfight Database.asset b/Assets/Common/Scriptables/Bossfight Database.asset new file mode 100644 index 0000000..4bbd086 --- /dev/null +++ b/Assets/Common/Scriptables/Bossfight Database.asset @@ -0,0 +1,51 @@ +%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: 8c56553a9f6e0f8439953e4008fa4833, type: 3} + m_Name: Bossfight Database + m_EditorClassIdentifier: + bossfights: + - bossType: 1 + displayName: MEGA SLIME + bossPrefab: {fileID: 5964416160108566549, guid: 39801caeba5fd7e4d815ca03728f482d, + type: 3} + fencePrefab: {fileID: 6967435664897069084, guid: c098a263fcd5d3a489ab7f38017bfce2, + type: 3} + - bossType: 3 + displayName: MIGHTY CRAB + bossPrefab: {fileID: 2150824473416715463, guid: e061174aa69bee94b99b2e2a798e4b79, + type: 3} + fencePrefab: {fileID: 6967435664897069084, guid: e5ba9edff5749654e9f9254d146aa062, + type: 3} + - bossType: 2 + displayName: QUEEN WASP + bossPrefab: {fileID: 2150824473416715463, guid: 80a8889eeffae08468fb24937274c0e8, + type: 3} + fencePrefab: {fileID: 6967435664897069084, guid: c098a263fcd5d3a489ab7f38017bfce2, + type: 3} + - bossType: 0 + displayName: MYSTERIOUS MASK + bossPrefab: {fileID: 5964416160108566549, guid: e1fcb21549ee01547beadb30c24248e0, + type: 3} + fencePrefab: {fileID: 6967435664897069084, guid: 18939989e8dbf704b982bde9ea7e8873, + type: 3} + - bossType: 5 + displayName: FOR WHOM THE BELL TOLLS + bossPrefab: {fileID: 4574435750923931073, guid: b4adcec29d46a994ba0c95f194cb64e0, + type: 3} + fencePrefab: {fileID: 6967435664897069084, guid: 18939989e8dbf704b982bde9ea7e8873, + type: 3} + - bossType: 4 + displayName: THE VOID + bossPrefab: {fileID: 1090571174421192766, guid: 65fc20f9c4000714ab78a84619f6b8ef, + type: 3} + fencePrefab: {fileID: 6967435664897069084, guid: 5558991dbcad058409cdcf21cd73dea0, + type: 3} diff --git a/Assets/Common/Scriptables/Bossfight Database.asset.meta b/Assets/Common/Scriptables/Bossfight Database.asset.meta new file mode 100644 index 0000000..6c0e4f2 --- /dev/null +++ b/Assets/Common/Scriptables/Bossfight Database.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: af0db12f0f2b0e34992aebce178468a7 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Characters Database.asset b/Assets/Common/Scriptables/Characters Database.asset new file mode 100644 index 0000000..8c7f6bf --- /dev/null +++ b/Assets/Common/Scriptables/Characters Database.asset @@ -0,0 +1,33 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6347c4bf45db0cb4b9b95edb3aa5908e, type: 3} + m_Name: Characters Database + m_EditorClassIdentifier: + characters: + - name: WIZARD + cost: 0 + icon: {fileID: 21300000, guid: 755f8689cc0272545aff1e866ef340e2, type: 3} + prefab: {fileID: 7849156713834091280, guid: 6d9fb0a90d19c4b4e9e35d4b41e2b37a, + type: 3} + hasStartingAbility: 0 + startingAbility: 0 + baseHP: 100 + baseDamage: 1 + - name: MAGE + cost: 500 + icon: {fileID: 21300000, guid: f732c85210a311741abc947ab8af1424, type: 3} + prefab: {fileID: 2921880940271959218, guid: 54121bc69e709ef4aae3deb8291032d8, + type: 3} + hasStartingAbility: 0 + startingAbility: 0 + baseHP: 120 + baseDamage: 1.2 diff --git a/Assets/Common/Scriptables/Characters Database.asset.meta b/Assets/Common/Scriptables/Characters Database.asset.meta new file mode 100644 index 0000000..9e30c7f --- /dev/null +++ b/Assets/Common/Scriptables/Characters Database.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 94ea5f0fdccb79e4cbdd7bd522bc3dc2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Currencies Database.asset b/Assets/Common/Scriptables/Currencies Database.asset new file mode 100644 index 0000000..a5c50ea --- /dev/null +++ b/Assets/Common/Scriptables/Currencies Database.asset @@ -0,0 +1,21 @@ +%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: a23ba7731b9c73c4ca43dcb5842230ab, type: 3} + m_Name: Currencies Database + m_EditorClassIdentifier: + currencies: + - id: gold + name: Gold + icon: {fileID: 21300000, guid: 05f378ff9ca9db843a4a433d68edd596, type: 3} + - id: temp_gold + name: Gold + icon: {fileID: 21300000, guid: 05f378ff9ca9db843a4a433d68edd596, type: 3} diff --git a/Assets/Common/Scriptables/Currencies Database.asset.meta b/Assets/Common/Scriptables/Currencies Database.asset.meta new file mode 100644 index 0000000..e569c5a --- /dev/null +++ b/Assets/Common/Scriptables/Currencies Database.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d102319cc337fef4b880cc6a9e40ff34 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Drop Database.asset b/Assets/Common/Scriptables/Drop Database.asset new file mode 100644 index 0000000..ec8f5aa --- /dev/null +++ b/Assets/Common/Scriptables/Drop Database.asset @@ -0,0 +1,59 @@ +%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: c9243079d1d16af49907120c059b995c, type: 3} + m_Name: Drop Database + m_EditorClassIdentifier: + gems: + - dropType: 0 + prefab: {fileID: 9143106580007897129, guid: e2434e12c48aad342a597ad9d08a9fe0, + type: 3} + affectedByMagnet: 1 + dropCooldown: 0 + - dropType: 1 + prefab: {fileID: 3767841545309144952, guid: c13a6d6a7784ecd4f90a22c3ce2e5903, + type: 3} + affectedByMagnet: 1 + dropCooldown: 0 + - dropType: 2 + prefab: {fileID: 1494583194590317331, guid: ef3b7cf0f6a3ec04bb4e88a673250008, + type: 3} + affectedByMagnet: 1 + dropCooldown: 0 + - dropType: 3 + prefab: {fileID: 1537621102715106445, guid: f4d4d0d16e89884448fd6e144d12d08c, + type: 3} + affectedByMagnet: 1 + dropCooldown: 0 + - dropType: 10 + prefab: {fileID: 38311367728016649, guid: de47d81e6dffeec47828e2867df98072, type: 3} + affectedByMagnet: 0 + dropCooldown: 5 + - dropType: 20 + prefab: {fileID: 3492111080169054687, guid: 0fe00d4c6ad341648bd885d10959eb00, + type: 3} + affectedByMagnet: 0 + dropCooldown: 20 + - dropType: 30 + prefab: {fileID: 5357998141908448301, guid: 77f2b74f802e4a048b4767a694018f7a, + type: 3} + affectedByMagnet: 0 + dropCooldown: 5 + - dropType: 40 + prefab: {fileID: 7999236800876406289, guid: bf4bdd82d81c78940af86324ea6bc89b, + type: 3} + affectedByMagnet: 0 + dropCooldown: 0 + - dropType: 100 + prefab: {fileID: 5701827647628563461, guid: 4a35a7cb0cae03f48a99efa54d058854, + type: 3} + affectedByMagnet: 0 + dropCooldown: 0 diff --git a/Assets/Common/Scriptables/Drop Database.asset.meta b/Assets/Common/Scriptables/Drop Database.asset.meta new file mode 100644 index 0000000..fcb0c51 --- /dev/null +++ b/Assets/Common/Scriptables/Drop Database.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 520187ec023659d46b81d976ef01a6b9 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Enemies Database VAT.asset b/Assets/Common/Scriptables/Enemies Database VAT.asset new file mode 100644 index 0000000..3f777f8 --- /dev/null +++ b/Assets/Common/Scriptables/Enemies Database VAT.asset @@ -0,0 +1,337 @@ +%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: 9fb969dd50a438d45b9176e14626575f, type: 3} + m_Name: Enemies Database VAT + m_EditorClassIdentifier: + enemies: + - type: 1 + prefab: {fileID: 3444381737939946904, guid: f35239e4907fd4b42a475ea65a359c61, + type: 3} + icon: {fileID: 21300000, guid: c7314c840a31eb342ae17551898d7fe1, type: 3} + enemyDrop: + - dropType: 0 + chance: 80 + - dropType: 10 + chance: 0 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 8 + prefab: {fileID: 7750280133108084670, guid: 87b20c39f7fd3634fb12cd1e9b81d123, + type: 3} + icon: {fileID: 21300000, guid: 148058df3a6abb446b4e99942a200b65, type: 3} + enemyDrop: + - dropType: 0 + chance: 60 + - dropType: 10 + chance: 0 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 0 + prefab: {fileID: 2733527425287836553, guid: 962f82528ce41944d9974ff14c4bf6f0, + type: 3} + icon: {fileID: 21300000, guid: 128a46be89fd93a42bc096292ec61c82, type: 3} + enemyDrop: + - dropType: 0 + chance: 90 + - dropType: 1 + chance: 70 + - dropType: 2 + chance: 20 + - dropType: 10 + chance: 0 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 2 + prefab: {fileID: 7824642542108222306, guid: b982eeabb173b3c4e9fcae607d57f4a0, + type: 3} + icon: {fileID: 21300000, guid: 3086c2163f612aa4eab4a1cc537a2874, type: 3} + enemyDrop: + - dropType: 0 + chance: 90 + - dropType: 1 + chance: 70 + - dropType: 2 + chance: 35 + - dropType: 10 + chance: 1 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 4 + prefab: {fileID: 112901448213715318, guid: 2ddb8a82b3ab8de4b8f9006687046b14, type: 3} + icon: {fileID: 21300000, guid: c1add2dcde28f2a4a9eb8db6532bc6af, type: 3} + enemyDrop: + - dropType: 0 + chance: 50 + - dropType: 1 + chance: 90 + - dropType: 2 + chance: 70 + - dropType: 3 + chance: 10 + - dropType: 10 + chance: 1 + - dropType: 20 + chance: 1 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 3 + prefab: {fileID: 3389287499568484066, guid: d3b3f5a635700ee4aa69f4e38b77abda, + type: 3} + icon: {fileID: 21300000, guid: 4bc01c02d515fb5499cabb92c17bda38, type: 3} + enemyDrop: + - dropType: 1 + chance: 80 + - dropType: 2 + chance: 80 + - dropType: 3 + chance: 80 + - dropType: 10 + chance: 2 + - dropType: 20 + chance: 2 + - dropType: 30 + chance: 3 + - dropType: 40 + chance: 5 + - dropType: 100 + chance: 0 + - type: 9 + prefab: {fileID: 3260861724416974580, guid: a33bb0c2a5e7a2747b2b702850620e1b, + type: 3} + icon: {fileID: 21300000, guid: b1352c1e3ffc6894e9772ac7c32bcb98, type: 3} + enemyDrop: + - dropType: 0 + chance: 70 + - dropType: 1 + chance: 1 + - dropType: 10 + chance: 0 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 5 + prefab: {fileID: 8061002119726710921, guid: 8edae3002a94f8d4dae6376067971fe2, + type: 3} + icon: {fileID: 21300000, guid: 54387ce7f86e6a445b53a6ce866ed863, type: 3} + enemyDrop: + - dropType: 0 + chance: 80 + - dropType: 1 + chance: 5 + - dropType: 10 + chance: 0 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 11 + prefab: {fileID: 222113239425099812, guid: 5c98e7374319b0643852395ef2a867a6, type: 3} + icon: {fileID: 21300000, guid: 6f24555dc7c21274e996d2f67d1972cd, type: 3} + enemyDrop: + - dropType: 0 + chance: 100 + - dropType: 1 + chance: 90 + - dropType: 10 + chance: 1 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 12 + prefab: {fileID: 7557152801314046436, guid: e0ab0e4bbe3e70149bc9186d287265f8, + type: 3} + icon: {fileID: 21300000, guid: 417fa5adf2f4fd84ca8cebb330cdcf06, type: 3} + enemyDrop: + - dropType: 1 + chance: 100 + - dropType: 2 + chance: 40 + - dropType: 10 + chance: 0 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 10 + prefab: {fileID: 824918003456901437, guid: 9981766f459ab4b4eab73357b4064823, type: 3} + icon: {fileID: 21300000, guid: 3af945337b8033c47b7ff9be6dda0a30, type: 3} + enemyDrop: + - dropType: 1 + chance: 100 + - dropType: 2 + chance: 80 + - dropType: 3 + chance: 25 + - dropType: 10 + chance: 1 + - dropType: 20 + chance: 1 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 13 + prefab: {fileID: 2306842002636852994, guid: aad1d54138ae4984c881d12e3f783d45, + type: 3} + icon: {fileID: 21300000, guid: fd6da456e46a8f14f9c3557339a413e0, type: 3} + enemyDrop: + - dropType: 1 + chance: 100 + - dropType: 2 + chance: 80 + - dropType: 10 + chance: 1 + - dropType: 20 + chance: 1 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 14 + prefab: {fileID: 5834692076060082797, guid: 49e78728d34ba3b4bb63300d8bd9c1f4, + type: 3} + icon: {fileID: 21300000, guid: 0f80b779db6f90540a1582a39f105d6e, type: 3} + enemyDrop: + - dropType: 1 + chance: 90 + - dropType: 2 + chance: 80 + - dropType: 3 + chance: 40 + - dropType: 10 + chance: 1 + - dropType: 20 + chance: 1 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 17 + prefab: {fileID: 2451294393971234138, guid: 3b108c45bc6dc0a468e1d94116919b1a, + type: 3} + icon: {fileID: 21300000, guid: c71a56a9ed4f03042822b101beacf426, type: 3} + enemyDrop: + - dropType: 0 + chance: 90 + - dropType: 1 + chance: 80 + - dropType: 10 + chance: 1 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 16 + prefab: {fileID: 265741163110345578, guid: 50b425057a696c94ca33d5e654c7d08d, type: 3} + icon: {fileID: 21300000, guid: ad5b17b0d6492f047b5bd28ba0ddf22a, type: 3} + enemyDrop: + - dropType: 2 + chance: 100 + - dropType: 10 + chance: 1 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 3 + - dropType: 40 + chance: 5 + - dropType: 100 + chance: 80 + - type: 18 + prefab: {fileID: 6920036414143981837, guid: e9d61095a5b6c9049a196a7234ea91cf, + type: 3} + icon: {fileID: 21300000, guid: f8ba29ff37142b74e8d5134eefa2ae5c, type: 3} + enemyDrop: + - dropType: 2 + chance: 60 + - dropType: 10 + chance: 1 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 15 + prefab: {fileID: 409291670857762511, guid: f1e1215023a87f945a82b1dfe6a890b3, type: 3} + icon: {fileID: 21300000, guid: 5cb5f0f6bbbd2844fb9324dcac6f8d7f, type: 3} + enemyDrop: + - dropType: 1 + chance: 50 + - dropType: 10 + chance: 2 + - dropType: 20 + chance: 2 + - dropType: 30 + chance: 3 + - dropType: 40 + chance: 5 + - dropType: 100 + chance: 0 diff --git a/Assets/Common/Scriptables/Enemies Database VAT.asset.meta b/Assets/Common/Scriptables/Enemies Database VAT.asset.meta new file mode 100644 index 0000000..068ef8c --- /dev/null +++ b/Assets/Common/Scriptables/Enemies Database VAT.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7e12a9ec2d11c514f86809b8674f99c7 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Enemies Database.asset b/Assets/Common/Scriptables/Enemies Database.asset new file mode 100644 index 0000000..985fbcd --- /dev/null +++ b/Assets/Common/Scriptables/Enemies Database.asset @@ -0,0 +1,342 @@ +%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: 9fb969dd50a438d45b9176e14626575f, type: 3} + m_Name: Enemies Database + m_EditorClassIdentifier: + enemies: + - type: 1 + prefab: {fileID: 1090571174421192766, guid: bdb159c5340f537448bf478665384e2d, + type: 3} + icon: {fileID: 21300000, guid: c7314c840a31eb342ae17551898d7fe1, type: 3} + enemyDrop: + - dropType: 0 + chance: 80 + - dropType: 10 + chance: 0 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 8 + prefab: {fileID: 1090571174421192766, guid: 5dc89d49c6842b5409db52d345501d70, + type: 3} + icon: {fileID: 21300000, guid: 148058df3a6abb446b4e99942a200b65, type: 3} + enemyDrop: + - dropType: 0 + chance: 60 + - dropType: 10 + chance: 0 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 0 + prefab: {fileID: 1090571174421192766, guid: fbbda8dafe08b654f8e239cc4a20dad6, + type: 3} + icon: {fileID: 21300000, guid: 128a46be89fd93a42bc096292ec61c82, type: 3} + enemyDrop: + - dropType: 0 + chance: 90 + - dropType: 1 + chance: 70 + - dropType: 2 + chance: 20 + - dropType: 10 + chance: 0 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 2 + prefab: {fileID: 1090571174421192766, guid: 616763e865365904f81474b24c7dbd5a, + type: 3} + icon: {fileID: 21300000, guid: 3086c2163f612aa4eab4a1cc537a2874, type: 3} + enemyDrop: + - dropType: 0 + chance: 90 + - dropType: 1 + chance: 70 + - dropType: 2 + chance: 35 + - dropType: 10 + chance: 1 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 4 + prefab: {fileID: 1090571174421192766, guid: 448a3acc725a9854388bb61e498acffd, + type: 3} + icon: {fileID: 21300000, guid: c1add2dcde28f2a4a9eb8db6532bc6af, type: 3} + enemyDrop: + - dropType: 0 + chance: 50 + - dropType: 1 + chance: 90 + - dropType: 2 + chance: 70 + - dropType: 3 + chance: 10 + - dropType: 10 + chance: 1 + - dropType: 20 + chance: 1 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 3 + prefab: {fileID: 1090571174421192766, guid: 933a2aced38cff24b98c4f6bbf425bdc, + type: 3} + icon: {fileID: 21300000, guid: 4bc01c02d515fb5499cabb92c17bda38, type: 3} + enemyDrop: + - dropType: 1 + chance: 80 + - dropType: 2 + chance: 80 + - dropType: 3 + chance: 80 + - dropType: 10 + chance: 2 + - dropType: 20 + chance: 2 + - dropType: 30 + chance: 3 + - dropType: 40 + chance: 5 + - dropType: 100 + chance: 0 + - type: 9 + prefab: {fileID: 1000559380795741602, guid: 4fd0e1f4242cc534ba52cd31872d072b, + type: 3} + icon: {fileID: 21300000, guid: b1352c1e3ffc6894e9772ac7c32bcb98, type: 3} + enemyDrop: + - dropType: 0 + chance: 70 + - dropType: 1 + chance: 1 + - dropType: 10 + chance: 0 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 5 + prefab: {fileID: 1090571174421192766, guid: ba471a66ef3b5e84c8dbda0667af2dc3, + type: 3} + icon: {fileID: 21300000, guid: 54387ce7f86e6a445b53a6ce866ed863, type: 3} + enemyDrop: + - dropType: 0 + chance: 80 + - dropType: 1 + chance: 5 + - dropType: 10 + chance: 0 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 11 + prefab: {fileID: 1090571174421192766, guid: 28a727afd8706d44684b3377fb914bf0, + type: 3} + icon: {fileID: 21300000, guid: 6f24555dc7c21274e996d2f67d1972cd, type: 3} + enemyDrop: + - dropType: 0 + chance: 100 + - dropType: 1 + chance: 90 + - dropType: 10 + chance: 1 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 12 + prefab: {fileID: 1090571174421192766, guid: 7297358f854c26540b61d98d1dc9feda, + type: 3} + icon: {fileID: 21300000, guid: 417fa5adf2f4fd84ca8cebb330cdcf06, type: 3} + enemyDrop: + - dropType: 1 + chance: 100 + - dropType: 2 + chance: 40 + - dropType: 10 + chance: 0 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 10 + prefab: {fileID: 1090571174421192766, guid: 2ee190a0483a3014c9fa908f77e80e41, + type: 3} + icon: {fileID: 21300000, guid: 3af945337b8033c47b7ff9be6dda0a30, type: 3} + enemyDrop: + - dropType: 1 + chance: 100 + - dropType: 2 + chance: 80 + - dropType: 3 + chance: 25 + - dropType: 10 + chance: 1 + - dropType: 20 + chance: 1 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 13 + prefab: {fileID: 1090571174421192766, guid: d61327b5b6eb9684c83daba2169b97cb, + type: 3} + icon: {fileID: 21300000, guid: fd6da456e46a8f14f9c3557339a413e0, type: 3} + enemyDrop: + - dropType: 1 + chance: 100 + - dropType: 2 + chance: 80 + - dropType: 10 + chance: 1 + - dropType: 20 + chance: 1 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 14 + prefab: {fileID: 1090571174421192766, guid: 3b85b112e1154b4469a44f0040a84e7e, + type: 3} + icon: {fileID: 21300000, guid: 0f80b779db6f90540a1582a39f105d6e, type: 3} + enemyDrop: + - dropType: 1 + chance: 90 + - dropType: 2 + chance: 80 + - dropType: 3 + chance: 40 + - dropType: 10 + chance: 1 + - dropType: 20 + chance: 1 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 17 + prefab: {fileID: 1090571174421192766, guid: 9e7966bd0b80059438f701d4a2cbdbfa, + type: 3} + icon: {fileID: 21300000, guid: c71a56a9ed4f03042822b101beacf426, type: 3} + enemyDrop: + - dropType: 0 + chance: 90 + - dropType: 1 + chance: 80 + - dropType: 10 + chance: 1 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 16 + prefab: {fileID: 1090571174421192766, guid: f338a2d1e2742e84ba2c9d561d503157, + type: 3} + icon: {fileID: 21300000, guid: ad5b17b0d6492f047b5bd28ba0ddf22a, type: 3} + enemyDrop: + - dropType: 2 + chance: 100 + - dropType: 10 + chance: 1 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 3 + - dropType: 40 + chance: 5 + - dropType: 100 + chance: 80 + - type: 18 + prefab: {fileID: 1090571174421192766, guid: a0aa1826c7adb0847a0b4e8e7da48151, + type: 3} + icon: {fileID: 21300000, guid: f8ba29ff37142b74e8d5134eefa2ae5c, type: 3} + enemyDrop: + - dropType: 2 + chance: 60 + - dropType: 10 + chance: 1 + - dropType: 20 + chance: 0 + - dropType: 30 + chance: 1 + - dropType: 40 + chance: 1 + - dropType: 100 + chance: 0 + - type: 15 + prefab: {fileID: 1090571174421192766, guid: 527cb116fb01ba34994bd85d880719fe, + type: 3} + icon: {fileID: 21300000, guid: 5cb5f0f6bbbd2844fb9324dcac6f8d7f, type: 3} + enemyDrop: + - dropType: 1 + chance: 50 + - dropType: 10 + chance: 2 + - dropType: 20 + chance: 2 + - dropType: 30 + chance: 3 + - dropType: 40 + chance: 5 + - dropType: 100 + chance: 0 diff --git a/Assets/Common/Scriptables/Enemies Database.asset.meta b/Assets/Common/Scriptables/Enemies Database.asset.meta new file mode 100644 index 0000000..d826010 --- /dev/null +++ b/Assets/Common/Scriptables/Enemies Database.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d2602d31e8c0b1b4797a4095529207e6 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Enemy Dissolve Settings.asset b/Assets/Common/Scriptables/Enemy Dissolve Settings.asset new file mode 100644 index 0000000..0c3bbe2 --- /dev/null +++ b/Assets/Common/Scriptables/Enemy Dissolve Settings.asset @@ -0,0 +1,130 @@ +%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: fa3c00a7748473b43bfa8030d1a3a903, type: 3} + m_Name: Enemy Dissolve Settings + m_EditorClassIdentifier: + duration: 0.5 + dissolveColor: {r: 0, g: 0, b: 0, a: 1} + dissolveCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0.032703217 + outSlope: 0.032703217 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0.284923 + - serializedVersion: 3 + time: 0.2 + value: 0 + inSlope: 0.0445069 + outSlope: 0.0445069 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 1 + - serializedVersion: 3 + time: 0.21 + value: 0.2 + inSlope: -0.05170144 + outSlope: -0.05170144 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.08213279 + - serializedVersion: 3 + time: 0.4 + value: 0.2 + inSlope: 0.022727093 + outSlope: 0.022727093 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.5438472 + - serializedVersion: 3 + time: 0.41 + value: 0.39908448 + inSlope: 0.028312823 + outSlope: 0.028312823 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.11433273 + - serializedVersion: 3 + time: 0.55 + value: 0.4 + inSlope: 0.020683378 + outSlope: 0.020683378 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 1 + - serializedVersion: 3 + time: 0.56 + value: 0.6 + inSlope: 0.025294075 + outSlope: 0.025294075 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 1 + - serializedVersion: 3 + time: 0.7 + value: 0.6 + inSlope: 0.0074554696 + outSlope: 0.0074554696 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 1 + - serializedVersion: 3 + time: 0.71 + value: 0.8 + inSlope: -0.009211952 + outSlope: -0.009211952 + tangentMode: 0 + weightedMode: 0 + inWeight: 1 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.85 + value: 0.8 + inSlope: -0.012477119 + outSlope: -0.012477119 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.99685687 + - serializedVersion: 3 + time: 0.86 + value: 1 + inSlope: -0.009278259 + outSlope: -0.009278259 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: -0.006221684 + outSlope: -0.006221684 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.9995287 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 diff --git a/Assets/Common/Scriptables/Enemy Dissolve Settings.asset.meta b/Assets/Common/Scriptables/Enemy Dissolve Settings.asset.meta new file mode 100644 index 0000000..2f8603c --- /dev/null +++ b/Assets/Common/Scriptables/Enemy Dissolve Settings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2809f161967d6a0499a1a3061833468b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Experience Data.asset b/Assets/Common/Scriptables/Experience Data.asset new file mode 100644 index 0000000..658ebb5 --- /dev/null +++ b/Assets/Common/Scriptables/Experience Data.asset @@ -0,0 +1,137 @@ +%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: 1d03371d130b0624faa7f0d4cb61d768, type: 3} + m_Name: Experience Data + m_EditorClassIdentifier: + levels: + - multiplier: 1.5 + xp: 5 + - multiplier: 1 + xp: 5 + - multiplier: 1.4 + xp: 7 + - multiplier: 0 + xp: 9.8 + - multiplier: 0 + xp: 13.72 + - multiplier: 0 + xp: 19.208 + - multiplier: 0 + xp: 26.8912 + - multiplier: 0 + xp: 37.64768 + - multiplier: 0 + xp: 52.70675 + - multiplier: 0 + xp: 73.789444 + - multiplier: 0 + xp: 103.30522 + - multiplier: 0 + xp: 144.6273 + - multiplier: 0 + xp: 202.47823 + - multiplier: 0 + xp: 283.4695 + - multiplier: 0 + xp: 396.8573 + - multiplier: 0 + xp: 555.6002 + - multiplier: 0 + xp: 777.8403 + - multiplier: 0 + xp: 1088.9763 + - multiplier: 0 + xp: 1524.5668 + - multiplier: 0 + xp: 2134.3936 + - multiplier: 0 + xp: 2988.151 + - multiplier: 0 + xp: 4183.411 + - multiplier: 0 + xp: 5856.7754 + - multiplier: 0 + xp: 8199.485 + - multiplier: 0 + xp: 11479.279 + - multiplier: 0 + xp: 16070.991 + - multiplier: 0 + xp: 22499.387 + - multiplier: 0 + xp: 31499.14 + - multiplier: 0 + xp: 44098.797 + - multiplier: 0 + xp: 61738.316 + - multiplier: 0 + xp: 86433.64 + - multiplier: 0 + xp: 121007.09 + - multiplier: 0 + xp: 169409.92 + - multiplier: 0 + xp: 237173.89 + - multiplier: 0 + xp: 332043.44 + - multiplier: 0 + xp: 464860.8 + - multiplier: 0 + xp: 650805.1 + - multiplier: 0 + xp: 911127.2 + - multiplier: 0 + xp: 1275578 + - multiplier: 0 + xp: 1785809.1 + - multiplier: 0 + xp: 2500132.8 + - multiplier: 0 + xp: 3500185.8 + - multiplier: 0 + xp: 4900260 + - multiplier: 0 + xp: 6860364 + - multiplier: 0 + xp: 9604509 + - multiplier: 0 + xp: 13446312 + - multiplier: 0 + xp: 18824836 + - multiplier: 0 + xp: 26354770 + - multiplier: 0 + xp: 36896676 + - multiplier: 0 + xp: 51655344 + - multiplier: 0 + xp: 72317480 + - multiplier: 2 + xp: 144634960 + - multiplier: 2 + xp: 289269920 + - multiplier: 2 + xp: 578539840 + - multiplier: 2 + xp: 1.1570797e+9 + - multiplier: 2 + xp: 2.3141594e+9 + - multiplier: 2 + xp: 4.6283187e+9 + - multiplier: 2 + xp: 9.256637e+9 + - multiplier: 2 + xp: 1.8513275e+10 + - multiplier: 2 + xp: 3.702655e+10 + - multiplier: 2 + xp: 7.40531e+10 diff --git a/Assets/Common/Scriptables/Experience Data.asset.meta b/Assets/Common/Scriptables/Experience Data.asset.meta new file mode 100644 index 0000000..65573c7 --- /dev/null +++ b/Assets/Common/Scriptables/Experience Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fffb86bb83bfc2140a50ff57366afd1f +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Input.meta b/Assets/Common/Scriptables/Input.meta new file mode 100644 index 0000000..b8f02e8 --- /dev/null +++ b/Assets/Common/Scriptables/Input.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 167645ace93b86f4dbfc0c881078b592 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Input/Input Asset.inputactions.meta b/Assets/Common/Scriptables/Input/Input Asset.inputactions.meta new file mode 100644 index 0000000..2f0dc09 --- /dev/null +++ b/Assets/Common/Scriptables/Input/Input Asset.inputactions.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: e3d7cb309cd97cb4998aceb684f33068 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 8404be70184654265930450def6a9037, type: 3} + generateWrapperCode: 1 + wrapperCodePath: Assets/Common/Scripts/Toolkit/Input/Input Asset.cs + wrapperClassName: + wrapperCodeNamespace: OctoberStudio.Input diff --git a/Assets/Common/Scriptables/ProjectSettings.asset b/Assets/Common/Scriptables/ProjectSettings.asset new file mode 100644 index 0000000..620dcc3 --- /dev/null +++ b/Assets/Common/Scriptables/ProjectSettings.asset @@ -0,0 +1,17 @@ +%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: eba65de5fd9069241aafb2d7d75b5f44, type: 3} + m_Name: ProjectSettings + m_EditorClassIdentifier: + mainMenuSceneName: Main Menu + gameSceneName: Game + loadingSceneName: Loading Screen diff --git a/Assets/Common/Scriptables/ProjectSettings.asset.meta b/Assets/Common/Scriptables/ProjectSettings.asset.meta new file mode 100644 index 0000000..e9a6fc7 --- /dev/null +++ b/Assets/Common/Scriptables/ProjectSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d2aed15142d84f14a821502876d16809 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Stages.meta b/Assets/Common/Scriptables/Stages.meta new file mode 100644 index 0000000..0646dbd --- /dev/null +++ b/Assets/Common/Scriptables/Stages.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ed3021c0f9163a3449c4c22de2bdd2bb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Stages/Stage 1.asset b/Assets/Common/Scriptables/Stages/Stage 1.asset new file mode 100644 index 0000000..002e940 --- /dev/null +++ b/Assets/Common/Scriptables/Stages/Stage 1.asset @@ -0,0 +1,27 @@ +%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: e675658e5d57a9046b3324c0c946a620, type: 3} + m_Name: Stage 1 + m_EditorClassIdentifier: + icon: {fileID: 21300000, guid: baf23008440c44a4088a3e760f4dd7a6, type: 3} + displayName: DREAMY WOODS + timeline: {fileID: 11400000, guid: fa599a9bdd46a7b4886ff5ecbdfbe895, type: 2} + stageType: 0 + stageFieldData: {fileID: 11400000, guid: 52c7b0006b996a04681b47c761528a3d, type: 2} + spawnProp: 1 + removePropFromBossfight: 1 + spotlightColor: {r: 0.64705884, g: 1, b: 0.2901961, a: 0.24705882} + spotlightShadowColor: {r: 0.011764706, g: 0.09411765, b: 0.2901961, a: 0.95686275} + enemyDamage: 1 + enemyHP: 1 + useCustomMusic: 0 + musicName: Stage Music diff --git a/Assets/Common/Scriptables/Stages/Stage 1.asset.meta b/Assets/Common/Scriptables/Stages/Stage 1.asset.meta new file mode 100644 index 0000000..6ce9cc9 --- /dev/null +++ b/Assets/Common/Scriptables/Stages/Stage 1.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 65cc8c2c02e900547ba566463492af67 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Stages/Stage 1.playable.meta b/Assets/Common/Scriptables/Stages/Stage 1.playable.meta new file mode 100644 index 0000000..7c7e0dc --- /dev/null +++ b/Assets/Common/Scriptables/Stages/Stage 1.playable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fa599a9bdd46a7b4886ff5ecbdfbe895 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Stages/Stage 2.asset b/Assets/Common/Scriptables/Stages/Stage 2.asset new file mode 100644 index 0000000..6342066 --- /dev/null +++ b/Assets/Common/Scriptables/Stages/Stage 2.asset @@ -0,0 +1,27 @@ +%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: e675658e5d57a9046b3324c0c946a620, type: 3} + m_Name: Stage 2 + m_EditorClassIdentifier: + icon: {fileID: 21300000, guid: 9000f7664ecafea498cba3b07fa1f838, type: 3} + displayName: SHADE PALACE + timeline: {fileID: 11400000, guid: b0f895641243c3540b636140e9d64276, type: 2} + stageType: 0 + stageFieldData: {fileID: 11400000, guid: 4784fb39006132f48ad76bf040e6db27, type: 2} + spawnProp: 1 + removePropFromBossfight: 1 + spotlightColor: {r: 0.7921569, g: 0.93333334, b: 1, a: 0.24705882} + spotlightShadowColor: {r: 0.011764706, g: 0.09411765, b: 0.2901961, a: 0.95686275} + enemyDamage: 1 + enemyHP: 1 + useCustomMusic: 0 + musicName: Stage Music diff --git a/Assets/Common/Scriptables/Stages/Stage 2.asset.meta b/Assets/Common/Scriptables/Stages/Stage 2.asset.meta new file mode 100644 index 0000000..ca92dea --- /dev/null +++ b/Assets/Common/Scriptables/Stages/Stage 2.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2cc23836d2ac4b748986d78dce1713aa +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Stages/Stage 2.playable.meta b/Assets/Common/Scriptables/Stages/Stage 2.playable.meta new file mode 100644 index 0000000..94a9e2b --- /dev/null +++ b/Assets/Common/Scriptables/Stages/Stage 2.playable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b0f895641243c3540b636140e9d64276 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Stages/Stage 3.asset b/Assets/Common/Scriptables/Stages/Stage 3.asset new file mode 100644 index 0000000..f5a6a8d --- /dev/null +++ b/Assets/Common/Scriptables/Stages/Stage 3.asset @@ -0,0 +1,27 @@ +%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: e675658e5d57a9046b3324c0c946a620, type: 3} + m_Name: Stage 3 + m_EditorClassIdentifier: + icon: {fileID: 21300000, guid: 9000f7664ecafea498cba3b07fa1f838, type: 3} + displayName: BLCX SAMPLE + timeline: {fileID: 11400000, guid: 1962591010dc4a56ab9bd736fa175b63, type: 2} + stageType: 0 + stageFieldData: {fileID: 11400000, guid: 4784fb39006132f48ad76bf040e6db27, type: 2} + spawnProp: 1 + removePropFromBossfight: 1 + spotlightColor: {r: 0.7921569, g: 0.93333334, b: 1, a: 0.24705882} + spotlightShadowColor: {r: 0.011764706, g: 0.09411765, b: 0.2901961, a: 0.95686275} + enemyDamage: 1 + enemyHP: 1 + useCustomMusic: 0 + musicName: Stage Music diff --git a/Assets/Common/Scriptables/Stages/Stage 3.asset.meta b/Assets/Common/Scriptables/Stages/Stage 3.asset.meta new file mode 100644 index 0000000..2fe267a --- /dev/null +++ b/Assets/Common/Scriptables/Stages/Stage 3.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 238551b478d64c9eb8ab6431318d8e72 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Stages/Stage 3.playable.meta b/Assets/Common/Scriptables/Stages/Stage 3.playable.meta new file mode 100644 index 0000000..62b5d63 --- /dev/null +++ b/Assets/Common/Scriptables/Stages/Stage 3.playable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1962591010dc4a56ab9bd736fa175b63 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Stages/Stage Field Data.meta b/Assets/Common/Scriptables/Stages/Stage Field Data.meta new file mode 100644 index 0000000..859d1af --- /dev/null +++ b/Assets/Common/Scriptables/Stages/Stage Field Data.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 99477569eb3b7d147a76d9cb5bb84539 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Stages/Stage Field Data/Stage 1 Field Data.asset b/Assets/Common/Scriptables/Stages/Stage Field Data/Stage 1 Field Data.asset new file mode 100644 index 0000000..48553eb --- /dev/null +++ b/Assets/Common/Scriptables/Stages/Stage Field Data/Stage 1 Field Data.asset @@ -0,0 +1,38 @@ +%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: 108aeb0c3fe1ce34588d447d300c8020, type: 3} + m_Name: Stage 1 Field Data + m_EditorClassIdentifier: + obsoleteBackgroundPrefab: {fileID: 0} + backgroundPrefabs: + - {fileID: 4228152677517912084, guid: 72656fe2fa1a65647bf20dd40a6b25b8, type: 3} + topPrefab: {fileID: 6659819002268331200, guid: eb6aa68784579a74dbccb5b0f2bed58f, + type: 3} + bottomPrefab: {fileID: 7164971267086277502, guid: 813fcdb24b546da40bd63b835d404f58, + type: 3} + leftPrefab: {fileID: 1012426333365272321, guid: 4ba1a8dce6ec36a4fa0c56b7ae70f060, + type: 3} + rightPrefab: {fileID: 1883665581421635691, guid: 45c4ba4cb0301234da1ede1171c1480b, + type: 3} + topRightPrefab: {fileID: 8389163192620866072, guid: 3fec59a217c2f1c4d940cfa9132a6ddf, + type: 3} + topLeftPrefab: {fileID: 3653819040653122886, guid: dfe4337897bed05459df7ffd892b3bbb, + type: 3} + bottomRightPrefab: {fileID: 5336617445698214928, guid: a0f2ba96e3e752b40846f0dde6a43325, + type: 3} + bottomLeftPrefab: {fileID: 2104026248382152375, guid: 773770bad6d1c334db3377ac21750582, + type: 3} + propChances: + - prefab: {fileID: 1028214238412592778, guid: 2accda9df7a5e08479ce38f9b320104f, + type: 3} + maxAmount: 3 + chance: 75 diff --git a/Assets/Common/Scriptables/Stages/Stage Field Data/Stage 1 Field Data.asset.meta b/Assets/Common/Scriptables/Stages/Stage Field Data/Stage 1 Field Data.asset.meta new file mode 100644 index 0000000..b105c6c --- /dev/null +++ b/Assets/Common/Scriptables/Stages/Stage Field Data/Stage 1 Field Data.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 52c7b0006b996a04681b47c761528a3d +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Stages/Stage Field Data/Stage 2 Field Data 1.asset b/Assets/Common/Scriptables/Stages/Stage Field Data/Stage 2 Field Data 1.asset new file mode 100644 index 0000000..a02cb7b --- /dev/null +++ b/Assets/Common/Scriptables/Stages/Stage Field Data/Stage 2 Field Data 1.asset @@ -0,0 +1,38 @@ +%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: 108aeb0c3fe1ce34588d447d300c8020, type: 3} + m_Name: Stage 2 Field Data 1 + m_EditorClassIdentifier: + obsoleteBackgroundPrefab: {fileID: 0} + backgroundPrefabs: + - {fileID: 4228152677517912084, guid: 6db061bf302b26d42a0e336ad7c3b8f8, type: 3} + topPrefab: {fileID: 3057872433570077357, guid: ad957230a71ce374b813eba750025fbb, + type: 3} + bottomPrefab: {fileID: 464442095299332598, guid: 309cb689d34e2bc41b1a15c157ac3678, + type: 3} + leftPrefab: {fileID: 6705434063911671504, guid: 8987a1d04dc9b6d4192ef5be24107d5f, + type: 3} + rightPrefab: {fileID: 8863145417921677161, guid: 5a77b215b4b151a478c2fd303bcffadb, + type: 3} + topRightPrefab: {fileID: 3541167979401028516, guid: 0ac3ae68764071149bd1343a25075113, + type: 3} + topLeftPrefab: {fileID: 3541167979401028516, guid: 0ac3ae68764071149bd1343a25075113, + type: 3} + bottomRightPrefab: {fileID: 3541167979401028516, guid: 0ac3ae68764071149bd1343a25075113, + type: 3} + bottomLeftPrefab: {fileID: 3541167979401028516, guid: 0ac3ae68764071149bd1343a25075113, + type: 3} + propChances: + - prefab: {fileID: 1028214238412592778, guid: 1f9045912c762e44186e2735add53554, + type: 3} + maxAmount: 2 + chance: 75 diff --git a/Assets/Common/Scriptables/Stages/Stage Field Data/Stage 2 Field Data 1.asset.meta b/Assets/Common/Scriptables/Stages/Stage Field Data/Stage 2 Field Data 1.asset.meta new file mode 100644 index 0000000..fa5cfbd --- /dev/null +++ b/Assets/Common/Scriptables/Stages/Stage Field Data/Stage 2 Field Data 1.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4784fb39006132f48ad76bf040e6db27 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Stages/Stages Database.asset b/Assets/Common/Scriptables/Stages/Stages Database.asset new file mode 100644 index 0000000..cfdba44 --- /dev/null +++ b/Assets/Common/Scriptables/Stages/Stages Database.asset @@ -0,0 +1,18 @@ +%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: 925c0123597e16c489f7e2219144907d, type: 3} + m_Name: Stages Database + m_EditorClassIdentifier: + stages: + - {fileID: 11400000, guid: 65cc8c2c02e900547ba566463492af67, type: 2} + - {fileID: 11400000, guid: 2cc23836d2ac4b748986d78dce1713aa, type: 2} + - {fileID: 11400000, guid: 238551b478d64c9eb8ab6431318d8e72, type: 2} diff --git a/Assets/Common/Scriptables/Stages/Stages Database.asset.meta b/Assets/Common/Scriptables/Stages/Stages Database.asset.meta new file mode 100644 index 0000000..17cb5c3 --- /dev/null +++ b/Assets/Common/Scriptables/Stages/Stages Database.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dd33ab26d59ba964bb14dc6f04f2b921 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Testing.meta b/Assets/Common/Scriptables/Testing.meta new file mode 100644 index 0000000..86e9f37 --- /dev/null +++ b/Assets/Common/Scriptables/Testing.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f40c1875c42178248aef47b1804e3763 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Testing/Testing Preset.asset b/Assets/Common/Scriptables/Testing/Testing Preset.asset new file mode 100644 index 0000000..7221cfc --- /dev/null +++ b/Assets/Common/Scriptables/Testing/Testing Preset.asset @@ -0,0 +1,17 @@ +%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: ef6ba5f06fb1f254485408470b14b310, type: 3} + m_Name: Testing Preset + m_EditorClassIdentifier: + startTime: 0 + xpLevel: 0 + abilities: [] diff --git a/Assets/Common/Scriptables/Testing/Testing Preset.asset.meta b/Assets/Common/Scriptables/Testing/Testing Preset.asset.meta new file mode 100644 index 0000000..5fa6709 --- /dev/null +++ b/Assets/Common/Scriptables/Testing/Testing Preset.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0b2b4e01ae419fb47b00f52de8081dbc +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Upgrades.meta b/Assets/Common/Scriptables/Upgrades.meta new file mode 100644 index 0000000..11ad78f --- /dev/null +++ b/Assets/Common/Scriptables/Upgrades.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 74cbd96c624e0514b93d6acc3cf3f7e2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Upgrades/Upgrades Database.asset b/Assets/Common/Scriptables/Upgrades/Upgrades Database.asset new file mode 100644 index 0000000..8f04686 --- /dev/null +++ b/Assets/Common/Scriptables/Upgrades/Upgrades Database.asset @@ -0,0 +1,20 @@ +%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: 1488ee7297da57e489b6352dc6a2ef43, type: 3} + m_Name: Upgrades Database + m_EditorClassIdentifier: + upgrades: + - {fileID: 11400000, guid: 72b30c93416c42e4e9bffbacd232a6dd, type: 2} + - {fileID: 11400000, guid: 5964f8391b7783147855efc1e964f978, type: 2} + - {fileID: 11400000, guid: f9bbdce87b9ca3b458535d1b7bad230e, type: 2} + - {fileID: 11400000, guid: 9d44b06a4060f7244a61ba2c2000c236, type: 2} + - {fileID: 11400000, guid: 75b9efef8be59234582b4fed524cfd8b, type: 2} diff --git a/Assets/Common/Scriptables/Upgrades/Upgrades Database.asset.meta b/Assets/Common/Scriptables/Upgrades/Upgrades Database.asset.meta new file mode 100644 index 0000000..5d03ecd --- /dev/null +++ b/Assets/Common/Scriptables/Upgrades/Upgrades Database.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f249c53865e711542a3df804b8db1786 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Upgrades/Upgrades.meta b/Assets/Common/Scriptables/Upgrades/Upgrades.meta new file mode 100644 index 0000000..5e7ae84 --- /dev/null +++ b/Assets/Common/Scriptables/Upgrades/Upgrades.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 064458936f5b8174da21976b3052491d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Upgrades/Upgrades/Armour Upgrade.asset b/Assets/Common/Scriptables/Upgrades/Upgrades/Armour Upgrade.asset new file mode 100644 index 0000000..a16ff66 --- /dev/null +++ b/Assets/Common/Scriptables/Upgrades/Upgrades/Armour Upgrade.asset @@ -0,0 +1,27 @@ +%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: 36d3b836181b43648ba3d70244b2d519, type: 3} + m_Name: Armour Upgrade + m_EditorClassIdentifier: + upgradeType: 0 + icon: {fileID: 21300000, guid: defd5000544285c42b4e1ae97fedaa5d, type: 3} + title: ARMOR + devStartLevel: -1 + levels: + - cost: 200 + value: 0.9 + - cost: 400 + value: 0.8 + - cost: 1000 + value: 0.7 + - cost: 2000 + value: 0.6 diff --git a/Assets/Common/Scriptables/Upgrades/Upgrades/Armour Upgrade.asset.meta b/Assets/Common/Scriptables/Upgrades/Upgrades/Armour Upgrade.asset.meta new file mode 100644 index 0000000..d5fda42 --- /dev/null +++ b/Assets/Common/Scriptables/Upgrades/Upgrades/Armour Upgrade.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 72b30c93416c42e4e9bffbacd232a6dd +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Upgrades/Upgrades/Damage Upgrade.asset b/Assets/Common/Scriptables/Upgrades/Upgrades/Damage Upgrade.asset new file mode 100644 index 0000000..e245261 --- /dev/null +++ b/Assets/Common/Scriptables/Upgrades/Upgrades/Damage Upgrade.asset @@ -0,0 +1,27 @@ +%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: 36d3b836181b43648ba3d70244b2d519, type: 3} + m_Name: Damage Upgrade + m_EditorClassIdentifier: + upgradeType: 3 + icon: {fileID: 21300000, guid: b500287734c36194abb87d59e0cc108c, type: 3} + title: DAMAGE + devStartLevel: -1 + levels: + - cost: 200 + value: 1.25 + - cost: 400 + value: 1.5 + - cost: 1000 + value: 1.75 + - cost: 2000 + value: 2 diff --git a/Assets/Common/Scriptables/Upgrades/Upgrades/Damage Upgrade.asset.meta b/Assets/Common/Scriptables/Upgrades/Upgrades/Damage Upgrade.asset.meta new file mode 100644 index 0000000..d8d1689 --- /dev/null +++ b/Assets/Common/Scriptables/Upgrades/Upgrades/Damage Upgrade.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5964f8391b7783147855efc1e964f978 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Upgrades/Upgrades/Healing Upgrade.asset b/Assets/Common/Scriptables/Upgrades/Upgrades/Healing Upgrade.asset new file mode 100644 index 0000000..7661829 --- /dev/null +++ b/Assets/Common/Scriptables/Upgrades/Upgrades/Healing Upgrade.asset @@ -0,0 +1,27 @@ +%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: 36d3b836181b43648ba3d70244b2d519, type: 3} + m_Name: Healing Upgrade + m_EditorClassIdentifier: + upgradeType: 2 + icon: {fileID: 21300000, guid: 6c0287f4a16152145b8d9dc446a2be3b, type: 3} + title: HEALING + devStartLevel: -1 + levels: + - cost: 200 + value: 20 + - cost: 400 + value: 30 + - cost: 1000 + value: 40 + - cost: 2000 + value: 50 diff --git a/Assets/Common/Scriptables/Upgrades/Upgrades/Healing Upgrade.asset.meta b/Assets/Common/Scriptables/Upgrades/Upgrades/Healing Upgrade.asset.meta new file mode 100644 index 0000000..abb7654 --- /dev/null +++ b/Assets/Common/Scriptables/Upgrades/Upgrades/Healing Upgrade.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f9bbdce87b9ca3b458535d1b7bad230e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Upgrades/Upgrades/Health Upgrade.asset b/Assets/Common/Scriptables/Upgrades/Upgrades/Health Upgrade.asset new file mode 100644 index 0000000..03cdfcd --- /dev/null +++ b/Assets/Common/Scriptables/Upgrades/Upgrades/Health Upgrade.asset @@ -0,0 +1,27 @@ +%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: 36d3b836181b43648ba3d70244b2d519, type: 3} + m_Name: Health Upgrade + m_EditorClassIdentifier: + upgradeType: 1 + icon: {fileID: 21300000, guid: 2deb6e762eff10748b0caa8e6f3976b5, type: 3} + title: HEALTH + devStartLevel: -1 + levels: + - cost: 200 + value: 100 + - cost: 400 + value: 200 + - cost: 1000 + value: 300 + - cost: 2000 + value: 400 diff --git a/Assets/Common/Scriptables/Upgrades/Upgrades/Health Upgrade.asset.meta b/Assets/Common/Scriptables/Upgrades/Upgrades/Health Upgrade.asset.meta new file mode 100644 index 0000000..badc441 --- /dev/null +++ b/Assets/Common/Scriptables/Upgrades/Upgrades/Health Upgrade.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9d44b06a4060f7244a61ba2c2000c236 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scriptables/Upgrades/Upgrades/Revive Upgrade.asset b/Assets/Common/Scriptables/Upgrades/Upgrades/Revive Upgrade.asset new file mode 100644 index 0000000..9dbc85d --- /dev/null +++ b/Assets/Common/Scriptables/Upgrades/Upgrades/Revive Upgrade.asset @@ -0,0 +1,21 @@ +%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: 36d3b836181b43648ba3d70244b2d519, type: 3} + m_Name: Revive Upgrade + m_EditorClassIdentifier: + upgradeType: 4 + icon: {fileID: 21300000, guid: 4a5f03c47f7094549aef6dbcbb22d190, type: 3} + title: REVIVE + devStartLevel: -1 + levels: + - cost: 1000 + value: 0 diff --git a/Assets/Common/Scriptables/Upgrades/Upgrades/Revive Upgrade.asset.meta b/Assets/Common/Scriptables/Upgrades/Upgrades/Revive Upgrade.asset.meta new file mode 100644 index 0000000..e74bd10 --- /dev/null +++ b/Assets/Common/Scriptables/Upgrades/Upgrades/Revive Upgrade.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 75b9efef8be59234582b4fed524cfd8b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities.meta b/Assets/Common/Scripts/Abilities.meta new file mode 100644 index 0000000..50db6b9 --- /dev/null +++ b/Assets/Common/Scripts/Abilities.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3e2e82035b192d64abc0b96eafca7d18 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors.meta b/Assets/Common/Scripts/Abilities/Behaviors.meta new file mode 100644 index 0000000..df4f94f --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 88b30e86d1fc7bc44866b4978b953a58 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/AbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/AbilityBehavior.cs new file mode 100644 index 0000000..d597f6c --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/AbilityBehavior.cs @@ -0,0 +1,48 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public abstract class AbilityBehavior : MonoBehaviour, IAbilityBehavior where T: GenericAbilityData where K : AbilityLevel + { + public T Data { get; private set; } + public AbilityData AbilityData => Data; + public AbilityType AbilityType => Data.AbilityType; + + public K AbilityLevel { get; private set; } + public int LevelId { get; private set; } + + public virtual void Init(AbilityData data, int levelId) + { + SetData(data as T); + SetAbilityLevel(levelId); + + Data.onAbilityUpgraded += OnAbilityUpgraded; + } + + protected virtual void SetData(T data) + { + Data = data; + } + + protected virtual void SetAbilityLevel(int levelId) + { + LevelId = levelId; + AbilityLevel = Data.GetLevel(levelId); + } + + protected virtual void OnAbilityUpgraded(int levelId) + { + SetAbilityLevel(levelId); + } + + private void OnDestroy() + { + Data.onAbilityUpgraded -= OnAbilityUpgraded; + } + + public virtual void Clear() + { + Destroy(gameObject); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/AbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/AbilityBehavior.cs.meta new file mode 100644 index 0000000..5cea593 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/AbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 397d74438d4239e4ca3d0af0238d20ed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities.meta new file mode 100644 index 0000000..9de9952 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e3de2c5d152cd6840aab9cc53e7bf244 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang.meta new file mode 100644 index 0000000..2cb2111 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 950b353253d0f3049b91d5e14a507657 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/BoomerangAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/BoomerangAbilityBehavior.cs new file mode 100644 index 0000000..239139d --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/BoomerangAbilityBehavior.cs @@ -0,0 +1,102 @@ +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class BoomerangAbilityBehavior : AbilityBehavior + { + [SerializeField] GameObject boomerangPrefab; + public GameObject BoomerangPrefab => boomerangPrefab; + + private PoolComponent projectilePool; + + private Coroutine abilityCoroutine; + private List projectiles = new List(); + + private void Awake() + { + projectilePool = new PoolComponent("Boomerang Ability Projectile", BoomerangPrefab, 5); + } + + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + Disable(); + + abilityCoroutine = StartCoroutine(AbilityCoroutine()); + } + + private IEnumerator AbilityCoroutine() + { + while (true) + { + for(int i = 0; i < AbilityLevel.ProjectileCount; i++) + { + var projectile = projectilePool.GetEntity(); + + projectile.transform.position = PlayerBehavior.CenterPosition; + + var enemy = StageController.EnemiesSpawner.GetClosestEnemy(projectile.transform.position); + + Vector2 direction; + if(enemy == null) + { + direction = Random.insideUnitCircle.normalized; + } else + { + direction = (enemy.Center - projectile.transform.position.XY()).normalized; + } + + projectile.DamageMultiplier = AbilityLevel.Damage; + projectile.ProjectileLifetime = AbilityLevel.ProjectileLifetime; + projectile.ProjectileTravelDistance = AbilityLevel.ProjectileTravelDistance; + projectile.Size = AbilityLevel.ProjectileSize; + + projectile.onBoomerangFinished += OnBoomerangFinished; + + projectile.Spawn(direction); + + projectiles.Add(projectile); + + yield return new WaitForSeconds(AbilityLevel.TimeBetweenProjectiles); + } + + yield return new WaitForSeconds(AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier - AbilityLevel.TimeBetweenProjectiles * AbilityLevel.ProjectileCount); + } + } + + private void Disable() + { + if (abilityCoroutine != null) StopCoroutine(abilityCoroutine); + + for (int i = 0; i < projectiles.Count; i++) + { + var projectile = projectiles[i]; + + projectile.onBoomerangFinished -= OnBoomerangFinished; + + projectile.Disable(); + } + + projectiles.Clear(); + } + + private void OnBoomerangFinished(BoomerangProjectileBehavior boomerang) + { + boomerang.onBoomerangFinished -= OnBoomerangFinished; + + projectiles.Remove(boomerang); + } + + public override void Clear() + { + Disable(); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/BoomerangAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/BoomerangAbilityBehavior.cs.meta new file mode 100644 index 0000000..735a113 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/BoomerangAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6771daf351f24204ab63d44288ec260f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/BoomerangAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/BoomerangAbilityData.cs new file mode 100644 index 0000000..8f6e291 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/BoomerangAbilityData.cs @@ -0,0 +1,50 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Boomerang Ability Data", menuName = "October/Abilities/Active/Boomerang")] + public class BoomerangAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.Boomerang; + } + + private void OnValidate() + { + type = AbilityType.Boomerang; + } + } + + [System.Serializable] + public class BoomerangAbilityLevel : AbilityLevel + { + [Tooltip("Amount of boomerang spawned at the same time")] + [SerializeField] int projectileCount; + public int ProjectileCount => projectileCount; + + [Tooltip("Amount of time before boomerang disappears")] + [SerializeField] float projectileLifetime; + public float ProjectileLifetime => projectileLifetime; + + [Tooltip("Amount of time between firing boomerang in one attack")] + [SerializeField] float timeBetweenProjectiles; + public float TimeBetweenProjectiles => timeBetweenProjectiles; + + [Tooltip("Amount of time between attacks")] + [SerializeField] float abilityCooldown; + public float AbilityCooldown => abilityCooldown; + + [Tooltip("Max distance the boomerang will travel from the player")] + [SerializeField] float projectileTravelDistance; + public float ProjectileTravelDistance => projectileTravelDistance; + + [Tooltip("Damage of the boomerang calculates as 'Damage = Player.Damage * damage'")] + [SerializeField] float damage; + public float Damage => damage; + + [Tooltip("Size of the boomerang")] + [SerializeField] float projectileSize; + public float ProjectileSize => projectileSize; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/BoomerangAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/BoomerangAbilityData.cs.meta new file mode 100644 index 0000000..5ccf908 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/BoomerangAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6a60f52c2a6bf3b4a81b89d34e2fe101 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/BoomerangProjectileBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/BoomerangProjectileBehavior.cs new file mode 100644 index 0000000..2067787 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/BoomerangProjectileBehavior.cs @@ -0,0 +1,45 @@ +using OctoberStudio.Easing; +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio.Abilities +{ + public class BoomerangProjectileBehavior : ProjectileBehavior + { + private static readonly int BOOMERANG_THROW_HASH = "Boomerang Throw".GetHashCode(); + + public UnityAction onBoomerangFinished; + + [SerializeField] AnimationCurve trajectiory; + + private IEasingCoroutine movementCoroutine; + + public float ProjectileTravelDistance { get; set; } + public float ProjectileLifetime { get; set; } + public float Size { get; set; } + + public void Spawn(Vector3 direction) + { + Init(); + + transform.localScale = Vector3.one * Size * PlayerBehavior.Player.SizeMultiplier; + + var targetPosition = transform.position + direction * ProjectileTravelDistance * PlayerBehavior.Player.SizeMultiplier * PlayerBehavior.Player.DurationMultiplier; + movementCoroutine = transform.DoPosition(targetPosition, ProjectileLifetime / PlayerBehavior.Player.ProjectileSpeedMultiplier).SetEasingCurve(trajectiory).SetOnFinish(() => + { + gameObject.SetActive(false); + onBoomerangFinished?.Invoke(this); + }); + + KickBack = false; + + GameController.AudioManager.PlaySound(BOOMERANG_THROW_HASH); + } + + public void Disable() + { + movementCoroutine.StopIfExists(); + gameObject.SetActive(false); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/BoomerangProjectileBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/BoomerangProjectileBehavior.cs.meta new file mode 100644 index 0000000..2aab935 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/BoomerangProjectileBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 59e867cef2e471f44a220e3113531d9c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution.meta new file mode 100644 index 0000000..02584f4 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 133055e8ea04f1d4b88b04c1a7edda64 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution/RecoilerAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution/RecoilerAbilityBehavior.cs new file mode 100644 index 0000000..808a96e --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution/RecoilerAbilityBehavior.cs @@ -0,0 +1,96 @@ +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class RecoilerAbilityBehavior : AbilityBehavior + { + public static readonly int RECOILER_LAUNCH_HASH = "Recoiler Launch".GetHashCode(); + + [SerializeField] GameObject recoilerPrefab; + public GameObject RecoilerPrefab => recoilerPrefab; + + private PoolComponent projectilePool; + + private Coroutine abilityCoroutine; + private List projectiles = new List(); + + private void Awake() + { + projectilePool = new PoolComponent("Recoiler Ability Projectile", RecoilerPrefab, 5); + } + + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + Disable(); + + abilityCoroutine = StartCoroutine(AbilityCoroutine()); + } + + private IEnumerator AbilityCoroutine() + { + while (true) + { + SpawnProjectile(0); + SpawnProjectile(180); + + GameController.AudioManager.PlaySound(RECOILER_LAUNCH_HASH); + + yield return new WaitForSeconds(AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier); + } + } + + private void SpawnProjectile(float startingAngle) + { + var projectile = projectilePool.GetEntity(); + + projectile.transform.position = PlayerBehavior.CenterPosition; + + projectile.DamageMultiplier = AbilityLevel.Damage; + projectile.ProjectileLifetime = AbilityLevel.ProjectileLifetime; + projectile.ProjectileTravelDistance = AbilityLevel.ProjectileTravelDistance; + projectile.Size = AbilityLevel.ProjectileSize; + projectile.AngularSpeed = AbilityLevel.AngularSpeed; + + projectile.onRecoilerFinished += OnRecoilerFinished; + + projectile.Spawn(startingAngle); + + projectiles.Add(projectile); + } + + private void Disable() + { + if (abilityCoroutine != null) StopCoroutine(abilityCoroutine); + + for (int i = 0; i < projectiles.Count; i++) + { + var projectile = projectiles[i]; + + projectile.onRecoilerFinished -= OnRecoilerFinished; + + projectile.Disable(); + } + + projectiles.Clear(); + } + + private void OnRecoilerFinished(RecoilerProjectileBehavior recoiler) + { + recoiler.onRecoilerFinished -= OnRecoilerFinished; + + projectiles.Remove(recoiler); + } + + public override void Clear() + { + Disable(); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution/RecoilerAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution/RecoilerAbilityBehavior.cs.meta new file mode 100644 index 0000000..3bf667e --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution/RecoilerAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ef97d0be936ca07468541ee6fa141d9d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution/RecoilerAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution/RecoilerAbilityData.cs new file mode 100644 index 0000000..6d897c9 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution/RecoilerAbilityData.cs @@ -0,0 +1,46 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Recoiler Ability Data", menuName = "October/Abilities/Evolution/Recoiler")] + public class RecoilerAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.Recoiler; + } + + private void OnValidate() + { + type = AbilityType.Recoiler; + } + } + + [System.Serializable] + public class RecoilerAbilityLevel : AbilityLevel + { + [Tooltip("Amount of time before recoiler disappears")] + [SerializeField] float projectileLifetime; + public float ProjectileLifetime => projectileLifetime; + + [Tooltip("Amount of time between attacks")] + [SerializeField] float abilityCooldown; + public float AbilityCooldown => abilityCooldown; + + [Tooltip("Max distance the recoiler will travel from the player")] + [SerializeField] float projectileTravelDistance; + public float ProjectileTravelDistance => projectileTravelDistance; + + [Tooltip("Rotational speed of the recoiler")] + [SerializeField] float angularSpeed; + public float AngularSpeed => angularSpeed; + + [Tooltip("Damage of the recoiler calculates as 'Damage = Player.Damage * Damage'")] + [SerializeField] float damage; + public float Damage => damage; + + [Tooltip("Size of the recoiler")] + [SerializeField] float projectileSize; + public float ProjectileSize => projectileSize; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution/RecoilerAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution/RecoilerAbilityData.cs.meta new file mode 100644 index 0000000..c029228 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution/RecoilerAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6b45cb7027aba0e42a578f2da7fde9b6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution/RecoilerProjectileBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution/RecoilerProjectileBehavior.cs new file mode 100644 index 0000000..1ccc000 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution/RecoilerProjectileBehavior.cs @@ -0,0 +1,70 @@ +using OctoberStudio.Extensions; +using System.Collections; +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio.Abilities +{ + public class RecoilerProjectileBehavior : ProjectileBehavior + { + public UnityAction onRecoilerFinished; + + private Coroutine movementCoroutine; + + public float ProjectileTravelDistance { get; set; } + public float ProjectileLifetime { get; set; } + public float Size { get; set; } + public float AngularSpeed { get; set; } + + public void Spawn(float startingAngle) + { + Init(); + transform.localScale = Vector3.one * Size * PlayerBehavior.Player.SizeMultiplier; + + KickBack = false; + + movementCoroutine = StartCoroutine(MovementCoroutine(startingAngle)); + } + + private IEnumerator MovementCoroutine(float startingAngle) + { + var time = 0f; + var duration = ProjectileLifetime * PlayerBehavior.Player.DurationMultiplier; + + var startPosition = PlayerBehavior.CenterPosition; + + var distance = ProjectileTravelDistance * PlayerBehavior.Player.SizeMultiplier; + var currentDistance = 0f; + do + { + yield return null; + + time += Time.deltaTime; + var t = time / duration; + + var angle = startingAngle + time * AngularSpeed * PlayerBehavior.Player.ProjectileSpeedMultiplier; + + float cos = Mathf.Abs(Mathf.Cos(angle * Mathf.Deg2Rad)); + float scale = Mathf.Lerp(0.5f, 1f, cos); + + currentDistance += Time.deltaTime * (distance / duration) * scale; + + var position = startPosition +( Quaternion.Euler(0, 0, angle) * Vector2.up * currentDistance).XY(); + + transform.position = position; + + } while (time < duration); + + gameObject.SetActive(false); + onRecoilerFinished?.Invoke(this); + + movementCoroutine = null; + } + + public void Disable() + { + if (movementCoroutine != null) StopCoroutine(movementCoroutine); + gameObject.SetActive(false); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution/RecoilerProjectileBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution/RecoilerProjectileBehavior.cs.meta new file mode 100644 index 0000000..b32ec3e --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boomerang/Evolution/RecoilerProjectileBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7faa7ba58563de1489d7b1ac32f6e805 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder.meta new file mode 100644 index 0000000..0dbcb30 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c47e5808c257861458c90cf7c28727c7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/BoulderProjectileBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/BoulderProjectileBehavior.cs new file mode 100644 index 0000000..cdb447f --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/BoulderProjectileBehavior.cs @@ -0,0 +1,41 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class BoulderProjectileBehavior : CameraSpaceProjectile + { + [SerializeField] bool kickBack; + + [SerializeField] Transform boulderTransform; + public float Size { get; set; } + public float AngularSpeed { get; set; } + + public override Rect GetBounds() + { + return new Rect(boulderTransform.position + (Vector3.down + Vector3.left) * Size / 2, Vector3.one * Size); + } + + public void SetData(float size, float damageMultiplier, float speed, float angularSpeed) + { + transform.localScale = Vector3.one * size; + + Size = size; + KickBack = kickBack; + DamageMultiplier = damageMultiplier; + + AngularSpeed = angularSpeed; + Speed = speed; + } + + public override void Update() + { + base.Update(); + + var xSign = -Direction.x / Mathf.Abs(Direction.x); + + transform.localScale = Vector3.one * Size * PlayerBehavior.Player.SizeMultiplier; + + boulderTransform.eulerAngles += Vector3.forward * xSign * Time.deltaTime * AngularSpeed * PlayerBehavior.Player.ProjectileSpeedMultiplier; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/BoulderProjectileBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/BoulderProjectileBehavior.cs.meta new file mode 100644 index 0000000..16caf9c --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/BoulderProjectileBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 93ee15f588cd26b4587855fc93f66632 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/Evolution.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/Evolution.meta new file mode 100644 index 0000000..88555d6 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/Evolution.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d82fdd6b86f165147bd186863f92c988 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/Evolution/MaceBallAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/Evolution/MaceBallAbilityBehavior.cs new file mode 100644 index 0000000..d11644c --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/Evolution/MaceBallAbilityBehavior.cs @@ -0,0 +1,32 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class MaceBallAbilityBehavior : AbilityBehavior + { + public static readonly int MACE_BALL_LAUNCH_HASH = "Mace Ball Launch".GetHashCode(); + + [SerializeField] BoulderProjectileBehavior boulderProjectileBehavior; + + public override void Init(AbilityData data, int stageId) + { + base.Init(data, stageId); + + GameController.AudioManager.PlaySound(MACE_BALL_LAUNCH_HASH); + + boulderProjectileBehavior.Direction = (Vector2.up + Vector2.right).normalized; + } + + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + boulderProjectileBehavior.SetData(AbilityLevel.Size, AbilityLevel.DamageMultiplier, AbilityLevel.Speed, AbilityLevel.AngularSpeed); + } + + public override void Clear() + { + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/Evolution/MaceBallAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/Evolution/MaceBallAbilityBehavior.cs.meta new file mode 100644 index 0000000..0d3a40f --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/Evolution/MaceBallAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 82df46dad133e89438f3406c9ff4d2d6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/Evolution/MaceBallAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/Evolution/MaceBallAbilityData.cs new file mode 100644 index 0000000..2b6f72c --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/Evolution/MaceBallAbilityData.cs @@ -0,0 +1,38 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Mace Ball Ability Data", menuName = "October/Abilities/Evolution/Mace Ball")] + public class MaceBallAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.MaceBall; + } + + private void OnValidate() + { + type = AbilityType.MaceBall; + } + } + + [System.Serializable] + public class MaceBallAbilityLevel : AbilityLevel + { + [Tooltip("The speed of the mace ball")] + [SerializeField] float speed; + public float Speed => speed; + + [Tooltip("The speed of the rotation of the mace ball")] + [SerializeField] float angularSpeed = 180; + public float AngularSpeed => angularSpeed; + + [Tooltip("The amount of damage the roling stone deals is calculated like Player.Damage * Damage")] + [SerializeField] float damage; + public float DamageMultiplier => damage; + + [Tooltip("The size of the mace ball")] + [SerializeField] float size; + public float Size => size; + } +} diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/Evolution/MaceBallAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/Evolution/MaceBallAbilityData.cs.meta new file mode 100644 index 0000000..9e7e637 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/Evolution/MaceBallAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4bbb4463f118f3d4bb9544bfbd915f0c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/RollingStoneAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/RollingStoneAbilityBehavior.cs new file mode 100644 index 0000000..dee759e --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/RollingStoneAbilityBehavior.cs @@ -0,0 +1,33 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class RollingStoneAbilityBehavior : AbilityBehavior + { + private static readonly int ROLLING_STONE_LAUNCH_HASH = "Rolling Stone Launch".GetHashCode(); + + [SerializeField] BoulderProjectileBehavior boulderProjectileBehavior; + + public override void Init(AbilityData data, int stageId) + { + base.Init(data, stageId); + + boulderProjectileBehavior.transform.position = PlayerBehavior.CenterPosition; + boulderProjectileBehavior.Direction = (Vector2.up + Vector2.right).normalized; + + GameController.AudioManager.PlaySound(ROLLING_STONE_LAUNCH_HASH); + } + + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + boulderProjectileBehavior.SetData(AbilityLevel.Size, AbilityLevel.Damage, AbilityLevel.Speed, AbilityLevel.AngularSpeed); + } + + public override void Clear() + { + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/RollingStoneAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/RollingStoneAbilityBehavior.cs.meta new file mode 100644 index 0000000..7ec0974 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/RollingStoneAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5dfcdf5356fdf9347b09821ffb2cc41e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/RollingStoneAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/RollingStoneAbilityData.cs new file mode 100644 index 0000000..29d4cf7 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/RollingStoneAbilityData.cs @@ -0,0 +1,38 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Rolling Stone Ability Data", menuName = "October/Abilities/Active/Rolling Stone")] + public class RollingStoneAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.RollingStone; + } + + private void OnValidate() + { + type = AbilityType.RollingStone; + } + } + + [System.Serializable] + public class RollingStoneAbilityLevel : AbilityLevel + { + [Tooltip("The speed of the rolling stone")] + [SerializeField] float speed; + public float Speed => speed; + + [Tooltip("The speed of the rotation of the rolling stone")] + [SerializeField] float angularSpeed = 180; + public float AngularSpeed => angularSpeed; + + [Tooltip("The amount of damage the roling stone deals is calculated like Player.Damage * Damage")] + [SerializeField] float damage; + public float Damage => damage; + + [Tooltip("The size of the rolling stone")] + [SerializeField] float size; + public float Size => size; + } +} diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/RollingStoneAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/RollingStoneAbilityData.cs.meta new file mode 100644 index 0000000..ae40d18 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Boulder/RollingStoneAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 44ab41556cf462c409841060a869521f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall.meta new file mode 100644 index 0000000..9517032 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c8b40605f15e83b439df159e603f750b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution.meta new file mode 100644 index 0000000..118e189 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7596c6c54757a414abdbe978411b385f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution/MeteorAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution/MeteorAbilityBehavior.cs new file mode 100644 index 0000000..a9e1dea --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution/MeteorAbilityBehavior.cs @@ -0,0 +1,101 @@ +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class MeteorAbilityBehavior : AbilityBehavior + { + [SerializeField] GameObject meteorPrefab; + public GameObject MeteorPrefab => meteorPrefab; + + private PoolComponent meteorPool; + + private Coroutine abilityCoroutine; + + private List aliveMeteors = new List(); + + private void Awake() + { + meteorPool = new PoolComponent("Meteor Ability Projectile", MeteorPrefab, 6); + } + + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + if (abilityCoroutine != null) Disable(); + + abilityCoroutine = StartCoroutine(AbilityCoroutine()); + } + + private IEnumerator AbilityCoroutine() + { + while (true) + { + for (int i = 0; i < AbilityLevel.ProjectilesCount; i++) + { + var meteor = meteorPool.GetEntity(); + + meteor.transform.position = PlayerBehavior.CenterPosition; + + meteor.DamageMultiplier = AbilityLevel.Damage; + meteor.ExplosionRadius = AbilityLevel.ExplosionRadius; + + meteor.onFinished += OnFireballFinished; + + var impactPosition = PlayerBehavior.CenterPosition; + + int counter = 0; + while(Vector3.Distance(impactPosition, PlayerBehavior.CenterPosition) < 0.5f) + { + if (counter > 10) break; + + impactPosition = CameraManager.GetPointInsideCamera(); + + counter++; + } + + meteor.Init(impactPosition); + + aliveMeteors.Add(meteor); + + yield return new WaitForSeconds(AbilityLevel.TimeBetweenProjectiles); + } + + yield return new WaitForSeconds(AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier - AbilityLevel.TimeBetweenProjectiles * AbilityLevel.ProjectilesCount); + } + } + + private void OnFireballFinished(MeteorProjectileBehavior meteor) + { + meteor.onFinished -= OnFireballFinished; + + aliveMeteors.Remove(meteor); + } + + public void Disable() + { + StopCoroutine(abilityCoroutine); + + for (int i = 0; i < aliveMeteors.Count; i++) + { + var meteor = aliveMeteors[i]; + + meteor.onFinished -= OnFireballFinished; + + meteor.Clear(); + } + + aliveMeteors.Clear(); + } + + public override void Clear() + { + Disable(); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution/MeteorAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution/MeteorAbilityBehavior.cs.meta new file mode 100644 index 0000000..c233c1e --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution/MeteorAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c5959e2e071c7fb4e900bcf9307219e9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution/MeteorAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution/MeteorAbilityData.cs new file mode 100644 index 0000000..070c9ac --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution/MeteorAbilityData.cs @@ -0,0 +1,42 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Meteor Ability Data", menuName = "October/Abilities/Evolution/Meteor")] + public class MeteorAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.Meteor; + } + + private void OnValidate() + { + type = AbilityType.Meteor; + } + } + + [System.Serializable] + public class MeteorAbilityLevel : AbilityLevel + { + [Tooltip("Amount of fireballs spawned at the same time")] + [SerializeField] int projectilesCount; + public int ProjectilesCount => projectilesCount; + + [Tooltip("Amount of time between firing meteors in one attack")] + [SerializeField] float timeBetweenProjectiles; + public float TimeBetweenProjectiles => timeBetweenProjectiles; + + [Tooltip("Amount of time between attacks")] + [SerializeField] float abilityCooldown; + public float AbilityCooldown => abilityCooldown; + + [Tooltip("Damage of the fireball calculates as 'Damage = Player.Damage * Damage'")] + [SerializeField] float damage; + public float Damage => damage; + + [Tooltip("Inside this radius every enemy will be damaged")] + [SerializeField] float explosionRadius; + public float ExplosionRadius => explosionRadius; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution/MeteorAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution/MeteorAbilityData.cs.meta new file mode 100644 index 0000000..2ed1a3a --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution/MeteorAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7ef84cc4bbaf71b47bb750531b36ab2f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution/MeteorProjectileBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution/MeteorProjectileBehavior.cs new file mode 100644 index 0000000..9a3fc4c --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution/MeteorProjectileBehavior.cs @@ -0,0 +1,79 @@ +using OctoberStudio.Easing; +using OctoberStudio.Extensions; +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio.Abilities +{ + public class MeteorProjectileBehavior : MonoBehaviour + { + public static readonly int METEOR_LAUNCH_HASH = "Meteor Launch".GetHashCode(); + public static readonly int METEOR_IMPACT_HASH = "Meteor Impact".GetHashCode(); + + [SerializeField] ParticleSystem explosionParticle; + [SerializeField] GameObject visuals; + + [SerializeField] float speed = 4f; + + public event UnityAction onFinished; + + private IEasingCoroutine movementCoroutine; + private IEasingCoroutine disableCoroutine; + + public float DamageMultiplier { get; set; } + public float ExplosionRadius { get; set; } + + public void Init(Vector2 impactPosition) + { + var spawnPosition = impactPosition + (visuals.transform.rotation * Vector3.up).XY() * CameraManager.HalfHeight * 2.2f; + + visuals.SetActive(true); + + movementCoroutine.StopIfExists(); + disableCoroutine.StopIfExists(); + + transform.position = spawnPosition; + + var distance = Vector2.Distance(impactPosition, spawnPosition); + var duration = distance / speed; + movementCoroutine = transform.DoPosition(impactPosition, duration).SetOnFinish(Explode); + + GameController.AudioManager.PlaySound(METEOR_LAUNCH_HASH); + } + + private void Explode() + { + visuals.SetActive(false); + + var enemies = StageController.EnemiesSpawner.GetEnemiesInRadius(transform.position, ExplosionRadius); + + for (int i = 0; i < enemies.Count; i++) + { + var enemy = enemies[i]; + + enemy.TakeDamage(PlayerBehavior.Player.Damage * DamageMultiplier); + } + + explosionParticle.Play(); + + disableCoroutine = EasingManager.DoAfter(2.5f, () => + { + gameObject.SetActive(false); + visuals.SetActive(true); + onFinished?.Invoke(this); + }); + + GameController.AudioManager.PlaySound(METEOR_IMPACT_HASH); + } + + public void Clear() + { + movementCoroutine.StopIfExists(); + disableCoroutine.StopIfExists(); + + gameObject.SetActive(false); + + visuals.SetActive(true); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution/MeteorProjectileBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution/MeteorProjectileBehavior.cs.meta new file mode 100644 index 0000000..88928a2 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/Evolution/MeteorProjectileBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2f3c9a4617a90544ba52e1b91ea4b3b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/FireballAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/FireballAbilityBehavior.cs new file mode 100644 index 0000000..dc01e68 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/FireballAbilityBehavior.cs @@ -0,0 +1,104 @@ +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class FireballAbilityBehavior : AbilityBehavior + { + [SerializeField] GameObject fireballPrefab; + public GameObject FireballPrefab => fireballPrefab; + + private PoolComponent fireballPool; + + private Coroutine abilityCoroutine; + + private List aliveFireballs = new List(); + + private void Awake() + { + fireballPool = new PoolComponent("Fireball Ability Projectile", FireballPrefab, 6); + } + + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + if (abilityCoroutine != null) Disable(); + + abilityCoroutine = StartCoroutine(AbilityCoroutine()); + } + + private IEnumerator AbilityCoroutine() + { + while (true) + { + for(int i = 0; i < AbilityLevel.ProjectilesCount; i++) + { + var fireball = fireballPool.GetEntity(); + + fireball.transform.position = PlayerBehavior.CenterPosition; + + var closestEnemy = StageController.EnemiesSpawner.GetClosestEnemy(PlayerBehavior.CenterPosition); + + if(closestEnemy != null) + { + Vector2 direction = (closestEnemy.Center - fireball.transform.position.XY()).normalized; + fireball.transform.rotation = Quaternion.FromToRotation(Vector2.up, direction); + } else + { + fireball.transform.rotation = Quaternion.FromToRotation(Vector2.up, Random.insideUnitCircle.normalized); + } + + fireball.DamageMultiplier = AbilityLevel.Damage; + fireball.Speed = AbilityLevel.Speed; + fireball.Lifetime = AbilityLevel.FireballLifetime; + fireball.Size = AbilityLevel.ProjectileSize; + fireball.ExplosionRadius = AbilityLevel.ExplosionRadius; + + fireball.onFinished += OnFireballFinished; + + fireball.Init(); + + aliveFireballs.Add(fireball); + + yield return new WaitForSeconds(AbilityLevel.TimeBetweenFireballs); + } + + yield return new WaitForSeconds(AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier - AbilityLevel.TimeBetweenFireballs * AbilityLevel.ProjectilesCount); + } + } + + private void OnFireballFinished(FireballProjectileBehavior fireball) + { + fireball.onFinished -= OnFireballFinished; + + aliveFireballs.Remove(fireball); + } + + public void Disable() + { + StopCoroutine(abilityCoroutine); + + for(int i = 0; i < aliveFireballs.Count; i++) + { + var fireball = aliveFireballs[i]; + + fireball.onFinished -= OnFireballFinished; + + fireball.Clear(); + } + + aliveFireballs.Clear(); + } + + public override void Clear() + { + Disable(); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/FireballAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/FireballAbilityBehavior.cs.meta new file mode 100644 index 0000000..29bc39d --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/FireballAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 04cf18f0194b5304c8a1e0aa36d1afb4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/FireballAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/FireballAbilityData.cs new file mode 100644 index 0000000..541cfa9 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/FireballAbilityData.cs @@ -0,0 +1,54 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Fireball Ability Data", menuName = "October/Abilities/Active/Fireball")] + public class FireballAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.Fireball; + } + + private void OnValidate() + { + type = AbilityType.Fireball; + } + } + + [System.Serializable] + public class FireballAbilityLevel : AbilityLevel + { + [Tooltip("Amount of fireballs spawned at the same time")] + [SerializeField] int projectilesCount; + public int ProjectilesCount => projectilesCount; + + [Tooltip("Amount of time between firing fireballs in one attack")] + [SerializeField] float timeBetweenFireballs; + public float TimeBetweenFireballs => timeBetweenFireballs; + + [Tooltip("Amount of time between attacks")] + [SerializeField] float abilityCooldown; + public float AbilityCooldown => abilityCooldown; + + [Tooltip("Amount of time before fireball self destructs")] + [SerializeField] float fireballLifetime; + public float FireballLifetime => fireballLifetime; + + [Tooltip("Fireball speed")] + [SerializeField] float speed; + public float Speed => speed; + + [Tooltip("Damage of the fireball calculates as 'Damage = Player.Damage * Damage'")] + [SerializeField] float damage; + public float Damage => damage; + + [Tooltip("Scale of the fireball's transform")] + [SerializeField] float projectileSize; + public float ProjectileSize => projectileSize; + + [Tooltip("Inside this radius every enemy will be damaged")] + [SerializeField] float explosionRadius; + public float ExplosionRadius => explosionRadius; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/FireballAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/FireballAbilityData.cs.meta new file mode 100644 index 0000000..eb01ebe --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/FireballAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1586f7d6c44294444ad7f5dcc23f4e22 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/FireballProjectileBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/FireballProjectileBehavior.cs new file mode 100644 index 0000000..b33c9e3 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/FireballProjectileBehavior.cs @@ -0,0 +1,91 @@ +using OctoberStudio.Easing; +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio.Abilities +{ + public class FireballProjectileBehavior : MonoBehaviour + { + private static readonly int FIREBALL_LAUNCH_HASH = "Fireball Launch".GetHashCode(); + private static readonly int FIREBALL_EXPLOSION_HASH = "Fireball Explosion".GetHashCode(); + + [SerializeField] Collider2D fireballCollider; + + [SerializeField] ParticleSystem explosionParticle; + [SerializeField] GameObject visuals; + + private IEasingCoroutine movementCoroutine; + private IEasingCoroutine disableCoroutine; + + public float DamageMultiplier { get; set; } + public float ExplosionRadius { get; set; } + public float Lifetime { get; set; } + public float Speed { get; set; } + public float Size { get; set; } + + public event UnityAction onFinished; + + public void Init() + { + transform.localScale = Vector3.one * Size * PlayerBehavior.Player.SizeMultiplier; + + var distance = Speed * Lifetime * PlayerBehavior.Player.DurationMultiplier; + var selfDestructPosition = transform.position + transform.rotation * Vector3.up * distance; + + movementCoroutine = transform.DoPosition(selfDestructPosition, Lifetime / PlayerBehavior.Player.ProjectileSpeedMultiplier).SetOnFinish(Explode); + + visuals.SetActive(true); + fireballCollider.enabled = true; + + GameController.AudioManager.PlaySound(FIREBALL_LAUNCH_HASH); + } + + private void OnTriggerEnter2D(Collider2D other) + { + var enemy = other.GetComponent(); + + if (enemy != null) + { + movementCoroutine.Stop(); + + Explode(); + } + } + + private void Explode() + { + fireballCollider.enabled = false; + visuals.SetActive(false); + + var enemies = StageController.EnemiesSpawner.GetEnemiesInRadius(transform.position, ExplosionRadius); + + for (int i = 0; i < enemies.Count; i++) + { + var enemy = enemies[i]; + + enemy.TakeDamage(PlayerBehavior.Player.Damage * DamageMultiplier); + } + + explosionParticle.Play(); + + disableCoroutine = EasingManager.DoAfter(1f, () => + { + gameObject.SetActive(false); + onFinished?.Invoke(this); + }); + + GameController.AudioManager.PlaySound(FIREBALL_EXPLOSION_HASH); + } + + public void Clear() + { + movementCoroutine.StopIfExists(); + disableCoroutine.StopIfExists(); + + gameObject.SetActive(false); + + visuals.SetActive(true); + fireballCollider.enabled = true; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/FireballProjectileBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/FireballProjectileBehavior.cs.meta new file mode 100644 index 0000000..5564c93 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/FireBall/FireballProjectileBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f308c6edee80b9d4688478bf10f45935 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger.meta new file mode 100644 index 0000000..2d75240 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 44efe837a36e9ad458f0ffcab313dc90 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/Evolution.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/Evolution.meta new file mode 100644 index 0000000..447fc52 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/Evolution.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3ced78ec9490f6a41a36c80de00dd746 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/Evolution/TwinDaggerAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/Evolution/TwinDaggerAbilityBehavior.cs new file mode 100644 index 0000000..49927da --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/Evolution/TwinDaggerAbilityBehavior.cs @@ -0,0 +1,91 @@ +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class TwinDaggerAbilityBehavior : AbilityBehavior + { + public static readonly int TWIN_DAGGERS_HASH = "Twin Daggers Launch".GetHashCode(); + + [SerializeField] GameObject daggerPrefab; + public GameObject DaggerPrefab => daggerPrefab; + + private PoolComponent projectilePool; + + private Coroutine abilityCoroutine; + private List projectiles = new List(); + + private void Awake() + { + projectilePool = new PoolComponent("Twin Dagger Ability Projectile", DaggerPrefab, 5); + } + + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + Disable(); + + abilityCoroutine = StartCoroutine(AbilityCoroutine()); + } + + private IEnumerator AbilityCoroutine() + { + while (true) + { + for (int i = 0; i < AbilityLevel.ProjectileCount; i++) + { + var projectile = projectilePool.GetEntity(); + + projectile.transform.position = PlayerBehavior.CenterPosition; + + projectile.DamageMultiplier = AbilityLevel.Damage; + + projectile.onFinished += OnProjectileFinished; + + var angle = 360f / AbilityLevel.ProjectileCount * i; + + projectile.Init(projectile.transform.position, Quaternion.Euler(0, 0, angle) * Vector2.up); + projectile.KickBack = true; + projectiles.Add(projectile); + } + + GameController.AudioManager.PlaySound(TWIN_DAGGERS_HASH); + + yield return new WaitForSeconds(AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier); + } + } + + private void Disable() + { + if (abilityCoroutine != null) StopCoroutine(abilityCoroutine); + + for (int i = 0; i < projectiles.Count; i++) + { + var projectile = projectiles[i]; + + projectile.onFinished -= OnProjectileFinished; + + projectile.Clear(); + } + + projectiles.Clear(); + } + + private void OnProjectileFinished(SimplePlayerProjectileBehavior projectile) + { + projectile.onFinished -= OnProjectileFinished; + + projectiles.Remove(projectile); + } + + public override void Clear() + { + Disable(); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/Evolution/TwinDaggerAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/Evolution/TwinDaggerAbilityBehavior.cs.meta new file mode 100644 index 0000000..984f93b --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/Evolution/TwinDaggerAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9a9c4de779c766c4abfcd16b5a5f30e6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/Evolution/TwinDaggerAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/Evolution/TwinDaggerAbilityData.cs new file mode 100644 index 0000000..eb3c2c2 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/Evolution/TwinDaggerAbilityData.cs @@ -0,0 +1,34 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Twin Daggers Ability Data", menuName = "October/Abilities/Evolution/Twin Daggers")] + public class TwinDaggerAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.TwinDagger; + } + + private void OnValidate() + { + type = AbilityType.TwinDagger; + } + } + + [System.Serializable] + public class TwinDaggerAbilityLevel : AbilityLevel + { + [Tooltip("Amount of daggers spawned at the same time")] + [SerializeField] int projectileCount; + public int ProjectileCount => projectileCount; + + [Tooltip("Amount of time between attacks")] + [SerializeField] float abilityCooldown; + public float AbilityCooldown => abilityCooldown; + + [Tooltip("Damage of the boomerang calculates as 'Damage = Player.Damage * Damage'")] + [SerializeField] float damage; + public float Damage => damage; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/Evolution/TwinDaggerAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/Evolution/TwinDaggerAbilityData.cs.meta new file mode 100644 index 0000000..b0f1def --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/Evolution/TwinDaggerAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1159afb2b20d9cf4381fdee01a422901 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/FlyingDaggerAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/FlyingDaggerAbilityBehavior.cs new file mode 100644 index 0000000..fe5386f --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/FlyingDaggerAbilityBehavior.cs @@ -0,0 +1,92 @@ +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class FlyingDaggerAbilityBehavior : AbilityBehavior + { + [SerializeField] GameObject daggerPrefab; + public GameObject DaggerPrefab => daggerPrefab; + + private PoolComponent projectilePool; + + private Coroutine abilityCoroutine; + private List projectiles = new List(); + + private void Awake() + { + projectilePool = new PoolComponent("Flying Dagger Ability Projectile", DaggerPrefab, 5); + } + + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + Disable(); + + abilityCoroutine = StartCoroutine(AbilityCoroutine()); + } + + private IEnumerator AbilityCoroutine() + { + while (true) + { + for (int i = 0; i < AbilityLevel.ProjectileCount; i++) + { + var projectile = projectilePool.GetEntity(); + + projectile.transform.position = PlayerBehavior.CenterPosition; + + var deviation = AbilityLevel.Spread / 2f; + Vector3 direction = Quaternion.Euler(0, 0, Random.Range(-deviation, deviation)) * Vector2.up; + + projectile.DamageMultiplier = AbilityLevel.Damage; + projectile.ProjectileLifetime = AbilityLevel.ProjectileLifetime; + projectile.Size = AbilityLevel.ProjectileSize; + + projectile.onFinished += OnDaggerFinished; + + projectile.Spawn(direction * AbilityLevel.ThrowingForce * PlayerBehavior.Player.ProjectileSpeedMultiplier); + + projectiles.Add(projectile); + + yield return new WaitForSeconds(AbilityLevel.TimeBetweenProjectiles); + } + + yield return new WaitForSeconds(AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier - AbilityLevel.TimeBetweenProjectiles * AbilityLevel.ProjectileCount); + } + } + + private void Disable() + { + if (abilityCoroutine != null) StopCoroutine(abilityCoroutine); + + for (int i = 0; i < projectiles.Count; i++) + { + var projectile = projectiles[i]; + + projectile.onFinished -= OnDaggerFinished; + + projectile.Disable(); + } + + projectiles.Clear(); + } + + private void OnDaggerFinished(FlyingDaggerProjectileBehavior dagger) + { + dagger.onFinished -= OnDaggerFinished; + + projectiles.Remove(dagger); + } + + public override void Clear() + { + Disable(); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/FlyingDaggerAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/FlyingDaggerAbilityBehavior.cs.meta new file mode 100644 index 0000000..5375870 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/FlyingDaggerAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6b8476c5980d70044ab89a8e5ea9e5bd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/FlyingDaggerAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/FlyingDaggerAbilityData.cs new file mode 100644 index 0000000..40782da --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/FlyingDaggerAbilityData.cs @@ -0,0 +1,54 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Flying Dagger Ability Data", menuName = "October/Abilities/Active/Flying Dagger")] + public class FlyingDaggerAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.FlyingDagger; + } + + private void OnValidate() + { + type = AbilityType.FlyingDagger; + } + } + + [System.Serializable] + public class FlyingDaggerAbilityLevel : AbilityLevel + { + [Tooltip("Amount of daggers spawned at the same time")] + [SerializeField] int projectileCount; + public int ProjectileCount => projectileCount; + + [Tooltip("Amount of time before dagger disappears")] + [SerializeField] float projectileLifetime; + public float ProjectileLifetime => projectileLifetime; + + [Tooltip("Amount of time between throwig daggers in one attack")] + [SerializeField] float timeBetweenProjectiles; + public float TimeBetweenProjectiles => timeBetweenProjectiles; + + [Tooltip("Amount of time between attacks")] + [SerializeField] float abilityCooldown; + public float AbilityCooldown => abilityCooldown; + + [Tooltip("Force that will be applied to the dagger's rigidbody")] + [SerializeField] float throwingForce; + public float ThrowingForce => throwingForce; + + [Tooltip("How much will the throwing force deviate from the Vector2.up vector")] + [SerializeField] float spread; + public float Spread => spread; + + [Tooltip("Damage of the boomerang calculates as 'Damage = Player.Damage * Damage'")] + [SerializeField] float damage; + public float Damage => damage; + + [Tooltip("Size of the boomerang")] + [SerializeField] float projectileSize; + public float ProjectileSize => projectileSize; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/FlyingDaggerAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/FlyingDaggerAbilityData.cs.meta new file mode 100644 index 0000000..683a29a --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/FlyingDaggerAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ca844530d09d39247b276cdc829f2c85 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/FlyingDaggerProjectileBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/FlyingDaggerProjectileBehavior.cs new file mode 100644 index 0000000..0c98361 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/FlyingDaggerProjectileBehavior.cs @@ -0,0 +1,48 @@ +using OctoberStudio.Easing; +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio.Abilities +{ + public class FlyingDaggerProjectileBehavior : ProjectileBehavior + { + private static readonly int FLYING_DAGGER_LAUNCH_HASH = "Flying Dagger Launch".GetHashCode(); + + [SerializeField] Rigidbody2D rigidBody; + + public UnityAction onFinished; + + private IEasingCoroutine movementCoroutine; + + public float ProjectileLifetime { get; set; } + public float Size { get; set; } + + public void Spawn(Vector2 force) + { + Init(); + transform.localScale = Vector3.one * Size * PlayerBehavior.Player.SizeMultiplier; + + KickBack = true; + + rigidBody.velocity = Vector2.zero; + rigidBody.angularVelocity = 0; + + transform.rotation = Quaternion.identity; + + rigidBody.AddForce(force, ForceMode2D.Impulse); + + movementCoroutine = EasingManager.DoAfter(ProjectileLifetime, () => { + onFinished?.Invoke(this); + Disable(); + }); + + GameController.AudioManager.PlaySound(FLYING_DAGGER_LAUNCH_HASH); + } + + public void Disable() + { + movementCoroutine.StopIfExists(); + gameObject.SetActive(false); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/FlyingDaggerProjectileBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/FlyingDaggerProjectileBehavior.cs.meta new file mode 100644 index 0000000..73c6e50 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Flying Dagger/FlyingDaggerProjectileBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cb5a7568fb5f45940814f8055b6849d6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field.meta new file mode 100644 index 0000000..0f00bd7 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1e8218e88699a104da3bb59e97878bce +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/Evolution.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/Evolution.meta new file mode 100644 index 0000000..e338dbd --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/Evolution.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 98185b2b02825f14eb755656daee4d7f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/Evolution/TimeGazerAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/Evolution/TimeGazerAbilityData.cs new file mode 100644 index 0000000..da82e21 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/Evolution/TimeGazerAbilityData.cs @@ -0,0 +1,38 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Time Gazer Ability Data", menuName = "October/Abilities/Evolution/Time Gazer")] + public class TimeGazerAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.TimeGazer; + } + + private void OnValidate() + { + type = AbilityType.TimeGazer; + } + } + + [System.Serializable] + public class TimeGazerAbilityLevel : AbilityLevel + { + [Tooltip("The size of the timezone")] + [SerializeField, Min(0.1f)] float fieldRadius = 0.5f; + public float FieldRadius => fieldRadius; + + [Tooltip("Enemies inside timezone will move slower")] + [SerializeField, Min(0.1f)] float slowDownMultiplier = 0.5f; + public float SlowDownMultiplier => slowDownMultiplier; + + [Tooltip("The damage of the timezone. Multiplier by Player damage.")] + [SerializeField, Min(0.1f)] float damage = 1f; + public float Damage => damage; + + [Tooltip("Enemy will take damage every 'damageCooldown' seconds")] + [SerializeField, Min(0f)] float damageCooldown; + public float DamageCooldown => damageCooldown; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/Evolution/TimeGazerAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/Evolution/TimeGazerAbilityData.cs.meta new file mode 100644 index 0000000..3e8e231 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/Evolution/TimeGazerAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 991052d635f55094a817218699c72c87 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/Evolution/TimeZoneAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/Evolution/TimeZoneAbilityBehavior.cs new file mode 100644 index 0000000..a1d95d8 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/Evolution/TimeZoneAbilityBehavior.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class TimeZoneAbilityBehavior : AbilityBehavior + { + public static readonly int TIME_GAZER_HASH = "Time Gazer".GetHashCode(); + + [SerializeField] CircleCollider2D abilityCollider; + [SerializeField] Transform visuals; + + private Dictionary enemies = new Dictionary(); + + private Effect slowDownEffect; + + private float lastTimeSound; + + private void Awake() + { + slowDownEffect = new Effect(EffectType.Speed, 1); + lastTimeSound = -100; + } + + public override void Init(AbilityData data, int stageId) + { + base.Init(data, stageId); + + slowDownEffect.SetModifier(AbilityLevel.SlowDownMultiplier); + } + + private void LateUpdate() + { + transform.position = PlayerBehavior.CenterPosition; + + visuals.localScale = Vector2.one * AbilityLevel.FieldRadius * 2 * PlayerBehavior.Player.SizeMultiplier; + abilityCollider.radius = AbilityLevel.FieldRadius * PlayerBehavior.Player.SizeMultiplier; + + if(Time.time - lastTimeSound > 5) + { + lastTimeSound = Time.time; + + GameController.AudioManager.PlaySound(TIME_GAZER_HASH); + } + } + + private void OnTriggerEnter2D(Collider2D collision) + { + EnemyBehavior enemy = collision.GetComponent(); + + if (!enemies.ContainsKey(enemy)) + { + enemies.Add(enemy, Time.time); + + enemy.TakeDamage(AbilityLevel.Damage * PlayerBehavior.Player.Damage); + + enemy.AddEffect(slowDownEffect); + } + } + + private void Update() + { + foreach (var enemy in enemies.Keys.ToList()) + { + float time = enemies[enemy]; + + if (Time.time - time > AbilityLevel.DamageCooldown * PlayerBehavior.Player.CooldownMultiplier) + { + enemies[enemy] = Time.time; + + enemy.TakeDamage(AbilityLevel.Damage * PlayerBehavior.Player.Damage); + } + } + } + + private void OnTriggerExit2D(Collider2D collision) + { + EnemyBehavior enemy = collision.GetComponent(); + + if (enemies.ContainsKey(enemy)) + { + enemies.Remove(enemy); + + enemy.RemoveEffect(slowDownEffect); + } + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/Evolution/TimeZoneAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/Evolution/TimeZoneAbilityBehavior.cs.meta new file mode 100644 index 0000000..79d0029 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/Evolution/TimeZoneAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 64187ca78fc81004594da5f0b3e824ef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/GuardianEyeAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/GuardianEyeAbilityBehavior.cs new file mode 100644 index 0000000..a74fa87 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/GuardianEyeAbilityBehavior.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class GuardianEyeAbilityBehavior : AbilityBehavior + { + private static readonly int GUARDIAN_EYE_HASH = "Guardian Eye".GetHashCode(); + + [SerializeField] CircleCollider2D abilityCollider; + [SerializeField] Transform visuals; + + private Dictionary enemies = new Dictionary(); + + private float lastTimeSound; + + private void Awake() + { + lastTimeSound = -100; + } + + private void LateUpdate() + { + transform.position = PlayerBehavior.CenterPosition; + + visuals.localScale = Vector2.one * AbilityLevel.FieldRadius * 2 * PlayerBehavior.Player.SizeMultiplier; + abilityCollider.radius = AbilityLevel.FieldRadius * PlayerBehavior.Player.SizeMultiplier; + } + + private void OnTriggerEnter2D(Collider2D collision) + { + EnemyBehavior enemy = collision.GetComponent(); + + if (!enemies.ContainsKey(enemy)) + { + enemies.Add(enemy, Time.time); + + enemy.TakeDamage(AbilityLevel.Damage * PlayerBehavior.Player.Damage); + } + } + + private void Update() + { + foreach (var enemy in enemies.Keys.ToList()) + { + float time = enemies[enemy]; + + if(Time.time - time > AbilityLevel.DamageCooldown * PlayerBehavior.Player.CooldownMultiplier) + { + enemies[enemy] = Time.time; + + enemy.TakeDamage(AbilityLevel.Damage * PlayerBehavior.Player.Damage); + } + } + + if(Time.time - lastTimeSound > 5f) + { + lastTimeSound = Time.time; + + GameController.AudioManager.PlaySound(GUARDIAN_EYE_HASH); + } + } + + private void OnTriggerExit2D(Collider2D collision) + { + EnemyBehavior enemy = collision.GetComponent(); + + if (enemies.ContainsKey(enemy)) + { + enemies.Remove(enemy); + } + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/GuardianEyeAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/GuardianEyeAbilityBehavior.cs.meta new file mode 100644 index 0000000..881c332 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/GuardianEyeAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b7a197174524e5f4a8bad800afd34093 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/GuardianEyeAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/GuardianEyeAbilityData.cs new file mode 100644 index 0000000..23801a7 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/GuardianEyeAbilityData.cs @@ -0,0 +1,34 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Guardian Eye Ability Data", menuName = "October/Abilities/Active/Guardian Eye")] + public class GuardianEyeAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.GuardianEye; + } + + private void OnValidate() + { + type = AbilityType.GuardianEye; + } + } + + [System.Serializable] + public class GuardianEyeAbilityLevel : AbilityLevel + { + [Tooltip("The size of the forcefield")] + [SerializeField, Min(0.1f)] float fieldRadius = 0.5f; + public float FieldRadius => fieldRadius; + + [Tooltip("The damage of the forceField. Multiplier by Player damage.")] + [SerializeField, Min(0.1f)] float damage = 1f; + public float Damage => damage; + + [Tooltip("Enemy will take damage every 'damageCooldown' seconds")] + [SerializeField, Min(0f)] float damageCooldown; + public float DamageCooldown => damageCooldown; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/GuardianEyeAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/GuardianEyeAbilityData.cs.meta new file mode 100644 index 0000000..d0cee9e --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Force Field/GuardianEyeAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cee9e708d20778f40be895baad2b4eee +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard.meta new file mode 100644 index 0000000..537d1da --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 86c87d3067172204d98c3bc06d8082d9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/Evolution.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/Evolution.meta new file mode 100644 index 0000000..f2db065 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/Evolution.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2b2cb1437014dee46ae313ad1c4a5ed0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/Evolution/SilverStakesAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/Evolution/SilverStakesAbilityBehavior.cs new file mode 100644 index 0000000..10241ab --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/Evolution/SilverStakesAbilityBehavior.cs @@ -0,0 +1,59 @@ +using OctoberStudio.Easing; +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class SilverStakesAbilityBehavior : AbilityBehavior + { + public static readonly int SILVER_STAKES_LAUNCH_HASH = "Silver Stakes Launch".GetHashCode(); + + [SerializeField] GameObject silverShardPrefab; + public GameObject SilverShardPrefab => silverShardPrefab; + + private PoolComponent projectilePool; + public List projectiles = new List(); + + private void Awake() + { + projectilePool = new PoolComponent("Quick Silver Projectiule", SilverShardPrefab, 6); + } + + public override void Init(AbilityData data, int stageId) + { + base.Init(data, stageId); + + for (int i = 0; i < AbilityLevel.ProjectilesCount; i++) + { + var projectile = projectilePool.GetEntity(); + + projectile.transform.position = PlayerBehavior.CenterPosition; + projectile.SetData(AbilityLevel.ProjectileSize, AbilityLevel.Damage, AbilityLevel.ProjectileSpeed); + projectile.Direction = Random.onUnitSphere.SetZ(0).normalized; + + projectiles.Add(projectile); + } + + GameController.AudioManager.PlaySound(SILVER_STAKES_LAUNCH_HASH); + } + + private void Disable() + { + for (int i = 0; i < projectiles.Count; i++) + { + projectiles[i].gameObject.SetActive(false); + } + + projectiles.Clear(); + } + + public override void Clear() + { + Disable(); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/Evolution/SilverStakesAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/Evolution/SilverStakesAbilityBehavior.cs.meta new file mode 100644 index 0000000..41b88ac --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/Evolution/SilverStakesAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8aa94fd95fc02e14dae6f2687f4dea8f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/Evolution/SilverStakesAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/Evolution/SilverStakesAbilityData.cs new file mode 100644 index 0000000..892de71 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/Evolution/SilverStakesAbilityData.cs @@ -0,0 +1,38 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Silver Stakes Data", menuName = "October/Abilities/Evolution/Silver Stakes")] + public class SilverStakesAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.SilverStakes; + } + + private void OnValidate() + { + type = AbilityType.SilverStakes; + } + } + + [System.Serializable] + public class SilverStakesAbilityLevel : AbilityLevel + { + [Tooltip("Speed of silver shards")] + [SerializeField] float projectileSpeed; + public float ProjectileSpeed => projectileSpeed; + + [Tooltip("Damage of silver shards calculates like this: Player.Damage * Damage")] + [SerializeField] float damage; + public float Damage => damage; + + [Tooltip("Size of silver shards")] + [SerializeField] float projectileSize; + public float ProjectileSize => projectileSize; + + [Tooltip("Amount of silver shards")] + [SerializeField] int projectilesCount; + public int ProjectilesCount => projectilesCount; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/Evolution/SilverStakesAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/Evolution/SilverStakesAbilityData.cs.meta new file mode 100644 index 0000000..4e10dd8 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/Evolution/SilverStakesAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a3f0c3b47c29b524683086d39bed3a7d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/IceShardAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/IceShardAbilityBehavior.cs new file mode 100644 index 0000000..2a2f8a6 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/IceShardAbilityBehavior.cs @@ -0,0 +1,92 @@ +using OctoberStudio.Easing; +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class IceShardAbilityBehavior : AbilityBehavior + { + private static readonly int ICE_SHARD_LAUNCH_HASH = "Ice Shard Launch".GetHashCode(); + + [SerializeField] GameObject iceShardPrefab; + public GameObject IceShardPrefab => iceShardPrefab; + + private PoolComponent projectilePool; + public List projectiles = new List(); + + IEasingCoroutine projectileCoroutine; + Coroutine abilityCoroutine; + + private void Awake() + { + projectilePool = new PoolComponent("Ice Shard Projectiule", IceShardPrefab, 6); + } + + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + if (abilityCoroutine != null) Disable(); + + abilityCoroutine = StartCoroutine(AbilityCoroutine()); + } + + private IEnumerator AbilityCoroutine() + { + while (true) + { + var newProjectiles = new List(); + + for (int i = 0; i < AbilityLevel.ProjectilesCount; i++) + { + var projectile = projectilePool.GetEntity(); + + projectile.transform.position = PlayerBehavior.CenterPosition; + projectile.SetData(AbilityLevel.ProjectileSize, AbilityLevel.Damage, AbilityLevel.ProjectileSpeed); + projectile.Direction = Random.onUnitSphere.SetZ(0).normalized; + + projectiles.Add(projectile); + newProjectiles.Add(projectile); + } + + GameController.AudioManager.PlaySound(ICE_SHARD_LAUNCH_HASH); + + projectileCoroutine = EasingManager.DoAfter(AbilityLevel.ProjectileLifetime * PlayerBehavior.Player.DurationMultiplier, () => { + for (int i = 0; i < newProjectiles.Count; i++) + { + newProjectiles[i].gameObject.SetActive(false); + projectiles.Remove(newProjectiles[i]); + } + + newProjectiles.Clear(); + }); + + yield return new WaitForSeconds(AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier); + } + } + + private void Disable() + { + projectileCoroutine.StopIfExists(); + + for (int i = 0; i < projectiles.Count; i++) + { + projectiles[i].gameObject.SetActive(false); + } + + projectiles.Clear(); + + StopCoroutine(abilityCoroutine); + } + + public override void Clear() + { + Disable(); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/IceShardAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/IceShardAbilityBehavior.cs.meta new file mode 100644 index 0000000..3007460 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/IceShardAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4c116e412d977804b8dd58a955aa8bae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/IceShardAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/IceShardAbilityData.cs new file mode 100644 index 0000000..3f2f36b --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/IceShardAbilityData.cs @@ -0,0 +1,46 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Ice Shard Data", menuName = "October/Abilities/Active/Ice Shard")] + public class IceShardAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.IceShard; + } + + private void OnValidate() + { + type = AbilityType.IceShard; + } + } + + [System.Serializable] + public class IceShardAbilityLevel : AbilityLevel + { + [Tooltip("Ice shards spawn every 'AbilityCooldown' seconds")] + [SerializeField] float abilityCooldown; + public float AbilityCooldown => abilityCooldown; + + [Tooltip("Speed of ice shards")] + [SerializeField] float projectileSpeed; + public float ProjectileSpeed => projectileSpeed; + + [Tooltip("Damage of ice shards calculates like this: Player.Damage * Damage")] + [SerializeField] float damage; + public float Damage => damage; + + [Tooltip("Size of ice shards")] + [SerializeField] float projectileSize; + public float ProjectileSize => projectileSize; + + [Tooltip("Amount of ice shards")] + [SerializeField] int projectilesCount; + public int ProjectilesCount => projectilesCount; + + [Tooltip("Time ice shards stay alive")] + [SerializeField] float projectileLifetime; + public float ProjectileLifetime => projectileLifetime; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/IceShardAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/IceShardAbilityData.cs.meta new file mode 100644 index 0000000..ce28162 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/IceShardAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a6efdef0c11be664597b6b3c59fb6057 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/IceShardProjectileBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/IceShardProjectileBehavior.cs new file mode 100644 index 0000000..a36e956 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/IceShardProjectileBehavior.cs @@ -0,0 +1,31 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class IceShardProjectileBehavior : CameraSpaceProjectile + { + [SerializeField] BoxCollider2D boxCollider; + + public override Rect GetBounds() + { + var center = transform.position + transform.rotation * boxCollider.offset; + return new Rect(center, transform.rotation * boxCollider.size); + } + + public void SetData(float size, float damageMultiplier, float speed) + { + transform.localScale = Vector3.one * size * PlayerBehavior.Player.SizeMultiplier; + + DamageMultiplier = damageMultiplier; + + Speed = speed; + } + + public override void Update() + { + base.Update(); + + transform.rotation = Quaternion.FromToRotation(Vector3.up, Direction); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/IceShardProjectileBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/IceShardProjectileBehavior.cs.meta new file mode 100644 index 0000000..6f821da --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Ice Shard/IceShardProjectileBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d567f688e7cc05f43952ac72203bc596 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning.meta new file mode 100644 index 0000000..eff5069 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 905331e0bb0004a4aa49f7c1e4baa872 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/Evolution.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/Evolution.meta new file mode 100644 index 0000000..1134ace --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/Evolution.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3cbdd40693adf4447b347d6be7c42515 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/Evolution/ThunderRingAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/Evolution/ThunderRingAbilityBehavior.cs new file mode 100644 index 0000000..720ce21 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/Evolution/ThunderRingAbilityBehavior.cs @@ -0,0 +1,109 @@ +using OctoberStudio.Easing; +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class ThunderRingAbilityBehavior : AbilityBehavior + { + public static readonly int THUNDER_RING_STRIKE_HASH = "Thunder Ring Strike".GetHashCode(); + + [SerializeField] GameObject lightningPrefab; + public GameObject LightningPrefab => lightningPrefab; + + [SerializeField] GameObject ballLightningPrefab; + public GameObject BallLightningPrefab => ballLightningPrefab; + + public PoolComponent lightningPool; + public PoolComponent ballLightningPool; + + private Coroutine abilityCoroutine; + + private List easingCoroutines = new List(); + + private void Awake() + { + lightningPool = new PoolComponent("Ball Lightning ability particle", LightningPrefab, 6); + ballLightningPool = new PoolComponent("Ball Lightning Secondary Projectile", BallLightningPrefab, 6); + } + + public override void Init(AbilityData data, int stageId) + { + base.Init(data, stageId); + + abilityCoroutine = StartCoroutine(AbilityCoroutine()); + } + + private IEnumerator AbilityCoroutine() + { + while (true) + { + for (int i = 0; i < AbilityLevel.LightningsCount; i++) + { + yield return new WaitForSeconds(AbilityLevel.DurationBetweenHits); + + var particle = lightningPool.GetEntity(); + + var spawner = StageController.EnemiesSpawner; + var enemy = spawner.GetRandomVisibleEnemy(); + + if (enemy != null) + { + particle.transform.position = enemy.transform.position; + + enemy.TakeDamage(PlayerBehavior.Player.Damage * AbilityLevel.Damage); + } + else + { + particle.transform.position = PlayerBehavior.Player.transform.position + Vector3.up + Vector3.left; + } + + float angle = Random.Range(0, 180f); + + for (int j = 0; j < AbilityLevel.BallLightningCount; j++) + { + var ball = ballLightningPool.GetEntity(); + + angle += 360f / AbilityLevel.BallLightningCount; + + ball.Init(particle.transform.position, Quaternion.Euler(0, 0, angle) * Vector2.up); + + ball.DamageMultiplier = AbilityLevel.BallDamage; + ball.KickBack = false; + } + + IEasingCoroutine easingCoroutine = null; + easingCoroutine = EasingManager.DoAfter(1, () => + { + particle.gameObject.SetActive(false); + easingCoroutines.Remove(easingCoroutine); + }); + + easingCoroutines.Add(easingCoroutine); + + GameController.AudioManager.PlaySound(THUNDER_RING_STRIKE_HASH); + } + + yield return new WaitForSeconds(AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier - AbilityLevel.DurationBetweenHits); + } + } + + public override void Clear() + { + StopCoroutine(abilityCoroutine); + + for(int i = 0; i < easingCoroutines.Count; i++) + { + var easingCoroutine = easingCoroutines[i]; + if (easingCoroutine.ExistsAndActive()) easingCoroutine.Stop(); + } + + lightningPool.Destroy(); + ballLightningPool.Destroy(); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/Evolution/ThunderRingAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/Evolution/ThunderRingAbilityBehavior.cs.meta new file mode 100644 index 0000000..d96c5a1 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/Evolution/ThunderRingAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6b5f937ece3a33046a2cfc47c0f38dfc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/Evolution/ThunderRingAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/Evolution/ThunderRingAbilityData.cs new file mode 100644 index 0000000..52d2a8c --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/Evolution/ThunderRingAbilityData.cs @@ -0,0 +1,46 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Thunder Ring Ability Data", menuName = "October/Abilities/Evolution/Thunder Ring")] + public class ThunderRingAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.ThunderRing; + } + + private void OnValidate() + { + type = AbilityType.ThunderRing; + } + } + + [System.Serializable] + public class ThunderRingAbilityLevel : AbilityLevel + { + [Tooltip("This value is multiplied by the damage of the player")] + [SerializeField, Min(0.1f)] float damage = 1f; + public float Damage => damage; + + [Tooltip("The damage multiplier of the secondary projhectiles")] + [SerializeField, Min(0.1f)] float ballDamage = 1f; + public float BallDamage => ballDamage; + + [Tooltip("Amount of lightnings in one attack")] + [SerializeField, Min(1)] int lightningsCount = 1; + public int LightningsCount => lightningsCount; + + [Tooltip("Amount of additional projectiles")] + [SerializeField, Min(1)] int ballLightningCount = 1; + public int BallLightningCount => ballLightningCount; + + [Tooltip("Amount of time between attacks")] + [SerializeField] float abilityCooldown; + public float AbilityCooldown => abilityCooldown; + + [Tooltip("Amount of time between lightnings")] + [SerializeField] float durationBetweenHits; + public float DurationBetweenHits => durationBetweenHits; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/Evolution/ThunderRingAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/Evolution/ThunderRingAbilityData.cs.meta new file mode 100644 index 0000000..94f42dc --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/Evolution/ThunderRingAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dea7316e62ac85f4a8da77488f201efb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/LightningAmuletAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/LightningAmuletAbilityBehavior.cs new file mode 100644 index 0000000..49c3233 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/LightningAmuletAbilityBehavior.cs @@ -0,0 +1,95 @@ +using OctoberStudio.Easing; +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class LightningAmuletAbilityBehavior : AbilityBehavior + { + private static readonly int LIGHTNING_AMULET_HASH = "Lightning Amulet".GetHashCode(); + + [SerializeField] GameObject lightningPrefab; + public GameObject LightningPrefab => lightningPrefab; + + public PoolComponent lightningPool; + + private List easingCoroutines = new List(); + + private Coroutine abilityCoroutine; + + private void Awake() + { + lightningPool = new PoolComponent("Lightning ability particle", LightningPrefab, 6); + } + + public override void Init(AbilityData data, int stageId) + { + base.Init(data, stageId); + + abilityCoroutine = StartCoroutine(AbilityCoroutine()); + } + + private IEnumerator AbilityCoroutine() + { + while (true) + { + for(int i = 0; i < AbilityLevel.LightningsCount; i++) + { + yield return new WaitForSeconds(AbilityLevel.DurationBetweenHits); + + var particle = lightningPool.GetEntity(); + + var spawner = StageController.EnemiesSpawner; + var enemy = spawner.GetRandomVisibleEnemy(); + + if(enemy != null) + { + particle.transform.position = enemy.transform.position; + + enemy.TakeDamage(PlayerBehavior.Player.Damage * AbilityLevel.Damage); + + var enemiesInRadius = StageController.EnemiesSpawner.GetEnemiesInRadius(enemy.transform.position, AbilityLevel.AdditionalDamageRadius); + + foreach(var closeEnemy in enemiesInRadius) + { + if (closeEnemy != enemy) closeEnemy.TakeDamage(PlayerBehavior.Player.Damage * AbilityLevel.AdditionalDamage); + } + } else + { + particle.transform.position = PlayerBehavior.Player.transform.position + Vector3.up + Vector3.left; + } + + IEasingCoroutine easingCoroutine = null; + easingCoroutine = EasingManager.DoAfter(1, () => + { + particle.gameObject.SetActive(false); + easingCoroutines.Remove(easingCoroutine); + }); + + easingCoroutines.Add(easingCoroutine); + + GameController.AudioManager.PlaySound(LIGHTNING_AMULET_HASH); + } + + yield return new WaitForSeconds(AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier - AbilityLevel.DurationBetweenHits); + } + } + + public override void Clear() + { + StopCoroutine(abilityCoroutine); + + for (int i = 0; i < easingCoroutines.Count; i++) + { + var easingCoroutine = easingCoroutines[i]; + if (easingCoroutine.ExistsAndActive()) easingCoroutine.Stop(); + } + + lightningPool.Destroy(); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/LightningAmuletAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/LightningAmuletAbilityBehavior.cs.meta new file mode 100644 index 0000000..e17cbc4 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/LightningAmuletAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d18a95848ddd2104ebb802aef7784e64 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/LightningAmuletAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/LightningAmuletAbilityData.cs new file mode 100644 index 0000000..c2c557c --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/LightningAmuletAbilityData.cs @@ -0,0 +1,46 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Lightning Amulet Ability Data", menuName = "October/Abilities/Active/Lightning Amulet")] + public class LightningAmuletAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.LightningAmulet; + } + + private void OnValidate() + { + type = AbilityType.LightningAmulet; + } + } + + [System.Serializable] + public class LightningAmuletAbilityLevel : AbilityLevel + { + [Tooltip("This value is multiplied by the damage of the player")] + [SerializeField, Min(0.1f)] float damage = 1f; + public float Damage => damage; + + [Tooltip("This damage will be done to any enemy in radius")] + [SerializeField, Min(0.1f)] float additionalDamage; + public float AdditionalDamage => additionalDamage; + + [Tooltip("This is the radius in which every enemy will get the additional damage")] + [SerializeField, Min(0.01f)] float additionalDamageRadius; + public float AdditionalDamageRadius => additionalDamageRadius; + + [Tooltip("Amount of lightnings in one attack")] + [SerializeField, Min(1)] int lightningsCount = 1; + public int LightningsCount => lightningsCount; + + [Tooltip("Amount of time between attacks")] + [SerializeField] float abilityCooldown; + public float AbilityCooldown => abilityCooldown; + + [Tooltip("Amount of time between lightnings")] + [SerializeField] float durationBetweenHits; + public float DurationBetweenHits => durationBetweenHits; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/LightningAmuletAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/LightningAmuletAbilityData.cs.meta new file mode 100644 index 0000000..93c03d8 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Lightning/LightningAmuletAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 42aa83e6078ee1941b2f913d17e7c367 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune.meta new file mode 100644 index 0000000..0dcf5f9 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 213fcc0e0f00f7c40a4be1079fdb2570 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution.meta new file mode 100644 index 0000000..bcafb7b --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 554b453408cc9a34a9470f3d10f786df +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution/SpikyTrapAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution/SpikyTrapAbilityBehavior.cs new file mode 100644 index 0000000..fe783f9 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution/SpikyTrapAbilityBehavior.cs @@ -0,0 +1,52 @@ +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using System.Collections; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class SpikyTrapAbilityBehavior : AbilityBehavior + { + public static readonly int SPIKY_TRAP_SET_UP_HASH = "Spiky Trap Set Up".GetHashCode(); + + [SerializeField] GameObject spikyTrapPrefab; + public GameObject SpikyTrapPrefab => spikyTrapPrefab; + + [SerializeField] GameObject spikeBehavior; + public GameObject SpikeBehavior => spikeBehavior; + + private PoolComponent trapPool; + private PoolComponent spikePool; + + private void Awake() + { + trapPool = new PoolComponent("Spiky Trap Mine", SpikyTrapPrefab, 6); + spikePool = new PoolComponent("Spiky Trap Mine Spike", SpikeBehavior, 6); + } + + public override void Init(AbilityData data, int stageId) + { + base.Init(data, stageId); + + StartCoroutine(AbilityCoroutine()); + } + + private IEnumerator AbilityCoroutine() + { + while (true) + { + for (int i = 0; i < AbilityLevel.MinesCount; i++) + { + var mine = trapPool.GetEntity(); + + mine.transform.position = PlayerBehavior.CenterPosition + Random.onUnitSphere.XY().normalized * AbilityLevel.MineSpawnRadius * Random.Range(0.9f, 1.1f); + mine.SetData(AbilityLevel, spikePool); + } + + GameController.AudioManager.PlaySound(SPIKY_TRAP_SET_UP_HASH); + + yield return new WaitForSeconds(AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier); + } + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution/SpikyTrapAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution/SpikyTrapAbilityBehavior.cs.meta new file mode 100644 index 0000000..c06d03c --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution/SpikyTrapAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 857c2e2b7d696d24ba1e23725b65142a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution/SpikyTrapAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution/SpikyTrapAbilityData.cs new file mode 100644 index 0000000..d3b5dcb --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution/SpikyTrapAbilityData.cs @@ -0,0 +1,62 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Spiky Trap Ability Data", menuName = "October/Abilities/Evolution/Spiky Trap")] + public class SpikyTrapAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.SpikyTrap; + } + + private void OnValidate() + { + type = AbilityType.SpikyTrap; + } + } + + [System.Serializable] + public class SpikyTrapAbilityLevel : AbilityLevel + { + [Tooltip("Amount of mines that are spawned at the time")] + [SerializeField, Min(1f)] int minesCount = 1; + public int MinesCount => minesCount; + + [Tooltip("Amount of spikes that shppt after an explosion")] + [SerializeField, Min(1f)] int spikesCount = 6; + public int SpikesCount => spikesCount; + + [Tooltip("Amount of time between spawning mines")] + [SerializeField, Min(0.01f)] float abilityCooldown = 7; + public float AbilityCooldown => abilityCooldown; + + [Tooltip("Distance between the player and the mine spawn position")] + [SerializeField, Min(0)] float mineSpawnRadius; + public float MineSpawnRadius => mineSpawnRadius; + + [Tooltip("Amount of time before mine selfdestructs")] + [SerializeField, Min(0.01f)] float mineLifetime = 10; + public float MineLifetime => mineLifetime; + + [Tooltip("Damage of the mine calculates as 'Damage = Player.Damage * Damage'")] + [SerializeField, Min(0.01f)] float damage = 10; + public float Damage => damage; + + [Tooltip("Damage of the spike calculates as 'Damage = Player.Damage * SpikeDamage'")] + [SerializeField, Min(0.01f)] float spikeDamage = 10; + public float SpikeDamage => spikeDamage; + + [Tooltip("Scale of the mine's transform")] + [SerializeField, Min(0.1f)] float mineSize = 1; + public float MineSize => mineSize; + + [Tooltip("Max distance between the mine and the enemy that detonated the mine")] + [SerializeField, Min(0.1f)] float mineTriggerRadius = 1; + public float MineTriggerRadius => mineTriggerRadius; + + [Tooltip("Max distance between the mine and the enemy for the latter to be damaged")] + [SerializeField, Min(0.1f)] float mineDamageRadius = 1; + public float MineDamageRadius => mineDamageRadius; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution/SpikyTrapAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution/SpikyTrapAbilityData.cs.meta new file mode 100644 index 0000000..aed9edd --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution/SpikyTrapAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dd2ff9c5e3dc05c43a421319f81de6d2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution/SpikyTrapBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution/SpikyTrapBehavior.cs new file mode 100644 index 0000000..e3d86c9 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution/SpikyTrapBehavior.cs @@ -0,0 +1,91 @@ +using OctoberStudio.Easing; +using OctoberStudio.Pool; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class SpikyTrapBehavior : MonoBehaviour + { + public static readonly int SPIKY_TRAP_EXPLOSION_HASH = "Spiky Trap Explosion".GetHashCode(); + + [SerializeField] CircleCollider2D mineTriggerCollider; + [SerializeField] GameObject mineVisuals; + [SerializeField] ParticleSystem explosionParticle; + + PoolComponent spikesPool; + + public float DamageMultiplier { get; private set; } + public float DamageRadius { get; private set; } + + private int spikesCount; + private float spikeDamageMultiplier; + + private IEasingCoroutine lifetimeCoroutine; + + public void SetData(SpikyTrapAbilityLevel stage, PoolComponent spikesPool) + { + this.spikesPool = spikesPool; + spikesCount = stage.SpikesCount; + spikeDamageMultiplier = stage.SpikeDamage; + + var size = stage.MineSize * PlayerBehavior.Player.SizeMultiplier; + transform.localScale = Vector3.one * size; + mineTriggerCollider.radius = stage.MineTriggerRadius / size; + + DamageMultiplier = stage.Damage; + + DamageRadius = stage.MineDamageRadius * PlayerBehavior.Player.SizeMultiplier; + + mineVisuals.SetActive(true); + + EasingManager.DoAfter(0.2f, () => mineTriggerCollider.enabled = true); + lifetimeCoroutine = EasingManager.DoAfter(stage.MineLifetime, Explode); + } + + private void OnTriggerEnter2D(Collider2D collision) + { + var enemy = collision.GetComponent(); + + if (enemy != null) + { + Explode(); + } + } + + private void Explode() + { + mineTriggerCollider.enabled = false; + mineVisuals.SetActive(false); + + var enemies = StageController.EnemiesSpawner.GetEnemiesInRadius(transform.position, DamageRadius); + + for (int i = 0; i < enemies.Count; i++) + { + var enemy = enemies[i]; + + enemy.TakeDamage(PlayerBehavior.Player.Damage * DamageMultiplier); + } + + explosionParticle.Play(); + + float angle = Random.Range(0, 180f); + + for (int i = 0; i < spikesCount; i++) + { + var spike = spikesPool.GetEntity(); + angle += 360f / spikesCount; + + spike.Init(transform.position, Quaternion.Euler(0, 0, angle) * Vector2.up); + + spike.DamageMultiplier = spikeDamageMultiplier; + spike.KickBack = false; + } + + lifetimeCoroutine.StopIfExists(); + + GameController.AudioManager.PlaySound(SPIKY_TRAP_EXPLOSION_HASH); + + EasingManager.DoAfter(1f, () => gameObject.SetActive(false)); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution/SpikyTrapBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution/SpikyTrapBehavior.cs.meta new file mode 100644 index 0000000..87b3fa4 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/Evolution/SpikyTrapBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 456a56b7b84386142b232592709e562a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/MagicRuneAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/MagicRuneAbilityBehavior.cs new file mode 100644 index 0000000..e659ce7 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/MagicRuneAbilityBehavior.cs @@ -0,0 +1,48 @@ +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using System.Collections; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class MagicRuneAbilityBehavior : AbilityBehavior + { + private static readonly int MAGIC_RUNE_SETUP_HASH = "Magic Rune Setup".GetHashCode(); + + [Tooltip("Rune Mine Prefab")] + [SerializeField] GameObject runeMinePrefab; + public GameObject RuneMinePrefab => runeMinePrefab; + + private PoolComponent minePool; + + private void Awake() + { + minePool = new PoolComponent("Magic Rune Ability", RuneMinePrefab, 6); + } + + public override void Init(AbilityData data, int stageId) + { + base.Init(data, stageId); + + StartCoroutine(AbilityCoroutine()); + } + + private IEnumerator AbilityCoroutine() + { + while (true) + { + for(int i = 0; i < AbilityLevel.MinesCount; i++) + { + var mine = minePool.GetEntity(); + + mine.transform.position = PlayerBehavior.CenterPosition + Random.onUnitSphere.XY().normalized * AbilityLevel.MineSpawnRadius * Random.Range(0.9f, 1.1f); + mine.SetData(AbilityLevel); + } + + GameController.AudioManager.PlaySound(MAGIC_RUNE_SETUP_HASH); + + yield return new WaitForSeconds(AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier); + } + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/MagicRuneAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/MagicRuneAbilityBehavior.cs.meta new file mode 100644 index 0000000..db04e47 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/MagicRuneAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 20359f609104ebc469dcc692b4dc22c6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/MagicRuneAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/MagicRuneAbilityData.cs new file mode 100644 index 0000000..bcc5f91 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/MagicRuneAbilityData.cs @@ -0,0 +1,54 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Magic Rune Ability Data", menuName = "October/Abilities/Active/Magic Rune")] + public class MagicRuneAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.MagicRune; + } + + private void OnValidate() + { + type = AbilityType.MagicRune; + } + } + + [System.Serializable] + public class MagicRuneAbilityLevel : AbilityLevel + { + [Tooltip("Amount of mines that are spawned at the time")] + [SerializeField, Min(1f)] int minesCount = 1; + public int MinesCount => minesCount; + + [Tooltip("Amount of time between spawning mines")] + [SerializeField, Min(0.01f)] float abilityCooldown = 7; + public float AbilityCooldown => abilityCooldown; + + [Tooltip("Distance between the player and the mine spawn position")] + [SerializeField, Min(0)] float mineSpawnRadius; + public float MineSpawnRadius => mineSpawnRadius; + + [Tooltip("Amount of time before mine selfdestructs")] + [SerializeField, Min(0.01f)] float mineLifetime = 10; + public float MineLifetime => mineLifetime; + + [Tooltip("Damage of the mine calculates as 'Damage = Player.Damage * Damage'")] + [SerializeField, Min(0.01f)] float damage = 10; + public float Damage => damage; + + [Tooltip("Scale of the mine's transform")] + [SerializeField, Min(0.1f)] float mineSize = 1; + public float MineSize => mineSize; + + [Tooltip("Max distance between the mine and the enemy that detonated the mine")] + [SerializeField, Min(0.1f)] float mineTriggerRadius = 1; + public float MineTriggerRadius => mineTriggerRadius; + + [Tooltip("Max distance between the mine and the enemy for the latter to be damaged")] + [SerializeField, Min(0.1f)] float mineDamageRadius = 1; + public float MineDamageRadius => mineDamageRadius; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/MagicRuneAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/MagicRuneAbilityData.cs.meta new file mode 100644 index 0000000..36f5a2d --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/MagicRuneAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 89c22678ba1bc0d46aea067da436741b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/MagicRuneMineBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/MagicRuneMineBehavior.cs new file mode 100644 index 0000000..85a5b3f --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/MagicRuneMineBehavior.cs @@ -0,0 +1,69 @@ +using OctoberStudio.Easing; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class MagicRuneMineBehavior : MonoBehaviour + { + private static readonly int MAGIC_RUNE_EXPLOSION_HASH = "Magic Rune Explosion".GetHashCode(); + + [SerializeField] CircleCollider2D mineTriggerCollider; + [SerializeField] GameObject mineVisuals; + [SerializeField] ParticleSystem explosionParticle; + + public float DamageMultiplier { get; private set; } + public float DamageRadius { get; private set; } + + private IEasingCoroutine lifetimeCoroutine; + + public void SetData(MagicRuneAbilityLevel stage) + { + var size = stage.MineSize * PlayerBehavior.Player.SizeMultiplier; + transform.localScale = Vector3.one * size; + mineTriggerCollider.radius = stage.MineTriggerRadius / size; + + DamageMultiplier = stage.Damage; + + DamageRadius = stage.MineDamageRadius * PlayerBehavior.Player.SizeMultiplier; + + mineVisuals.SetActive(true); + + EasingManager.DoAfter(0.2f, () => mineTriggerCollider.enabled = true); + + lifetimeCoroutine = EasingManager.DoAfter(stage.MineLifetime, Explode); + } + + private void OnTriggerEnter2D(Collider2D collision) + { + var enemy = collision.GetComponent(); + + if(enemy != null) + { + Explode(); + } + } + + private void Explode() + { + mineTriggerCollider.enabled = false; + mineVisuals.SetActive(false); + + var enemies = StageController.EnemiesSpawner.GetEnemiesInRadius(transform.position, DamageRadius); + + for(int i = 0; i < enemies.Count; i++) + { + var enemy = enemies[i]; + + enemy.TakeDamage(PlayerBehavior.Player.Damage * DamageMultiplier); + } + + explosionParticle.Play(); + + EasingManager.DoAfter(1f, () => gameObject.SetActive(false)); + + lifetimeCoroutine.StopIfExists(); + + GameController.AudioManager.PlaySound(MAGIC_RUNE_EXPLOSION_HASH); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/MagicRuneMineBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/MagicRuneMineBehavior.cs.meta new file mode 100644 index 0000000..6bd7024 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Magic Rune/MagicRuneMineBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bec748fa920504942bfb26b9bfc32efe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star.meta new file mode 100644 index 0000000..8601d04 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cd43fadcde402144a8182f276e873d03 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/Evolution.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/Evolution.meta new file mode 100644 index 0000000..8d7086e --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/Evolution.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 535bd69fd3b31424aae93581d6fbe816 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/Evolution/VoidStarAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/Evolution/VoidStarAbilityBehavior.cs new file mode 100644 index 0000000..567244a --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/Evolution/VoidStarAbilityBehavior.cs @@ -0,0 +1,92 @@ +using OctoberStudio.Easing; +using OctoberStudio.Pool; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class VoidStarAbilityBehavior : AbilityBehavior + { + public static readonly int VOID_STARS_LAUNCH_HASH = "Void Stars Launch".GetHashCode(); + + [SerializeField] GameObject starPrefab; + public GameObject StarPrefab => starPrefab; + + private List stars = new List(); + float angle = 0; + + private float radiusMultiplier = 1; + + private PoolComponent projectilesPool; + + private void Awake() + { + projectilesPool = new PoolComponent("Void Star Ability Projectile", starPrefab, 6); + } + + public override void Init(AbilityData data, int levelId) + { + base.Init(data, levelId); + + GameController.AudioManager.PlaySound(VOID_STARS_LAUNCH_HASH); + } + + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + for (int i = 0; i < stars.Count; i++) + { + stars[i].gameObject.SetActive(false); + } + + stars.Clear(); + + for (int i = 0; i < AbilityLevel.ProjectilesCount; i++) + { + var star = projectilesPool.GetEntity(); + + star.Init(); + + star.DamageMultiplier = AbilityLevel.Damage; + star.KickBack = true; + + star.Spawn(); + + stars.Add(star); + } + + EasingManager.DoFloat(0, 1, 0.5f, value => radiusMultiplier = value).SetEasing(EasingType.SineOut); + } + + private void LateUpdate() + { + transform.position = PlayerBehavior.CenterPosition; + + angle += AbilityLevel.AngularSpeed * PlayerBehavior.Player.ProjectileSpeedMultiplier * Time.deltaTime; + + for (int i = 0; i < stars.Count; i++) + { + float projectileAngle = 360f / stars.Count * i; + + projectileAngle += angle; + + stars[i].transform.localPosition = transform.position + Quaternion.Euler(0, 0, projectileAngle) * Vector3.up * AbilityLevel.Radius * radiusMultiplier * PlayerBehavior.Player.SizeMultiplier; + } + } + + public override void Clear() + { + for (int i = 0; i < stars.Count; i++) + { + stars[i].Clear(); + } + + stars.Clear(); + + projectilesPool.Destroy(); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/Evolution/VoidStarAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/Evolution/VoidStarAbilityBehavior.cs.meta new file mode 100644 index 0000000..dffcbcc --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/Evolution/VoidStarAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7ed25d7f596080143901f762610ee1dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/Evolution/VoidStarAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/Evolution/VoidStarAbilityData.cs new file mode 100644 index 0000000..a313e54 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/Evolution/VoidStarAbilityData.cs @@ -0,0 +1,38 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Void Star Ability Data", menuName = "October/Abilities/Evolution/Void Star")] + public class VoidStarAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.VoidStar; + } + + private void OnValidate() + { + type = AbilityType.VoidStar; + } + } + + [System.Serializable] + public class VoidStartAbilityLevel : AbilityLevel + { + [Tooltip("This value is multiplied by the damage of the player")] + [SerializeField, Min(0.1f)] float damage = 1f; + public float Damage => damage; + + [Tooltip("Amount of projectiles alive at the same time")] + [SerializeField] int projectilesCount = 2; + public int ProjectilesCount => projectilesCount; + + [Tooltip("Distance between the player and the projectiles")] + [SerializeField] float radius = 2.5f; + public float Radius => radius; + + [Tooltip("Rotation spped of projectiles")] + [SerializeField] float angularSpeed = -200; + public float AngularSpeed => angularSpeed; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/Evolution/VoidStarAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/Evolution/VoidStarAbilityData.cs.meta new file mode 100644 index 0000000..9a0b08a --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/Evolution/VoidStarAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9ad898821363a1e4bb8b98ccf9592d63 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/ShootingStarAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/ShootingStarAbilityData.cs new file mode 100644 index 0000000..c6849b8 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/ShootingStarAbilityData.cs @@ -0,0 +1,46 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Shooting Star Ability Data", menuName = "October/Abilities/Active/Shooting Star")] + public class ShootingStarAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.ShootingStar; + } + + private void OnValidate() + { + type = AbilityType.ShootingStar; + } + } + + [System.Serializable] + public class ShootingStartAbilityLevel: AbilityLevel + { + [Tooltip("This value is multiplied by the damage of the player")] + [SerializeField, Min(0.1f)] float damage = 1f; + public float Damage => damage; + + [Tooltip("Time between spawns of the projectiles")] + [SerializeField] float abilityCooldown; + public float AbilityCooldown => abilityCooldown; + + [Tooltip("Amount of time the projectiles are alive")] + [SerializeField] float projectileLifetime; + public float ProjectileLifetime => projectileLifetime; + + [Tooltip("Amount of projectiles alive at the same time")] + [SerializeField] int projectilesCount = 2; + public int ProjectilesCount => projectilesCount; + + [Tooltip("Distance between the player and the projectiles")] + [SerializeField] float radius = 2.5f; + public float Radius => radius; + + [Tooltip("Rotation spped of projectiles")] + [SerializeField] float angularSpeed = -200; + public float AngularSpeed => angularSpeed; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/ShootingStarAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/ShootingStarAbilityData.cs.meta new file mode 100644 index 0000000..d5cb422 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/ShootingStarAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b5c5b94e0f62c8c4aa563be6b3ce9c7b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/ShootingStarProjectile.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/ShootingStarProjectile.cs new file mode 100644 index 0000000..3c3b765 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/ShootingStarProjectile.cs @@ -0,0 +1,35 @@ +using OctoberStudio.Easing; +using UnityEngine; + +namespace OctoberStudio +{ + public class ShootingStarProjectile : ProjectileBehavior + { + IEasingCoroutine scaleEasing; + + public void Spawn() + { + if(scaleEasing.ExistsAndActive()) scaleEasing.Stop(); + + transform.localScale = Vector3.zero; + scaleEasing = transform.DoLocalScale(Vector3.one * PlayerBehavior.Player.SizeMultiplier, 0.5f).SetEasing(EasingType.SineOut); + } + + public void Hide() + { + if (scaleEasing.ExistsAndActive()) scaleEasing.Stop(); + + scaleEasing = transform.DoLocalScale(Vector3.zero, 0.5f).SetEasing(EasingType.SineIn).SetOnFinish(() => { + gameObject.SetActive(false); + }); + } + + public void Clear() + { + scaleEasing.StopIfExists(); + + transform.localScale = Vector3.one; + gameObject.SetActive(false); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/ShootingStarProjectile.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/ShootingStarProjectile.cs.meta new file mode 100644 index 0000000..cec993f --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/ShootingStarProjectile.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 23757c72e7951d94da38b954ecbb16f3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/ShootingStarsAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/ShootingStarsAbilityBehavior.cs new file mode 100644 index 0000000..2d35cd3 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/ShootingStarsAbilityBehavior.cs @@ -0,0 +1,123 @@ +using OctoberStudio.Easing; +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class ShootingStarsAbilityBehavior : AbilityBehavior + { + public static readonly int SHOOTING_STARS_LAUNCH_HASH = "Shooting Stars Launch".GetHashCode(); + + [SerializeField] GameObject starPrefab; + public GameObject StarPrefab => starPrefab; + + private List stars = new List(); + float angle = 0; + + private float radiusMultiplier = 1; + + private PoolComponent projectilesPool; + + private Coroutine abilityCoroutine; + + private void Awake() + { + projectilesPool = new PoolComponent("Shooting Star Ability Projectile", starPrefab, 6); + } + + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + if(abilityCoroutine != null) StopCoroutine(abilityCoroutine); + + for(int i = 0; i < stars.Count; i++) + { + stars[i].gameObject.SetActive(false); + } + + stars.Clear(); + + abilityCoroutine = StartCoroutine(AbilityCoroutine()); + } + + private IEnumerator AbilityCoroutine() + { + while (true) + { + float lifetime = AbilityLevel.ProjectileLifetime * PlayerBehavior.Player.DurationMultiplier; + float cooldown = AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier; + + for (int i = 0; i < AbilityLevel.ProjectilesCount; i++) + { + var star = projectilesPool.GetEntity(); + + star.Init(); + + star.DamageMultiplier = AbilityLevel.Damage; + star.KickBack = true; + + star.Spawn(); + + stars.Add(star); + } + + EasingManager.DoFloat(0, 1, 0.5f, value => radiusMultiplier = value).SetEasing(EasingType.SineOut); + + yield return new WaitForSeconds(lifetime - 0.5f); + + for(int i = 0; i < stars.Count; i++) + { + var star = stars[i]; + + star.Hide(); + } + + EasingManager.DoFloat(1, 0, 0.5f, value => radiusMultiplier = value).SetEasing(EasingType.SineOut); + + float delay = cooldown - lifetime; + if (delay < 0.5f) delay = 0.5f; + + GameController.AudioManager.PlaySound(SHOOTING_STARS_LAUNCH_HASH); + + yield return new WaitForSeconds(delay); + + stars.Clear(); + } + } + + private void LateUpdate() + { + transform.position = PlayerBehavior.CenterPosition; + + angle += AbilityLevel.AngularSpeed * PlayerBehavior.Player.ProjectileSpeedMultiplier * Time.deltaTime; + + for (int i = 0; i < stars.Count; i++) + { + float projectileAngle = 360f / stars.Count * i; + + projectileAngle += angle; + + stars[i].transform.localPosition = transform.position + Quaternion.Euler(0, 0, projectileAngle) * Vector3.up * AbilityLevel.Radius * radiusMultiplier * PlayerBehavior.Player.SizeMultiplier; + } + } + + public override void Clear() + { + if (abilityCoroutine != null) StopCoroutine(abilityCoroutine); + + for (int i = 0; i < stars.Count; i++) + { + stars[i].Clear(); + } + + stars.Clear(); + + projectilesPool.Destroy(); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/ShootingStarsAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/ShootingStarsAbilityBehavior.cs.meta new file mode 100644 index 0000000..cc7daeb --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Shooting Star/ShootingStarsAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7fb4f48a6b6a044b82b6127983a7a61 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray.meta new file mode 100644 index 0000000..d2ed131 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a90be1592f0b64e4a93ae6462ac66899 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution.meta new file mode 100644 index 0000000..de98a14 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2896598cc33d988449df521b4c7228a4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution/EclipseRayProjectileBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution/EclipseRayProjectileBehavior.cs new file mode 100644 index 0000000..a42a201 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution/EclipseRayProjectileBehavior.cs @@ -0,0 +1,65 @@ +using System.Collections; +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio.Abilities +{ + public class EclipseRayProjectileBehavior : ProjectileBehavior + { + public UnityAction onFinished; + + private Coroutine movementCoroutine; + + public float InitialRadius { get; set; } + public float ProjectileLifetime { get; set; } + public float AngularSpeed { get; set; } + + public void Spawn(float startingAngle) + { + Init(); + transform.localScale = Vector3.one * PlayerBehavior.Player.SizeMultiplier; + + KickBack = false; + + movementCoroutine = StartCoroutine(MovementCoroutine(startingAngle)); + } + + private IEnumerator MovementCoroutine(float startingAngle) + { + var time = 0f; + var duration = ProjectileLifetime * PlayerBehavior.Player.DurationMultiplier; + + var startPosition = PlayerBehavior.Player.transform.position; + + var distance = InitialRadius * PlayerBehavior.Player.SizeMultiplier; + var currentDistance = distance; + do + { + time += Time.deltaTime; + var t = time / duration; + + var angle = startingAngle + time * AngularSpeed * PlayerBehavior.Player.ProjectileSpeedMultiplier; + + currentDistance -= Time.deltaTime * (distance / duration); + + var position = startPosition + Quaternion.Euler(0, 0, angle) * Vector3.up * currentDistance; + + transform.position = position; + + yield return null; + + } while (time < duration); + + gameObject.SetActive(false); + onFinished?.Invoke(this); + + movementCoroutine = null; + } + + public void Disable() + { + if (movementCoroutine != null) StopCoroutine(movementCoroutine); + gameObject.SetActive(false); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution/EclipseRayProjectileBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution/EclipseRayProjectileBehavior.cs.meta new file mode 100644 index 0000000..790e0d1 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution/EclipseRayProjectileBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8393a70229095f34683ed44d67922767 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution/LunarProjectorAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution/LunarProjectorAbilityBehavior.cs new file mode 100644 index 0000000..63569c0 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution/LunarProjectorAbilityBehavior.cs @@ -0,0 +1,93 @@ +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class LunarProjectorAbilityBehavior : AbilityBehavior + { + public static readonly int LUNAR_PROJECTOR_LAUNCH_HASH = "Eclipse Ray Launch".GetHashCode(); + + [SerializeField] GameObject eclipseRayPrefab; + public GameObject EclipseRayPrefab => eclipseRayPrefab; + + private PoolComponent projectilePool; + + private Coroutine abilityCoroutine; + private List projectiles = new List(); + + private void Awake() + { + projectilePool = new PoolComponent("Eclipse Ray Ability Projectile", EclipseRayPrefab, 5); + } + + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + Disable(); + + abilityCoroutine = StartCoroutine(AbilityCoroutine()); + } + + private IEnumerator AbilityCoroutine() + { + while (true) + { + for (int i = 0; i < AbilityLevel.ProjectileCount; i++) + { + var projectile = projectilePool.GetEntity(); + + projectile.transform.position = PlayerBehavior.Player.transform.position; + + projectile.DamageMultiplier = AbilityLevel.Damage; + projectile.ProjectileLifetime = AbilityLevel.ProjectileLifetime; + projectile.InitialRadius = AbilityLevel.InitialRadius; + projectile.AngularSpeed = AbilityLevel.AngularSpeed; + projectile.onFinished += OnRayFinished; + + var angle = 360f / AbilityLevel.ProjectileCount * i; + + projectile.Spawn(angle); + + projectiles.Add(projectile); + } + + GameController.AudioManager.PlaySound(LUNAR_PROJECTOR_LAUNCH_HASH); + + yield return new WaitForSeconds(AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier); + } + } + + private void Disable() + { + if (abilityCoroutine != null) StopCoroutine(abilityCoroutine); + + for (int i = 0; i < projectiles.Count; i++) + { + var projectile = projectiles[i]; + + projectile.onFinished -= OnRayFinished; + + projectile.Disable(); + } + + projectiles.Clear(); + } + + private void OnRayFinished(EclipseRayProjectileBehavior ray) + { + ray.onFinished -= OnRayFinished; + + projectiles.Remove(ray); + } + + public override void Clear() + { + Disable(); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution/LunarProjectorAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution/LunarProjectorAbilityBehavior.cs.meta new file mode 100644 index 0000000..dd92ba2 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution/LunarProjectorAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d4e0c55d085ed2341b8da8dcba43d9bc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution/LunarProjectorAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution/LunarProjectorAbilityData.cs new file mode 100644 index 0000000..ee0abda --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution/LunarProjectorAbilityData.cs @@ -0,0 +1,46 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Lunar Projector Ability Data", menuName = "October/Abilities/Evolution/Lunar Projector")] + public class LunarProjectorAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.LunarProjector; + } + + private void OnValidate() + { + type = AbilityType.LunarProjector; + } + } + + [System.Serializable] + public class LunarProjectorAbilityLevel : AbilityLevel + { + [Tooltip("Amount of rays spawned at the same time")] + [SerializeField] int projectileCount; + public int ProjectileCount => projectileCount; + + [Tooltip("Amount of time before rays disappear")] + [SerializeField] float projectileLifetime; + public float ProjectileLifetime => projectileLifetime; + + [Tooltip("Amount of time between attacks")] + [SerializeField] float abilityCooldown; + public float AbilityCooldown => abilityCooldown; + + [Tooltip("Max distance the rays will travel to the player")] + [SerializeField] float initialRadius; + public float InitialRadius => initialRadius; + + [Tooltip("Rotational speed of the recoiler")] + [SerializeField] float angularSpeed; + public float AngularSpeed => angularSpeed; + + [Tooltip("Damage of the ray calculates as 'Damage = Player.Damage * damageMultiplier'")] + [SerializeField] float damage; + public float Damage => damage; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution/LunarProjectorAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution/LunarProjectorAbilityData.cs.meta new file mode 100644 index 0000000..3e5361d --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/Evolution/LunarProjectorAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 10f85165c00ab52478088ba91528ee1f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/SolarMagnifierAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/SolarMagnifierAbilityBehavior.cs new file mode 100644 index 0000000..e320cbe --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/SolarMagnifierAbilityBehavior.cs @@ -0,0 +1,97 @@ +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class SolarMagnifierAbilityBehavior : AbilityBehavior + { + public static readonly int SOLAR_MAGNIFIER_LAUNCH_HASH = "Solar Magnifier Launch".GetHashCode(); + + [SerializeField] GameObject sunRayPrefab; + public GameObject SunRayPrefab => sunRayPrefab; + + private PoolComponent projectilePool; + + private Coroutine abilityCoroutine; + private List projectiles = new List(); + + private void Awake() + { + projectilePool = new PoolComponent("Sun Ray Ability Projectile", SunRayPrefab, 5); + } + + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + Disable(); + + abilityCoroutine = StartCoroutine(AbilityCoroutine()); + } + + private IEnumerator AbilityCoroutine() + { + while (true) + { + for (int i = 0; i < AbilityLevel.ProjectileCount; i++) + { + var projectile = projectilePool.GetEntity(); + + var enemy = StageController.EnemiesSpawner.GetRandomVisibleEnemy(); + + projectile.DamagePerSecond = AbilityLevel.DamagePerSecond; + projectile.AdditionalDamagePerSecond = AbilityLevel.AdditionalDamagePerSecond; + projectile.DamageInterval = 1f / AbilityLevel.DamageRate; + projectile.AdditionalDamageRadius = AbilityLevel.AdditionalDamageRadius; + + projectile.Lifetime = AbilityLevel.ProjectileLifetime * PlayerBehavior.Player.DurationMultiplier; + projectile.Speed = AbilityLevel.ProjectileSpeed; + + projectile.onFinished += OnProjectileFinished; + + projectile.Spawn(enemy); + + projectiles.Add(projectile); + + GameController.AudioManager.PlaySound(SOLAR_MAGNIFIER_LAUNCH_HASH); + + yield return new WaitForSeconds(AbilityLevel.TimeBetweenProjectiles); + } + + yield return new WaitForSeconds(AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier - AbilityLevel.TimeBetweenProjectiles * AbilityLevel.ProjectileCount); + } + } + + private void Disable() + { + if (abilityCoroutine != null) StopCoroutine(abilityCoroutine); + + for (int i = 0; i < projectiles.Count; i++) + { + var projectile = projectiles[i]; + + projectile.onFinished -= OnProjectileFinished; + + projectile.Disable(); + } + + projectiles.Clear(); + } + + private void OnProjectileFinished(SunRayProjectileBehavior sunRay) + { + sunRay.onFinished -= OnProjectileFinished; + + projectiles.Remove(sunRay); + } + + public override void Clear() + { + Disable(); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/SolarMagnifierAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/SolarMagnifierAbilityBehavior.cs.meta new file mode 100644 index 0000000..755d4e1 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/SolarMagnifierAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 471fa21b10d8d604f87630b40bcf4dba +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/SolarMagnifierAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/SolarMagnifierAbilityData.cs new file mode 100644 index 0000000..4f8144c --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/SolarMagnifierAbilityData.cs @@ -0,0 +1,60 @@ +using UnityEngine; +using UnityEngine.Serialization; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Solar Magnifier Ability Data", menuName = "October/Abilities/Active/Solar Magnifier")] + public class SolarMagnifierAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.SolarMagnifier; + } + + private void OnValidate() + { + type = AbilityType.SolarMagnifier; + } + } + + [System.Serializable] + public class SolarMagnifierAbilityLevel: AbilityLevel + { + [Tooltip("Amount of time between attacks")] + [SerializeField] float abilityCooldown; + public float AbilityCooldown => abilityCooldown; + + [Tooltip("Amount of time before sun ray disappears")] + [SerializeField] float projectileLifetime; + public float ProjectileLifetime => projectileLifetime; + + [Tooltip("Amount of time between firing sun rays in one attack")] + [SerializeField] float timeBetweenProjectiles; + public float TimeBetweenProjectiles => timeBetweenProjectiles; + + [Tooltip("Amount of sun rays spawned at the same time")] + [SerializeField] int projectileCount; + public int ProjectileCount => projectileCount; + + [Tooltip("Damage of the sun ray calculates as 'Damage = Player.Damage * DamagePerSecond'")] + [FormerlySerializedAs("damage")] + [SerializeField] float damagePerSecond; + public float DamagePerSecond => damagePerSecond; + + [Tooltip("Enemy will take damage in this time per second")] + [SerializeField] float damageRate; + public float DamageRate => damageRate; + + [Tooltip("All enemies in additionalDamageRadius will take additionalDamagePerSecond")] + [SerializeField] float additionalDamagePerSecond; + public float AdditionalDamagePerSecond => additionalDamagePerSecond; + + [Tooltip("The radius enemies have to be in to get additional damage")] + [SerializeField] float additionalDamageRadius; + public float AdditionalDamageRadius => additionalDamageRadius; + + [Tooltip("Spead of the sun ray")] + [SerializeField] float projectileSpeed; + public float ProjectileSpeed => projectileSpeed; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/SolarMagnifierAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/SolarMagnifierAbilityData.cs.meta new file mode 100644 index 0000000..5be6265 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/SolarMagnifierAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bb78b06ae98fb384483dcb5b4aa8b89c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/SunRayProjectileBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/SunRayProjectileBehavior.cs new file mode 100644 index 0000000..e3383fe --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/SunRayProjectileBehavior.cs @@ -0,0 +1,147 @@ +using OctoberStudio.Easing; +using OctoberStudio.Extensions; +using System.Collections; +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio +{ + public class SunRayProjectileBehavior : MonoBehaviour + { + public UnityAction onFinished; + + public float Lifetime { get; set; } + + public float DamagePerSecond { get; set; } + public float DamageInterval { get; set; } + public float AdditionalDamagePerSecond { get; set; } + public float AdditionalDamageRadius { get; set; } + + public float Speed { get; set; } + + public EnemyBehavior Target { get; private set; } + public bool IsTargetLocked { get; private set; } + + private IEasingCoroutine movementCoroutine; + private Coroutine waitingCoroutine; + + private float spawnTime; + private float lastDamageTime; + + private Vector3 offset; + + public void Spawn(EnemyBehavior target) + { + Target = target; + + if(Target != null) + { + transform.position = Target.transform.position; + IsTargetLocked = true; + + Target.onEnemyDied += OnEnemyDied; + } else + { + IsTargetLocked = false; + + transform.position = PlayerBehavior.Player.transform.position + new Vector3(-1, 1, 0); + + waitingCoroutine = StartCoroutine(WaitingForTarget()); + } + + spawnTime = Time.time; + lastDamageTime = Time.time - 100000; + + offset = Random.onUnitSphere.XY().normalized * 0.075f; + } + + private IEnumerator WaitingForTarget() + { + while(Target == null) + { + yield return null; + + Target = StageController.EnemiesSpawner.GetClosestEnemy(transform.position); + } + + MoveToTarget(); + } + + private void Update() + { + if (IsTargetLocked && Target != null) + { + transform.position = Target.transform.position + offset; + } + + if (Time.time > lastDamageTime + DamageInterval) + { + if (IsTargetLocked && Target != null) + { + Target.TakeDamage(DamagePerSecond * PlayerBehavior.Player.Damage * DamageInterval); + } + + var closeEnemies = StageController.EnemiesSpawner.GetEnemiesInRadius(transform.position, AdditionalDamageRadius); + + foreach(var enemy in closeEnemies) + { + if(enemy != Target) + { + enemy.TakeDamage(AdditionalDamagePerSecond * PlayerBehavior.Player.Damage * DamageInterval); + } + } + + lastDamageTime = Time.time; + } + + if(Time.time > spawnTime + Lifetime) + { + onFinished?.Invoke(this); + Disable(); + } + } + + private void MoveToTarget() + { + Target.onEnemyDied += OnEnemyDied; + + var distanve = Vector2.Distance(transform.position, Target.transform.position); + var time = distanve / (Speed * PlayerBehavior.Player.ProjectileSpeedMultiplier); + + movementCoroutine.StopIfExists(); + movementCoroutine = transform.DoPosition(Target.transform, time).SetEasing(EasingType.SineIn).SetOnFinish(() => IsTargetLocked = true); + } + + private void OnEnemyDied(EnemyBehavior enemy) + { + Target.onEnemyDied -= OnEnemyDied; + IsTargetLocked = false; + + Target = StageController.EnemiesSpawner.GetClosestEnemy(transform.position); + + if(Target != null) + { + MoveToTarget(); + } else + { + waitingCoroutine = StartCoroutine(WaitingForTarget()); + } + } + + public void Disable() + { + if(Target != null) + { + Target.onEnemyDied -= OnEnemyDied; + } + + movementCoroutine.StopIfExists(); + + IsTargetLocked = false; + + if (waitingCoroutine != null) StopCoroutine(waitingCoroutine); + + gameObject.SetActive(false); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/SunRayProjectileBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/SunRayProjectileBehavior.cs.meta new file mode 100644 index 0000000..959164e --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sun Ray/SunRayProjectileBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9dea884b614a3cc4c9d701c15041f1b4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword.meta new file mode 100644 index 0000000..24101f8 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0fdcdbeb962a0884e9374a13958e3cb5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/Evolution.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/Evolution.meta new file mode 100644 index 0000000..dd65c9c --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/Evolution.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 201b63ca902c30f42b4092258e176a95 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/Evolution/SacredBladeAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/Evolution/SacredBladeAbilityBehavior.cs new file mode 100644 index 0000000..472c7f5 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/Evolution/SacredBladeAbilityBehavior.cs @@ -0,0 +1,132 @@ +using OctoberStudio.Pool; +using OctoberStudio.Easing; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class SacredBladeAbilityBehavior : AbilityBehavior + { + public static readonly int SACRED_BLADE_ATTACK_HASH = "Sacred Blade Attack".GetHashCode(); + + [SerializeField] GameObject slashPrefab; + public GameObject SlashPrefab => slashPrefab; + + [SerializeField] GameObject wavePrefab; + public GameObject WavePrefab => wavePrefab; + + private PoolComponent slashPool; + private PoolComponent wavePool; + + private List slashes = new List(); + private List waves = new List(); + + [SerializeField] List shashDirections; + + Coroutine abilityCoroutine; + + private float AbilityCooldown => AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier; + + private void Awake() + { + slashPool = new PoolComponent("Blade Slash", SlashPrefab, 6); + wavePool = new PoolComponent("Blade Wave", WavePrefab, 12); + } + + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + if (abilityCoroutine != null) Disable(); + + abilityCoroutine = StartCoroutine(AbilityCoroutine()); + } + + private IEnumerator AbilityCoroutine() + { + var lastTimeSpawned = Time.time - AbilityCooldown; + + while (true) + { + for (int i = 0; i < AbilityLevel.SlashesCount; i++) + { + var slash = slashPool.GetEntity(); + + slash.transform.position = PlayerBehavior.CenterPosition; + slash.transform.rotation = Quaternion.FromToRotation(Vector2.right, PlayerBehavior.Player.LookDirection) * shashDirections[i].localRotation; + + slash.DamageMultiplier = AbilityLevel.Damage; + slash.KickBack = false; + + slash.Size = AbilityLevel.SlashSize; + + slash.Init(); + + slash.onFinished += OnProjectileFinished; + slashes.Add(slash); + + var wave = wavePool.GetEntity(); + + wave.DamageMultiplier = AbilityLevel.WaveDamage; + wave.KickBack = false; + + wave.Init(PlayerBehavior.CenterPosition, Quaternion.FromToRotation(Vector2.right, PlayerBehavior.Player.LookDirection) * shashDirections[i].localRotation * Vector2.right); + + wave.ScaleRotatingPart(Vector2.up, Vector2.one).SetEasing(EasingType.SineOut); + + wave.onFinished += OnWaveFinished; + + waves.Add(wave); + + GameController.AudioManager.PlaySound(SACRED_BLADE_ATTACK_HASH); + + yield return new WaitForSeconds(AbilityLevel.TimeBetweenSlashes * PlayerBehavior.Player.CooldownMultiplier); + } + + yield return new WaitForSeconds(AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier - AbilityLevel.TimeBetweenSlashes * PlayerBehavior.Player.CooldownMultiplier * AbilityLevel.SlashesCount); + } + } + + private void OnProjectileFinished(SwordSlashBehavior slash) + { + slash.onFinished -= OnProjectileFinished; + + slashes.Remove(slash); + } + + private void OnWaveFinished(SimplePlayerProjectileBehavior wave) + { + wave.onFinished -= OnWaveFinished; + + waves.Remove(wave); + } + + private void Disable() + { + for (int i = 0; i < slashes.Count; i++) + { + slashes[i].Disable(); + } + + for (int i = 0; i < waves.Count; i++) + { + waves[i].Clear(); + } + + slashes.Clear(); + waves.Clear(); + + StopCoroutine(abilityCoroutine); + } + + public override void Clear() + { + Disable(); + + slashPool.Destroy(); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/Evolution/SacredBladeAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/Evolution/SacredBladeAbilityBehavior.cs.meta new file mode 100644 index 0000000..483a7ea --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/Evolution/SacredBladeAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0081b9aa4e7e82a408834c7e9556c50a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/Evolution/SacredBladeAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/Evolution/SacredBladeAbilityData.cs new file mode 100644 index 0000000..9569077 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/Evolution/SacredBladeAbilityData.cs @@ -0,0 +1,48 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Sacred Blade Data", menuName = "October/Abilities/Evolution/Sacred Blade")] + public class SacredBladeAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.SacredBlade; + isWeaponAbility = true; + } + + private void OnValidate() + { + type = AbilityType.SacredBlade; + isWeaponAbility = true; + } + } + + [System.Serializable] + public class SacredBladeAbilityLevel : AbilityLevel + { + [Tooltip("Amount of time between attacks")] + [SerializeField] float abilityCooldown; + public float AbilityCooldown => abilityCooldown; + + [Tooltip("Amount of slashes in the attack")] + [SerializeField] int slashesCount; + public int SlashesCount => slashesCount; + + [Tooltip("Damage of slashes calculates like this: Player.Damage * Damage")] + [SerializeField] float damage; + public float Damage => damage; + + [Tooltip("Damage of waves calculates like this: Player.Damage * WaveDamage")] + [SerializeField] float waveDamage; + public float WaveDamage => waveDamage; + + [Tooltip("Size of slash")] + [SerializeField] float slashSize; + public float SlashSize => slashSize; + + [Tooltip("Delay Before each slash")] + [SerializeField] float timeBetweenSlashes; + public float TimeBetweenSlashes => timeBetweenSlashes; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/Evolution/SacredBladeAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/Evolution/SacredBladeAbilityData.cs.meta new file mode 100644 index 0000000..ddd912c --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/Evolution/SacredBladeAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 22d1e1571be5cc64f8e081e56acef858 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/SteelSwordWeaponAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/SteelSwordWeaponAbilityData.cs new file mode 100644 index 0000000..b1217a6 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/SteelSwordWeaponAbilityData.cs @@ -0,0 +1,44 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Steel Sword Data", menuName = "October/Abilities/Active/Steel Sword")] + public class SteelSwordWeaponAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.SteelSword; + isWeaponAbility = true; + } + + private void OnValidate() + { + type = AbilityType.SteelSword; + isWeaponAbility = true; + } + } + + [System.Serializable] + public class SteelSwordWeaponAbilityLevel : AbilityLevel + { + [Tooltip("Amount of time between attacks")] + [SerializeField] float abilityCooldown; + public float AbilityCooldown => abilityCooldown; + + [Tooltip("Amount of slashes in the attack")] + [SerializeField] int slashesCount; + public int SlashesCount => slashesCount; + + [Tooltip("Damage of slashes calculates like this: Player.Damage * Damage")] + [SerializeField] float damage; + public float Damage => damage; + + [Tooltip("Size of slash")] + [SerializeField] float slashSize; + public float SlashSize => slashSize; + + [Tooltip("Delay Before each slash")] + [SerializeField] float timeBetweenSlashes; + public float TimeBetweenSlashes => timeBetweenSlashes; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/SteelSwordWeaponAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/SteelSwordWeaponAbilityData.cs.meta new file mode 100644 index 0000000..e2a948c --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/SteelSwordWeaponAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5bafa157c553fd74398db8cc932d5cda +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/SwordSlashBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/SwordSlashBehavior.cs new file mode 100644 index 0000000..e70d385 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/SwordSlashBehavior.cs @@ -0,0 +1,44 @@ +using OctoberStudio.Easing; +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio.Abilities +{ + public class SwordSlashBehavior : ProjectileBehavior + { + [SerializeField] Collider2D slashCollider; + [SerializeField] float duration; + + public float Size { get; set; } + + public UnityAction onFinished; + + private IEasingCoroutine waitingCoroutine; + private IEasingCoroutine colliderCoroutine; + + public override void Init() + { + base.Init(); + + transform.localScale = Vector3.one * Size * PlayerBehavior.Player.SizeMultiplier; + + slashCollider.enabled = true; + + colliderCoroutine = EasingManager.DoAfter(0.1f, () => slashCollider.enabled = false); + + waitingCoroutine = EasingManager.DoAfter(duration, () => { + onFinished?.Invoke(this); + Disable(); + }); + } + + public void Disable() + { + waitingCoroutine.StopIfExists(); + colliderCoroutine.StopIfExists(); + + gameObject.SetActive(false); + slashCollider.enabled = true; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/SwordSlashBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/SwordSlashBehavior.cs.meta new file mode 100644 index 0000000..2f4ec94 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/SwordSlashBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1178b50ccb8622947af6d187de558ff8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/SwordWeaponAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/SwordWeaponAbilityBehavior.cs new file mode 100644 index 0000000..1e2a011 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/SwordWeaponAbilityBehavior.cs @@ -0,0 +1,100 @@ +using OctoberStudio.Easing; +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class SwordWeaponAbilityBehavior : AbilityBehavior + { + public static readonly int STEEL_SWORD_ATTACK_HASH = "Steel Sword Attack".GetHashCode(); + + [SerializeField] GameObject slashPrefab; + public GameObject SlashPrefab => slashPrefab; + + private PoolComponent slashPool; + private List slashes = new List(); + + [SerializeField] List shashDirections; + + IEasingCoroutine projectileCoroutine; + Coroutine abilityCoroutine; + + private float AbilityCooldown => AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier; + + private void Awake() + { + slashPool = new PoolComponent("Sword Slash", SlashPrefab, 50); + } + + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + if (abilityCoroutine != null) Disable(); + + abilityCoroutine = StartCoroutine(AbilityCoroutine()); + } + + private IEnumerator AbilityCoroutine() + { + var lastTimeSpawned = Time.time - AbilityCooldown; + + while (true) + { + for(int i = 0; i < AbilityLevel.SlashesCount; i++) + { + var slash = slashPool.GetEntity(); + + slash.transform.position = PlayerBehavior.CenterPosition; + slash.transform.rotation = Quaternion.FromToRotation(Vector2.right, PlayerBehavior.Player.LookDirection) * shashDirections[i].localRotation; + + slash.DamageMultiplier = AbilityLevel.Damage; + slash.KickBack = false; + + slash.Size = AbilityLevel.SlashSize; + + slash.Init(); + + slash.onFinished += OnProjectileFinished; + slashes.Add(slash); + + GameController.AudioManager.PlaySound(STEEL_SWORD_ATTACK_HASH); + + yield return new WaitForSeconds(AbilityLevel.TimeBetweenSlashes * PlayerBehavior.Player.CooldownMultiplier); + } + + yield return new WaitForSeconds(AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier - AbilityLevel.TimeBetweenSlashes * PlayerBehavior.Player.CooldownMultiplier * AbilityLevel.SlashesCount); + } + } + + private void OnProjectileFinished(SwordSlashBehavior slash) + { + slash.onFinished -= OnProjectileFinished; + + slashes.Remove(slash); + } + + private void Disable() + { + projectileCoroutine.StopIfExists(); + + for (int i = 0; i < slashes.Count; i++) + { + slashes[i].Disable(); + } + + slashes.Clear(); + + StopCoroutine(abilityCoroutine); + } + + public override void Clear() + { + Disable(); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/SwordWeaponAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/SwordWeaponAbilityBehavior.cs.meta new file mode 100644 index 0000000..15bf59c --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Sword/SwordWeaponAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 99493b8a72a4fe04ab0f930565a4364b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand.meta new file mode 100644 index 0000000..5f713ce --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 32e039326376fad42a8074097662c1e9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/Evolution.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/Evolution.meta new file mode 100644 index 0000000..2529cca --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/Evolution.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ae9c1dafa616f0f4d9cf33c82f743f48 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/Evolution/ScepterWeaponAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/Evolution/ScepterWeaponAbilityData.cs new file mode 100644 index 0000000..50c3248 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/Evolution/ScepterWeaponAbilityData.cs @@ -0,0 +1,44 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Scepter Data", menuName = "October/Abilities/Evolution/Scepter")] + public class ScepterWeaponAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.AncientScepter; + isWeaponAbility = true; + } + + private void OnValidate() + { + type = AbilityType.AncientScepter; + isWeaponAbility = true; + } + } + + [System.Serializable] + public class ScepterWeaponAbilityLevel : AbilityLevel + { + [Tooltip("Amount of time between attacks")] + [SerializeField] float abilityCooldown; + public float AbilityCooldown => abilityCooldown; + + [Tooltip("Speed of the projectile")] + [SerializeField] float projectileSpeed; + public float ProjectileSpeed => projectileSpeed; + + [Tooltip("Damage of projectiles calculates like this: Player.Damage * Damage")] + [SerializeField] float damage; + public float Damage => damage; + + [Tooltip("Size of projectiles")] + [SerializeField] float projectileSize; + public float ProjectileSize => projectileSize; + + [Tooltip("Time projectiles stay alive")] + [SerializeField] float projectileLifetime; + public float ProjectileLifetime => projectileLifetime; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/Evolution/ScepterWeaponAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/Evolution/ScepterWeaponAbilityData.cs.meta new file mode 100644 index 0000000..65e3f30 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/Evolution/ScepterWeaponAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b3a5414a78c464949a585f13729ee1f0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/Evolution/ScepterWeaponAvilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/Evolution/ScepterWeaponAvilityBehavior.cs new file mode 100644 index 0000000..6339bea --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/Evolution/ScepterWeaponAvilityBehavior.cs @@ -0,0 +1,109 @@ +using OctoberStudio.Easing; +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class ScepterWeaponAvilityBehavior : AbilityBehavior + { + public static readonly int SEPTER_PROJECTILE_LAUNCH_HASH = "Septer Projectile Launch".GetHashCode(); + + [SerializeField] GameObject projectilePrefab; + public GameObject ProjectilePrefab => projectilePrefab; + + private PoolComponent projectilePool; + public List projectiles = new List(); + + IEasingCoroutine projectileCoroutine; + Coroutine abilityCoroutine; + + private float AbilityCooldown => AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier; + + private void Awake() + { + projectilePool = new PoolComponent("Scepter Projectile", ProjectilePrefab, 50); + } + + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + if (abilityCoroutine != null) Disable(); + + abilityCoroutine = StartCoroutine(AbilityCoroutine()); + } + + private IEnumerator AbilityCoroutine() + { + var lastTimeSpawned = Time.time - AbilityCooldown; + + while (true) + { + while (lastTimeSpawned + AbilityCooldown < Time.time) + { + var spawnTime = lastTimeSpawned + AbilityCooldown; + + var projectile = projectilePool.GetEntity(); + + var closestEnemy = StageController.EnemiesSpawner.GetClosestEnemy(PlayerBehavior.CenterPosition); + + var direction = Vector2.up; + if (closestEnemy != null) + { + direction = closestEnemy.Center - PlayerBehavior.CenterPosition; + direction.Normalize(); + } + + var aliveDuration = Time.time - spawnTime; + var position = PlayerBehavior.CenterPosition + direction * aliveDuration * AbilityLevel.ProjectileSpeed * PlayerBehavior.Player.ProjectileSpeedMultiplier; + + projectile.Init(position, direction); + projectile.Speed = AbilityLevel.ProjectileSpeed * PlayerBehavior.Player.ProjectileSpeedMultiplier; + projectile.transform.localScale = Vector3.one * AbilityLevel.ProjectileSize * PlayerBehavior.Player.SizeMultiplier; + projectile.LifeTime = AbilityLevel.ProjectileLifetime; + projectile.DamageMultiplier = AbilityLevel.Damage; + + projectile.onFinished += OnProjectileFinished; + projectiles.Add(projectile); + + lastTimeSpawned += AbilityCooldown; + + GameController.AudioManager.PlaySound(SEPTER_PROJECTILE_LAUNCH_HASH); + } + + yield return null; + } + } + + private void OnProjectileFinished(SimplePlayerProjectileBehavior projectile) + { + projectile.onFinished -= OnProjectileFinished; + + projectiles.Remove(projectile); + } + + private void Disable() + { + projectileCoroutine.StopIfExists(); + + for (int i = 0; i < projectiles.Count; i++) + { + projectiles[i].gameObject.SetActive(false); + } + + projectiles.Clear(); + + StopCoroutine(abilityCoroutine); + } + + public override void Clear() + { + Disable(); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/Evolution/ScepterWeaponAvilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/Evolution/ScepterWeaponAvilityBehavior.cs.meta new file mode 100644 index 0000000..6e74348 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/Evolution/ScepterWeaponAvilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ac6565002c09d22428df983b61c48906 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/WandWeaponAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/WandWeaponAbilityBehavior.cs new file mode 100644 index 0000000..f50c847 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/WandWeaponAbilityBehavior.cs @@ -0,0 +1,109 @@ +using OctoberStudio.Easing; +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class WandWeaponAbilityBehavior : AbilityBehavior + { + public static readonly int WAND_PROJECTILE_LAUNCH_HASH = "Wand Projectile Launch".GetHashCode(); + + [SerializeField] GameObject projectilePrefab; + public GameObject ProjectilePrefab => projectilePrefab; + + private PoolComponent projectilePool; + public List projectiles = new List(); + + IEasingCoroutine projectileCoroutine; + Coroutine abilityCoroutine; + + private float AbilityCooldown => AbilityLevel.AbilityCooldown * PlayerBehavior.Player.CooldownMultiplier; + + private void Awake() + { + projectilePool = new PoolComponent("Wand Projectiule", ProjectilePrefab, 50); + } + + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + if (abilityCoroutine != null) Disable(); + + abilityCoroutine = StartCoroutine(AbilityCoroutine()); + } + + private IEnumerator AbilityCoroutine() + { + var lastTimeSpawned = Time.time - AbilityCooldown; + + while (true) + { + while(lastTimeSpawned + AbilityCooldown < Time.time) + { + var spawnTime = lastTimeSpawned + AbilityCooldown; + + var projectile = projectilePool.GetEntity(); + + var closestEnemy = StageController.EnemiesSpawner.GetClosestEnemy(PlayerBehavior.CenterPosition); + + var direction = Vector2.up; + if(closestEnemy != null) + { + direction = closestEnemy.Center - PlayerBehavior.CenterPosition; + direction.Normalize(); + } + + var aliveDuration = Time.time - spawnTime; + var position = PlayerBehavior.CenterPosition + direction * aliveDuration * AbilityLevel.ProjectileSpeed * PlayerBehavior.Player.ProjectileSpeedMultiplier; + + projectile.Init(position, direction); + projectile.Speed = AbilityLevel.ProjectileSpeed * PlayerBehavior.Player.ProjectileSpeedMultiplier; + projectile.transform.localScale = Vector3.one * AbilityLevel.ProjectileSize * PlayerBehavior.Player.SizeMultiplier; + projectile.LifeTime = AbilityLevel.ProjectileLifetime; + projectile.DamageMultiplier = AbilityLevel.Damage; + + projectile.onFinished += OnProjectileFinished; + projectiles.Add(projectile); + + lastTimeSpawned += AbilityCooldown; + + GameController.AudioManager.PlaySound(WAND_PROJECTILE_LAUNCH_HASH); + } + + yield return null; + } + } + + private void OnProjectileFinished(SimplePlayerProjectileBehavior projectile) + { + projectile.onFinished -= OnProjectileFinished; + + projectiles.Remove(projectile); + } + + private void Disable() + { + projectileCoroutine.StopIfExists(); + + for (int i = 0; i < projectiles.Count; i++) + { + projectiles[i].gameObject.SetActive(false); + } + + projectiles.Clear(); + + StopCoroutine(abilityCoroutine); + } + + public override void Clear() + { + Disable(); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/WandWeaponAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/WandWeaponAbilityBehavior.cs.meta new file mode 100644 index 0000000..2e35227 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/WandWeaponAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3acffec179461d84598657c618f56b38 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/WoodenWandWeaponAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/WoodenWandWeaponAbilityData.cs new file mode 100644 index 0000000..3d465e1 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/WoodenWandWeaponAbilityData.cs @@ -0,0 +1,44 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Wooden Wand Data", menuName = "October/Abilities/Active/Wooden Wand")] + public class WoodenWandWeaponAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.WoodenWand; + isWeaponAbility = true; + } + + private void OnValidate() + { + type = AbilityType.WoodenWand; + isWeaponAbility = true; + } + } + + [System.Serializable] + public class WoodenWandWeaponAbilityLevel : AbilityLevel + { + [Tooltip("Amount of time between attacks")] + [SerializeField] float abilityCooldown; + public float AbilityCooldown => abilityCooldown; + + [Tooltip("Speed of the projectile")] + [SerializeField] float projectileSpeed; + public float ProjectileSpeed => projectileSpeed; + + [Tooltip("Damage of projectiles calculates like this: Player.Damage * Damage")] + [SerializeField] float damage; + public float Damage => damage; + + [Tooltip("Size of projectiles")] + [SerializeField] float projectileSize; + public float ProjectileSize => projectileSize; + + [Tooltip("Time projectiles stay alive")] + [SerializeField] float projectileLifetime; + public float ProjectileLifetime => projectileLifetime; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/WoodenWandWeaponAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/WoodenWandWeaponAbilityData.cs.meta new file mode 100644 index 0000000..86a9b60 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Active Abilities/Wand/WoodenWandWeaponAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 30b7a9b80971a9e4d8f8a1c92b676589 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/CameraSpaceProjectile.cs b/Assets/Common/Scripts/Abilities/Behaviors/CameraSpaceProjectile.cs new file mode 100644 index 0000000..78266d4 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/CameraSpaceProjectile.cs @@ -0,0 +1,51 @@ +using UnityEngine; + +namespace OctoberStudio +{ + public abstract class CameraSpaceProjectile : ProjectileBehavior + { + private Vector3 direction; + public Vector3 Direction { get => direction; set => direction = value; } + + public float Speed { get; set; } + + // Start is called before the first frame update + void Start() + { + + } + + public abstract Rect GetBounds(); + + public virtual void Update() + { + transform.position += direction * Time.deltaTime * Speed * PlayerBehavior.Player.ProjectileSpeedMultiplier; + + Rect bounds = GetBounds(); + + float distanceX; + if (CameraManager.IsPointOutsideCameraRight(bounds.max, out distanceX) || StageController.FieldManager.IsPointOutsideFieldRight(bounds.max, out distanceX)) + { + if (direction.x > 0) direction.x *= -1; + } + else if (CameraManager.IsPointOutsideCameraLeft(bounds.min, out distanceX) || StageController.FieldManager.IsPointOutsideFieldLeft(bounds.max, out distanceX)) + { + if (direction.x < 0) direction.x *= -1; + } + + if (distanceX > 0f) transform.position += direction * Mathf.Abs(distanceX / direction.x); + + float distanceY; + if (CameraManager.IsPointOutsideCameraTop(bounds.max, out distanceY) || StageController.FieldManager.IsPointOutsideFieldTop(bounds.max, out distanceY)) + { + if (direction.y > 0) direction.y *= -1; + } + else if (CameraManager.IsPointOutsideCameraBottom(bounds.min, out distanceY) || StageController.FieldManager.IsPointOutsideFieldBottom(bounds.max, out distanceY)) + { + if (direction.y < 0) direction.y *= -1; + } + + if (distanceY > 0) transform.position += direction * Mathf.Abs(distanceY / direction.y); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/CameraSpaceProjectile.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/CameraSpaceProjectile.cs.meta new file mode 100644 index 0000000..2f19d6c --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/CameraSpaceProjectile.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: daf1db02001455c45b8df205fb238b76 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/IAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/IAbilityBehavior.cs new file mode 100644 index 0000000..e6c3b67 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/IAbilityBehavior.cs @@ -0,0 +1,12 @@ +using OctoberStudio.Abilities; + +namespace OctoberStudio +{ + public interface IAbilityBehavior + { + AbilityType AbilityType { get; } + AbilityData AbilityData { get; } + void Init(AbilityData data, int stageId); + void Clear(); + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/IAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/IAbilityBehavior.cs.meta new file mode 100644 index 0000000..2fe5667 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/IAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ac557e1a1bcacdc43a89e76428e9e282 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities.meta new file mode 100644 index 0000000..b4350ee --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6eab8486186144a4f8045221f385ba7d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Cooldown.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Cooldown.meta new file mode 100644 index 0000000..bc22af3 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Cooldown.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c1d9f1ae3b456e64d80320390fb3254a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Cooldown/CooldownAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Cooldown/CooldownAbilityBehavior.cs new file mode 100644 index 0000000..cd2450c --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Cooldown/CooldownAbilityBehavior.cs @@ -0,0 +1,19 @@ +namespace OctoberStudio.Abilities +{ + public class CooldownAbilityBehavior : AbilityBehavior + { + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + PlayerBehavior.Player.RecalculateCooldownMuliplier(AbilityLevel.CooldownMultiplier); + } + + public override void Clear() + { + base.Clear(); + + PlayerBehavior.Player.RecalculateCooldownMuliplier(1); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Cooldown/CooldownAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Cooldown/CooldownAbilityBehavior.cs.meta new file mode 100644 index 0000000..134185a --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Cooldown/CooldownAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c7ab15eb11bd9274582d34afeb1e2bff +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Cooldown/CooldownAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Cooldown/CooldownAbilityData.cs new file mode 100644 index 0000000..c7ccecc --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Cooldown/CooldownAbilityData.cs @@ -0,0 +1,25 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Cooldown Ability Data", menuName = "October/Abilities/Passive/Cooldown")] + public class CooldownAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.Cooldown; + } + + private void OnValidate() + { + type = AbilityType.Cooldown; + } + } + + [System.Serializable] + public class CooldownAbilityLevel : AbilityLevel + { + [SerializeField, Range(0.1f, 1f)] float cooldownMultiplier = 1f; + public float CooldownMultiplier => cooldownMultiplier; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Cooldown/CooldownAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Cooldown/CooldownAbilityData.cs.meta new file mode 100644 index 0000000..4405737 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Cooldown/CooldownAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4993d821a20ea2e45a1f02d5edff9cd4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage Reduction.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage Reduction.meta new file mode 100644 index 0000000..98ba281 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage Reduction.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1b92dc8c63341444eaca927581061eee +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage Reduction/DamageReductionAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage Reduction/DamageReductionAbilityBehavior.cs new file mode 100644 index 0000000..1480350 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage Reduction/DamageReductionAbilityBehavior.cs @@ -0,0 +1,19 @@ +namespace OctoberStudio.Abilities +{ + public class DamageReductionAbilityBehavior : AbilityBehavior + { + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + PlayerBehavior.Player.RecalculateDamageReduction(AbilityLevel.DamageReductionPercent); + } + + public override void Clear() + { + base.Clear(); + + PlayerBehavior.Player.RecalculateDamageReduction(0); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage Reduction/DamageReductionAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage Reduction/DamageReductionAbilityBehavior.cs.meta new file mode 100644 index 0000000..be056d1 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage Reduction/DamageReductionAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 379e8f956c035934894d85a3bdff5f03 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage Reduction/DamageReductionAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage Reduction/DamageReductionAbilityData.cs new file mode 100644 index 0000000..531b78e --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage Reduction/DamageReductionAbilityData.cs @@ -0,0 +1,26 @@ +using OctoberStudio.Abilities; +using UnityEngine; + +namespace OctoberStudio +{ + [CreateAssetMenu(fileName = "Damage Reduction Ability Data", menuName = "October/Abilities/Passive/Damage Reduction")] + public class DamageReductionAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.DamageReduction; + } + + private void OnValidate() + { + type = AbilityType.DamageReduction; + } + } + + [System.Serializable] + public class DamageReductionAbilityLevel : AbilityLevel + { + [SerializeField, Range(1, 99)] int damageReductionPercent = 10; + public int DamageReductionPercent => damageReductionPercent; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage Reduction/DamageReductionAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage Reduction/DamageReductionAbilityData.cs.meta new file mode 100644 index 0000000..6b70c75 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage Reduction/DamageReductionAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 80567d708e2a27c42b25f3bc909504ed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage.meta new file mode 100644 index 0000000..bd9f6a2 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ef18190032004f9408195399810ddf80 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage/DamageAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage/DamageAbilityBehavior.cs new file mode 100644 index 0000000..16071b9 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage/DamageAbilityBehavior.cs @@ -0,0 +1,19 @@ +namespace OctoberStudio.Abilities +{ + public class DamageAbilityBehavior : AbilityBehavior + { + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + PlayerBehavior.Player.RecalculateDamage(AbilityLevel.DamageMultiplier); + } + + public override void Clear() + { + base.Clear(); + + PlayerBehavior.Player.RecalculateDamage(1); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage/DamageAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage/DamageAbilityBehavior.cs.meta new file mode 100644 index 0000000..11f4d72 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage/DamageAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ee670fe7045662c49a6e06f30c199d48 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage/DamageAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage/DamageAbilityData.cs new file mode 100644 index 0000000..3c3fd60 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage/DamageAbilityData.cs @@ -0,0 +1,25 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Damage Ability Data", menuName = "October/Abilities/Passive/Damage")] + public class DamageAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.Damage; + } + + private void OnValidate() + { + type = AbilityType.Damage; + } + } + + [System.Serializable] + public class DamageAbilityLevel : AbilityLevel + { + [SerializeField, Min(1f)] float damageMultiplier = 1f; + public float DamageMultiplier => damageMultiplier; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage/DamageAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage/DamageAbilityData.cs.meta new file mode 100644 index 0000000..bf6e7aa --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Damage/DamageAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 27811a4e1e5345c49af3035cf61ce11a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Duration.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Duration.meta new file mode 100644 index 0000000..ea6935d --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Duration.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5c0895cc7e1f7174b8a8c70ac84197b0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Duration/DurationAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Duration/DurationAbilityBehavior.cs new file mode 100644 index 0000000..2435673 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Duration/DurationAbilityBehavior.cs @@ -0,0 +1,19 @@ +namespace OctoberStudio.Abilities +{ + public class DurationAbilityBehavior : AbilityBehavior + { + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + PlayerBehavior.Player.RecalculateDurationMultiplier(AbilityLevel.DurationMultiplier); + } + + public override void Clear() + { + base.Clear(); + + PlayerBehavior.Player.RecalculateDurationMultiplier(1); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Duration/DurationAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Duration/DurationAbilityBehavior.cs.meta new file mode 100644 index 0000000..c847a2f --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Duration/DurationAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 13667f4df42d03d45bf048884bfbc6d7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Duration/DurationAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Duration/DurationAbilityData.cs new file mode 100644 index 0000000..73a52ee --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Duration/DurationAbilityData.cs @@ -0,0 +1,25 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Duration Ability Data", menuName = "October/Abilities/Passive/Duration")] + public class DurationAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.Duration; + } + + private void OnValidate() + { + type = AbilityType.Duration; + } + } + + [System.Serializable] + public class DurationAbilityLevel : AbilityLevel + { + [SerializeField, Min(1)] float durationMultiplier = 1; + public float DurationMultiplier => durationMultiplier; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Duration/DurationAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Duration/DurationAbilityData.cs.meta new file mode 100644 index 0000000..18c5e71 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Duration/DurationAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ddcefea9e6c1a38469cce16fcdd79c04 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Gold.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Gold.meta new file mode 100644 index 0000000..f78061e --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Gold.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d4446813b3c6fd34bbd0febea5d21228 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Gold/GoldEndgameAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Gold/GoldEndgameAbilityBehavior.cs new file mode 100644 index 0000000..6f17c7f --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Gold/GoldEndgameAbilityBehavior.cs @@ -0,0 +1,20 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class GoldEndgameAbilityBehavior : AbilityBehavior + { + protected override void SetAbilityLevel(int levelId) + { + base.SetAbilityLevel(levelId); + + var gold = AbilityLevel.GoldAmount * PlayerBehavior.Player.GoldMultiplier; + var clampedGold = Mathf.RoundToInt(gold); + + GameController.TempGold.Deposit(clampedGold); + } + } +} + diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Gold/GoldEndgameAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Gold/GoldEndgameAbilityBehavior.cs.meta new file mode 100644 index 0000000..bbbc898 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Gold/GoldEndgameAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 83122d2f10a723244af3b7f9abccfffe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Gold/GoldEndgameAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Gold/GoldEndgameAbilityData.cs new file mode 100644 index 0000000..44c9458 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Gold/GoldEndgameAbilityData.cs @@ -0,0 +1,26 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Gold Endgame Ability Data", menuName = "October/Abilities/Passive/Gold Endgame")] + public class GoldEndgameAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.GoldEndgame; + } + + private void OnValidate() + { + type = AbilityType.GoldEndgame; + } + } + + [System.Serializable] + public class GoldEndgameAbilityLevel : AbilityLevel + { + [Tooltip("Give the player a specified amount of gold")] + [SerializeField, Min(1)] int goldAmount = 40; + public int GoldAmount => goldAmount; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Gold/GoldEndgameAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Gold/GoldEndgameAbilityData.cs.meta new file mode 100644 index 0000000..44a5c57 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Gold/GoldEndgameAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 61300d54e4355ed4cae8799f8c4d9c26 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Heal.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Heal.meta new file mode 100644 index 0000000..b92b8be --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Heal.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b1352d2e894ef0943a98de0ad9e08e95 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Heal/HealEndgameAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Heal/HealEndgameAbilityBehavior.cs new file mode 100644 index 0000000..12f020f --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Heal/HealEndgameAbilityBehavior.cs @@ -0,0 +1,17 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class HealEndgameAbilityBehavior : AbilityBehavior + { + protected override void SetAbilityLevel(int levelId) + { + base.SetAbilityLevel(levelId); + + PlayerBehavior.Player.RestoreHP(AbilityLevel.HealPersentage); + } + } +} + diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Heal/HealEndgameAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Heal/HealEndgameAbilityBehavior.cs.meta new file mode 100644 index 0000000..d6841bf --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Heal/HealEndgameAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a21277ce3c3b2c74da7ad86786ae0c4e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Heal/HealEndgameAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Heal/HealEndgameAbilityData.cs new file mode 100644 index 0000000..c2ba291 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Heal/HealEndgameAbilityData.cs @@ -0,0 +1,26 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Heal Endgame Ability Data", menuName = "October/Abilities/Passive/Heal Endgame")] + public class HealEndgameAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.HealEndgame; + } + + private void OnValidate() + { + type = AbilityType.HealEndgame; + } + } + + [System.Serializable] + public class HealEndgameAbilityLevel : AbilityLevel + { + [Tooltip("Heal the player by the persentage of their max hp")] + [SerializeField, Range(0, 100)] int healPersentage = 40; + public int HealPersentage => healPersentage; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Heal/HealEndgameAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Heal/HealEndgameAbilityData.cs.meta new file mode 100644 index 0000000..4918561 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Endgame Heal/HealEndgameAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0d4428a2a0945e7429675f5c6a7cf695 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Increased Gold.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Increased Gold.meta new file mode 100644 index 0000000..0f82f05 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Increased Gold.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 80665be6ea0f6ff47ab6650f3a428e6e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Increased Gold/GoldAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Increased Gold/GoldAbilityBehavior.cs new file mode 100644 index 0000000..9ffe30d --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Increased Gold/GoldAbilityBehavior.cs @@ -0,0 +1,19 @@ +namespace OctoberStudio.Abilities +{ + public class GoldAbilityBehavior : AbilityBehavior + { + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + PlayerBehavior.Player.RecalculateGoldMultiplier(AbilityLevel.GoldMultiplier); + } + + public override void Clear() + { + base.Clear(); + + PlayerBehavior.Player.RecalculateGoldMultiplier(1); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Increased Gold/GoldAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Increased Gold/GoldAbilityBehavior.cs.meta new file mode 100644 index 0000000..6322151 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Increased Gold/GoldAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e6312095e560a0f4796ad8c9e7fd7719 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Increased Gold/GoldAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Increased Gold/GoldAbilityData.cs new file mode 100644 index 0000000..00e840b --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Increased Gold/GoldAbilityData.cs @@ -0,0 +1,25 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Gold Ability Data", menuName = "October/Abilities/Passive/Gold")] + public class GoldAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.IncreasedGold; + } + + private void OnValidate() + { + type = AbilityType.IncreasedGold; + } + } + + [System.Serializable] + public class GoldAbilityLevel : AbilityLevel + { + [SerializeField, Min(1)] float goldMultiplier = 1; + public float GoldMultiplier => goldMultiplier; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Increased Gold/GoldAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Increased Gold/GoldAbilityData.cs.meta new file mode 100644 index 0000000..a21040a --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Increased Gold/GoldAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2e293eb14a87432429512420c3c8ac6a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Magnet.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Magnet.meta new file mode 100644 index 0000000..197ad10 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Magnet.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eede157ce3116dc499e32ccfc813cfa0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Magnet/MagnetAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Magnet/MagnetAbilityBehavior.cs new file mode 100644 index 0000000..82d5504 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Magnet/MagnetAbilityBehavior.cs @@ -0,0 +1,19 @@ +namespace OctoberStudio.Abilities +{ + public class MagnetAbilityBehavior : AbilityBehavior + { + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + PlayerBehavior.Player.RecalculateMagnetRadius(AbilityLevel.RadiusMultiplier); + } + + public override void Clear() + { + base.Clear(); + + PlayerBehavior.Player.RecalculateMagnetRadius(1); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Magnet/MagnetAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Magnet/MagnetAbilityBehavior.cs.meta new file mode 100644 index 0000000..5932ba3 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Magnet/MagnetAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dc6cfaf896a74a6428dac19e5a705ce5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Magnet/MagnetAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Magnet/MagnetAbilityData.cs new file mode 100644 index 0000000..18eef89 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Magnet/MagnetAbilityData.cs @@ -0,0 +1,25 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Magnet Ability Data", menuName = "October/Abilities/Passive/Magnet")] + public class MagnetAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.Magnet; + } + + private void OnValidate() + { + type = AbilityType.Magnet; + } + } + + [System.Serializable] + public class MagnetAbilityLevel : AbilityLevel + { + [SerializeField, Min(1f)] float radiusMultiplier = 1f; + public float RadiusMultiplier => radiusMultiplier; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Magnet/MagnetAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Magnet/MagnetAbilityData.cs.meta new file mode 100644 index 0000000..f196d30 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Magnet/MagnetAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 69a603a3e05b0a14e81aad0ae1e51e6a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Max HP.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Max HP.meta new file mode 100644 index 0000000..2501c2d --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Max HP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8e6cdcd401e1efd4895b97516523ed1b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Max HP/MaxHPAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Max HP/MaxHPAbilityBehavior.cs new file mode 100644 index 0000000..295b76e --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Max HP/MaxHPAbilityBehavior.cs @@ -0,0 +1,19 @@ +namespace OctoberStudio.Abilities +{ + public class MaxHPAbilityBehavior : AbilityBehavior + { + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + PlayerBehavior.Player.RecalculateMaxHP(AbilityLevel.MaxHPMultiplier); + } + + public override void Clear() + { + base.Clear(); + + PlayerBehavior.Player.RecalculateMaxHP(1); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Max HP/MaxHPAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Max HP/MaxHPAbilityBehavior.cs.meta new file mode 100644 index 0000000..9f927ee --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Max HP/MaxHPAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 672a3e85f9bf3534b828a24573214de9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Max HP/MaxHPAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Max HP/MaxHPAbilityData.cs new file mode 100644 index 0000000..1ef813b --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Max HP/MaxHPAbilityData.cs @@ -0,0 +1,25 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Max HP Ability Data", menuName = "October/Abilities/Passive/Max HP")] + public class MaxHPAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.MaxHP; + } + + private void OnValidate() + { + type = AbilityType.MaxHP; + } + } + + [System.Serializable] + public class MaxHPAbilityLevel : AbilityLevel + { + [SerializeField, Min(1f)] float maxHPMultiplier = 1f; + public float MaxHPMultiplier => maxHPMultiplier; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Max HP/MaxHPAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Max HP/MaxHPAbilityData.cs.meta new file mode 100644 index 0000000..e1ed513 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Max HP/MaxHPAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 836da791dfdd51a43b63a8106936ab66 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Move Speed.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Move Speed.meta new file mode 100644 index 0000000..7dfcea5 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Move Speed.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9560f9586443d784d8829e0f1067f2fd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Move Speed/MoveSpeedAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Move Speed/MoveSpeedAbilityData.cs new file mode 100644 index 0000000..29e1afa --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Move Speed/MoveSpeedAbilityData.cs @@ -0,0 +1,25 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Move Speed Ability Data", menuName = "October/Abilities/Passive/Move Speed")] + public class MoveSpeedAbilityData: GenericAbilityData + { + private void Awake() + { + type = AbilityType.MoveSpeed; + } + + private void OnValidate() + { + type = AbilityType.MoveSpeed; + } + } + + [System.Serializable] + public class MoveSpeedAbilityLevel : AbilityLevel + { + [SerializeField, Min(1f)] float speedMultiplier = 1f; + public float SpeedMultiplier => speedMultiplier; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Move Speed/MoveSpeedAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Move Speed/MoveSpeedAbilityData.cs.meta new file mode 100644 index 0000000..6d15c04 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Move Speed/MoveSpeedAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a76f2259899b0db46a67c9cea309929d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Move Speed/SportShoesAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Move Speed/SportShoesAbilityBehavior.cs new file mode 100644 index 0000000..3c367a9 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Move Speed/SportShoesAbilityBehavior.cs @@ -0,0 +1,19 @@ +namespace OctoberStudio.Abilities +{ + public class SportShoesAbilityBehavior : AbilityBehavior + { + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + PlayerBehavior.Player.RecalculateMoveSpeed(AbilityLevel.SpeedMultiplier); + } + + public override void Clear() + { + base.Clear(); + + PlayerBehavior.Player.RecalculateMoveSpeed(1); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Move Speed/SportShoesAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Move Speed/SportShoesAbilityBehavior.cs.meta new file mode 100644 index 0000000..a7d0fc4 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Move Speed/SportShoesAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7b0010876017c19459ce21f77a2eab6f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Projectile Speed.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Projectile Speed.meta new file mode 100644 index 0000000..8a87861 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Projectile Speed.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f67465587aaed824ea9c909d711e298b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Projectile Speed/ProjectileSpeedAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Projectile Speed/ProjectileSpeedAbilityBehavior.cs new file mode 100644 index 0000000..a5e950d --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Projectile Speed/ProjectileSpeedAbilityBehavior.cs @@ -0,0 +1,19 @@ +namespace OctoberStudio.Abilities +{ + public class ProjectileSpeedAbilityBehavior : AbilityBehavior + { + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + PlayerBehavior.Player.RecalculateProjectileSpeedMultiplier(AbilityLevel.ProjectileSpeedMultiplier); + } + + public override void Clear() + { + base.Clear(); + + PlayerBehavior.Player.RecalculateProjectileSpeedMultiplier(1); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Projectile Speed/ProjectileSpeedAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Projectile Speed/ProjectileSpeedAbilityBehavior.cs.meta new file mode 100644 index 0000000..a5275bd --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Projectile Speed/ProjectileSpeedAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 25b77c5b7e799e04a8f5c86027b8e021 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Projectile Speed/ProjectileSpeedAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Projectile Speed/ProjectileSpeedAbilityData.cs new file mode 100644 index 0000000..4391ea2 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Projectile Speed/ProjectileSpeedAbilityData.cs @@ -0,0 +1,26 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + + [CreateAssetMenu(fileName = "Projectile Speed Ability Data", menuName = "October/Abilities/Passive/Projectile Speed")] + public class ProjectileSpeedAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.ProjectileSpeed; + } + + private void OnValidate() + { + type = AbilityType.ProjectileSpeed; + } + } + + [System.Serializable] + public class ProjectileSpeedAbilityLevel : AbilityLevel + { + [SerializeField, Min(1f)] float projectileSpeedMultiplier = 1f; + public float ProjectileSpeedMultiplier => projectileSpeedMultiplier; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Projectile Speed/ProjectileSpeedAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Projectile Speed/ProjectileSpeedAbilityData.cs.meta new file mode 100644 index 0000000..894789c --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Projectile Speed/ProjectileSpeedAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e7071a3204d49c545801f25ffb445d84 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Restore HP.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Restore HP.meta new file mode 100644 index 0000000..712c24e --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Restore HP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b4a968d2cbc50c64699c9021c72e3067 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Restore HP/RestoreHPAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Restore HP/RestoreHPAbilityBehavior.cs new file mode 100644 index 0000000..76e609d --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Restore HP/RestoreHPAbilityBehavior.cs @@ -0,0 +1,40 @@ +using OctoberStudio.Abilities; +using System.Collections; +using UnityEngine; + +namespace OctoberStudio +{ + public class RestoreHPAbilityBehavior : AbilityBehavior + { + protected Coroutine coroutine; + + public override void Init(AbilityData data, int stageId) + { + base.Init(data, stageId); + + coroutine = StartCoroutine(AbilityCoroutine()); + } + + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + } + + private IEnumerator AbilityCoroutine() + { + while (true) + { + PlayerBehavior.Player.RestoreHP(AbilityLevel.RestoredHPPercent); + + yield return new WaitForSeconds(AbilityLevel.Cooldown * PlayerBehavior.Player.CooldownMultiplier); + } + } + + public override void Clear() + { + if(coroutine != null) StopCoroutine(coroutine); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Restore HP/RestoreHPAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Restore HP/RestoreHPAbilityBehavior.cs.meta new file mode 100644 index 0000000..bb873de --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Restore HP/RestoreHPAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cf3d5eeba9a4bf64683d7d28013b70f4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Restore HP/RestoreHPAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Restore HP/RestoreHPAbilityData.cs new file mode 100644 index 0000000..70acd9c --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Restore HP/RestoreHPAbilityData.cs @@ -0,0 +1,28 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Restore HP Ability Data", menuName = "October/Abilities/Passive/Restore HP")] + public class RestoreHPAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.RestoreHP; + } + + private void OnValidate() + { + type = AbilityType.RestoreHP; + } + } + + [System.Serializable] + public class RestoreHPAbilityLevel : AbilityLevel + { + [SerializeField, Range(0f, 20f)] int restoredHPPercent = 1; + public int RestoredHPPercent => restoredHPPercent; + + [SerializeField] float cooldown; + public float Cooldown => cooldown; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Restore HP/RestoreHPAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Restore HP/RestoreHPAbilityData.cs.meta new file mode 100644 index 0000000..f0c31e0 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Restore HP/RestoreHPAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d9fe18c54c4716e48be4d22e29ffe7a0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Size.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Size.meta new file mode 100644 index 0000000..cdd9d9a --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Size.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 152af7908d6573d4ab145370da5b21bf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Size/SizeAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Size/SizeAbilityBehavior.cs new file mode 100644 index 0000000..3d948c0 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Size/SizeAbilityBehavior.cs @@ -0,0 +1,19 @@ +namespace OctoberStudio.Abilities +{ + public class SizeAbilityBehavior : AbilityBehavior + { + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + PlayerBehavior.Player.RecalculateSizeMultiplier(AbilityLevel.SizeMultiplier); + } + + public override void Clear() + { + base.Clear(); + + PlayerBehavior.Player.RecalculateSizeMultiplier(1); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Size/SizeAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Size/SizeAbilityBehavior.cs.meta new file mode 100644 index 0000000..4f56d06 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Size/SizeAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bb2c8fec874a705408f5c8cb799fb4fe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Size/SizeAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Size/SizeAbilityData.cs new file mode 100644 index 0000000..17bcb09 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Size/SizeAbilityData.cs @@ -0,0 +1,25 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Size Ability Data", menuName = "October/Abilities/Passive/Size")] + public class SizeAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.Size; + } + + private void OnValidate() + { + type = AbilityType.Size; + } + } + + [System.Serializable] + public class SizeAbilityLevel : AbilityLevel + { + [SerializeField, Min(1)] float sizeMultiplier = 1; + public float SizeMultiplier => sizeMultiplier; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Size/SizeAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Size/SizeAbilityData.cs.meta new file mode 100644 index 0000000..46bf216 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/Size/SizeAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 42eac6d655d395e42bd4c18409d47a17 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/XP.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/XP.meta new file mode 100644 index 0000000..d5a2533 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/XP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 80add8ae6ece9d44cba6200519f9b6f2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/XP/XPAbilityBehavior.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/XP/XPAbilityBehavior.cs new file mode 100644 index 0000000..f8c5769 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/XP/XPAbilityBehavior.cs @@ -0,0 +1,19 @@ +namespace OctoberStudio.Abilities +{ + public class XPAbilityBehavior : AbilityBehavior + { + protected override void SetAbilityLevel(int stageId) + { + base.SetAbilityLevel(stageId); + + PlayerBehavior.Player.RecalculateXPMuliplier(AbilityLevel.XPMultiplier); + } + + public override void Clear() + { + base.Clear(); + + PlayerBehavior.Player.RecalculateXPMuliplier(1); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/XP/XPAbilityBehavior.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/XP/XPAbilityBehavior.cs.meta new file mode 100644 index 0000000..9870755 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/XP/XPAbilityBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a15d6c36cf47fcb4e8ad1a5b4971c332 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/XP/XPAbilityData.cs b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/XP/XPAbilityData.cs new file mode 100644 index 0000000..41f2afa --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/XP/XPAbilityData.cs @@ -0,0 +1,25 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "XP Ability Data", menuName = "October/Abilities/Passive/XP")] + public class XPAbilityData : GenericAbilityData + { + private void Awake() + { + type = AbilityType.XP; + } + + private void OnValidate() + { + type = AbilityType.XP; + } + } + + [System.Serializable] + public class XPAbilityLevel : AbilityLevel + { + [SerializeField, Min(1f)] float xpMultiplier = 1f; + public float XPMultiplier => xpMultiplier; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/XP/XPAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/XP/XPAbilityData.cs.meta new file mode 100644 index 0000000..d9d251f --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Behaviors/Passive Abilities/XP/XPAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f352f4c5114321b47afd027220a77c40 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Data.meta b/Assets/Common/Scripts/Abilities/Data.meta new file mode 100644 index 0000000..7f4bd3d --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Data.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 57ff6c9dfb934a34785b21dbb73b697b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Data/AbilitiesDatabase.cs b/Assets/Common/Scripts/Abilities/Data/AbilitiesDatabase.cs new file mode 100644 index 0000000..0e74855 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Data/AbilitiesDatabase.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [CreateAssetMenu(fileName = "Abilities Database", menuName = "October/Abilities/Database")] + public class AbilitiesDatabase : ScriptableObject + { + [SerializeField] int activeAbilitiesCapacity = 5; + [SerializeField] int passiveAbilitiesCapacity = 5; + + public int ActiveAbilitiesCapacity => activeAbilitiesCapacity; + public int PassiveAbilitiesCapacity => passiveAbilitiesCapacity; + + [Header("Abilities Weight Multipliers")] + [SerializeField] float firstLevelsActiveAbilityWeightMultiplier = 1.2f; + [SerializeField] float aquiredAbilityWeightMultiplier = 1.2f; + [SerializeField] float lessAbilitiesOfTypeWeightMultiplier = 1.2f; + [SerializeField] float evolutionAbilityWeightMultiplier = 10f; + [SerializeField] float requiredForEvolutionWeightMultiplier = 1.2f; + + public float FirstLevelsActiveAbilityWeightMultiplier => firstLevelsActiveAbilityWeightMultiplier; + public float AquiredAbilityWeightMultiplier => aquiredAbilityWeightMultiplier; + public float LessAbilitiesOfTypeWeightMultiplier => lessAbilitiesOfTypeWeightMultiplier; + public float EvolutionAbilityWeightMultiplier => evolutionAbilityWeightMultiplier; + public float RequiredForEvolutionWeightMultiplier => requiredForEvolutionWeightMultiplier; + + + [SerializeField] List abilities; + + public int AbilitiesCount => abilities.Count; + + public AbilityData GetAbility(int index) + { + return abilities[index]; + } + + public AbilityData GetAbility(AbilityType type) + { + for(int i = 0; i < abilities.Count; i++) + { + AbilityData ability = abilities[i]; + + if(ability.AbilityType == type) return ability; + } + + return null; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Data/AbilitiesDatabase.cs.meta b/Assets/Common/Scripts/Abilities/Data/AbilitiesDatabase.cs.meta new file mode 100644 index 0000000..211b756 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Data/AbilitiesDatabase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2f769f2d35f4a354ab98600d8c1dbb7d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Data/AbilitiesSave.cs b/Assets/Common/Scripts/Abilities/Data/AbilitiesSave.cs new file mode 100644 index 0000000..c54f2f5 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Data/AbilitiesSave.cs @@ -0,0 +1,109 @@ +using OctoberStudio.Save; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + [System.Serializable] + public class AbilitiesSave : ISave + { + [SerializeField] AbilitySave[] savedAbilities; + + private Dictionary abilitiesLevels; + + public void Init() + { + abilitiesLevels = new Dictionary(); + + if(savedAbilities == null) savedAbilities = new AbilitySave[0]; + + for(int i = 0; i < savedAbilities.Length; i++) + { + var save = savedAbilities[i]; + + if (abilitiesLevels.ContainsKey(save.AbilityType)) + { + var savedLevel = abilitiesLevels[save.AbilityType]; + + if(save.Level > savedLevel) + { + abilitiesLevels[save.AbilityType] = save.Level; + } + } else + { + abilitiesLevels.Add(save.AbilityType, save.Level); + } + } + } + + public List GetSavedAbilities() + { + return abilitiesLevels.Keys.ToList(); + } + + public int GetAbilityLevel(AbilityType ability) + { + if (abilitiesLevels.ContainsKey(ability)) + { + return abilitiesLevels[ability]; + } else + { + return -1; + } + } + + public void SetAbilityLevel(AbilityType ability, int level) + { + if (abilitiesLevels.ContainsKey(ability)) + { + abilitiesLevels[ability] = level; + } else + { + abilitiesLevels.Add(ability, level); + } + } + + public void RemoveAbility(AbilityType ability) + { + if (abilitiesLevels.ContainsKey(ability)) + { + abilitiesLevels.Remove(ability); + } + } + + public void Flush() + { + savedAbilities = new AbilitySave[abilitiesLevels.Count]; + + int i = 0; + + foreach(var ability in abilitiesLevels.Keys) + { + var abilitySave = new AbilitySave(ability, abilitiesLevels[ability]); + savedAbilities[i++] = abilitySave; + } + } + + public void Clear() + { + abilitiesLevels.Clear(); + } + + [System.Serializable] + private class AbilitySave + { + [SerializeField] AbilityType abilityType; + [SerializeField] int level; + + public AbilityType AbilityType => abilityType; + public int Level => level; + + public AbilitySave(AbilityType abilityType, int level) + { + this.abilityType = abilityType; + this.level = level; + } + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Data/AbilitiesSave.cs.meta b/Assets/Common/Scripts/Abilities/Data/AbilitiesSave.cs.meta new file mode 100644 index 0000000..3d45bda --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Data/AbilitiesSave.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3575479ea3278d341ae99e82ea5015b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Data/AbilityData.cs b/Assets/Common/Scripts/Abilities/Data/AbilityData.cs new file mode 100644 index 0000000..791e2cc --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Data/AbilityData.cs @@ -0,0 +1,88 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio.Abilities +{ + public abstract class AbilityData : ScriptableObject + { + [Tooltip("The unique identifier of an ability")] + [SerializeField] protected AbilityType type; + public AbilityType AbilityType => type; + + [Tooltip("Shoud be short, no more than two words")] + [SerializeField] string title; + public string Title => title; + + [Tooltip("Keep it brief but informative")] + [SerializeField] string description; + public string Description => description; + + [Tooltip("Image that will appear on the ui")] + [SerializeField] Sprite icon; + public Sprite Icon => icon; + + [Tooltip("Prefab with the implementation of the ability")] + [SerializeField] GameObject prefab; + public GameObject Prefab => prefab; + + [SerializeField] protected bool isActiveAbility; + public bool IsActiveAbility => isActiveAbility; + + [Tooltip("Whether this ability is linked to the weapon. It will be shown to the player only if the character has the linked weapon equipped")] + [SerializeField] protected bool isWeaponAbility; + public bool IsWeaponAbility => isWeaponAbility; + + [Tooltip("This ability will only be shown if there are no other abilities available. Cannot be upgraded, always applies it's first level")] + [SerializeField] protected bool isEndgameAbility; + public bool IsEndgameAbility => isEndgameAbility; + + [Tooltip("Whether this ability is the evolution of other abilities. It will be shown to the player only if the evolution requirements are met")] + [SerializeField] bool isEvolution; + public bool IsEvolution => isEvolution; + + [Tooltip("The requirements for this ability to be shown to the player. Ignore this field if the 'isEvolution' field is false")] + [SerializeField] List evolutionRequirements; + public List EvolutionRequirements => evolutionRequirements; + + public abstract AbilityLevel[] Levels { get; } + public int LevelsCount => Levels.Length; + + public event UnityAction onAbilityUpgraded; + + public void Upgrade(int level) + { + if(level < LevelsCount) + { + onAbilityUpgraded?.Invoke(level); + } + } + + public AbilityLevel GetLevel(int index) + { + return Levels[index]; + } + } + + [System.Serializable] + public abstract class AbilityLevel + { + + } + + [System.Serializable] + public class EvolutionRequirement + { + [Tooltip("This ability should be active to trigger the evolution")] + [SerializeField] AbilityType abilityType; + public AbilityType AbilityType => abilityType; + + [Tooltip("The level of the ability needed to trigger the evolution")] + [SerializeField, Min(0)] int requiredAbilityLevel; + public int RequiredAbilityLevel => requiredAbilityLevel; + + [Tooltip("Whether this ability should be disabled after the evolution")] + [SerializeField] bool shouldRemoveAfterEvolution; + public bool ShouldRemoveAfterEvolution => shouldRemoveAfterEvolution; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Data/AbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Data/AbilityData.cs.meta new file mode 100644 index 0000000..eea44ac --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Data/AbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0481d404b8d9a0e4ca44e59a5e85bea2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Data/AbilityManager.cs b/Assets/Common/Scripts/Abilities/Data/AbilityManager.cs new file mode 100644 index 0000000..fe5be09 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Data/AbilityManager.cs @@ -0,0 +1,733 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + using OctoberStudio.Easing; + using OctoberStudio.Extensions; + + public class AbilityManager : MonoBehaviour + { + [SerializeField] protected AbilitiesDatabase abilitiesDatabase; + + [Space] + [SerializeField, Range(0, 1)] protected float chestChanceTier5; + [SerializeField, Range(0, 1)] protected float chestChanceTier3; + + protected List aquiredAbilities = new List(); + protected List removedAbilities = new List(); + protected AbilitiesSave save; + protected StageSave stageSave; + + public int ActiveAbilitiesCapacity => abilitiesDatabase.ActiveAbilitiesCapacity; + public int PassiveAbilitiesCapacity => abilitiesDatabase.PassiveAbilitiesCapacity; + + protected virtual void Awake() + { + save = GameController.SaveManager.GetSave("Abilities Save"); + save.Init(); + + stageSave = GameController.SaveManager.GetSave("Stage"); + + // Usualy the data isn't getting reset only if the Player continues the game after they've closed it without dying + if(stageSave.ResetStageData) save.Clear(); + } + + public virtual void Init(PresetData testingPreset, CharacterData characterData) + { + StageController.ExperienceManager.onXpLevelChanged += OnXpLevelChanged; + + if(testingPreset != null) + { + // If testing preset is assigned, loading starting abilities from it + + for (int i = 0; testingPreset.Abilities.Count > i; i++) + { + AbilityType type = testingPreset.Abilities[i].abilityType; + + AbilityData data = abilitiesDatabase.GetAbility(type); + AddAbility(data, testingPreset.Abilities[i].level); + } + } else if (!stageSave.ResetStageData) + { + // The game is being continued after the Player exited it without dying. Loading abilities from the save file + + var savedAbilities = save.GetSavedAbilities(); + for(int i = 0; i < savedAbilities.Count; i++) + { + AbilityType type = savedAbilities[i]; + + AbilityData data = abilitiesDatabase.GetAbility(type); + AddAbility(data, save.GetAbilityLevel(type)); + } + + // If there are no abilities stored in the save file, than we're loading character's starting ability or showing weapon selection window if there are none + + if(savedAbilities.Count == 0) + { + if (characterData.HasStartingAbility) + { + AbilityData data = abilitiesDatabase.GetAbility(characterData.StartingAbility); + AddAbility(data, 0); + } else + { + EasingManager.DoAfter(0.3f, ShowWeaponSelectScreen); + } + + } + } else if (characterData.HasStartingAbility) + { + // No testing presets or abilities from save file, loading character starting ability. + + AbilityData data = abilitiesDatabase.GetAbility(characterData.StartingAbility); + AddAbility(data, 0); + } + else + { + // Just showing weapon selection window with some delay + + EasingManager.DoAfter(0.3f, ShowWeaponSelectScreen); + } + } + + public virtual void AddAbility(AbilityData abilityData, int level = 0) + { + IAbilityBehavior ability = Instantiate(abilityData.Prefab).GetComponent(); + ability.Init(abilityData, level); + + if (abilityData.IsEvolution) + { + // For the evolution ability we have to search for every requirement, + // find if it was met, and remove all abilities that are being evolved from + + for (int i = 0; i < abilityData.EvolutionRequirements.Count; i++) + { + var requirement = abilityData.EvolutionRequirements[i]; + + if (requirement.ShouldRemoveAfterEvolution) + { + var requiredAbility = GetAquiredAbility(requirement.AbilityType); + + if (requiredAbility != null) + { + // Abilities' game object is being destroyed inside + requiredAbility.Clear(); + + aquiredAbilities.Remove(requiredAbility); + save.RemoveAbility(requiredAbility.AbilityType); + + removedAbilities.Add(requiredAbility.AbilityType); + } + } + } + } + + save.SetAbilityLevel(abilityData.AbilityType, level); + aquiredAbilities.Add(ability); + } + + public virtual int GetActiveAbilitiesCount() + { + // Crude, but it's called rearly, so no harm + int counter = 0; + foreach(var ability in aquiredAbilities) + { + if (ability.AbilityData.IsActiveAbility) counter++; + } + return counter; + } + + public virtual int GetPassiveAbilitiesCount() + { + // Crude, but it's called rearly, so no harm + int counter = 0; + foreach (var ability in aquiredAbilities) + { + if (!ability.AbilityData.IsActiveAbility) counter++; + } + return counter; + } + + protected virtual void ShowWeaponSelectScreen() + { + var weaponAbilities = new List(); + + // Finding all weapon abilities that arn't evolutinons + + for (int i = 0; i < abilitiesDatabase.AbilitiesCount; i++) + { + var abilityData = abilitiesDatabase.GetAbility(i); + + if (abilityData.IsWeaponAbility && !abilityData.IsEvolution) + { + weaponAbilities.Add(abilityData); + } + } + + // Randomly selecting up to three of them + + var selectedAbilities = new List(); + + while (weaponAbilities.Count > 0 && selectedAbilities.Count < 3) + { + var abilityData = weaponAbilities.PopRandom(); + selectedAbilities.Add(abilityData); + } + + // A check just to be sure, if there are none selected abilities then clearly something gone wrong. + // In that case should check if there are weapon abilities assigned to the abilities database at all + + if (selectedAbilities.Count > 0) + { + StageController.GameScreen.ShowAbilitiesPanel(selectedAbilities, false); + } + } + + protected virtual void OnXpLevelChanged(int level) + { + var abilities = GetAvailableAbilities(); + var selectedAbilities = new List(); + + var weightedAbilities = new List(); + + bool firstLevels = level < 10; + + var activeCount = GetActiveAbilitiesCount(); + var passiveCount = GetPassiveAbilitiesCount(); + + bool moreActive = activeCount > passiveCount; + bool morePassive = passiveCount > activeCount; + + // Here we are populating list of abilities with weights. + // Depending on the multipliers in the abilities database, some abilities will have higher chance to be selected + // For example, usualy evolution abilities should be selected every time they are available + + foreach (var ability in abilities) + { + var weight = 1f; + + if (IsAbilityAquired(ability.AbilityType)) weight *= abilitiesDatabase.AquiredAbilityWeightMultiplier; + + if (ability.IsActiveAbility) + { + if (firstLevels) weight *= abilitiesDatabase.FirstLevelsActiveAbilityWeightMultiplier; + if (morePassive) weight *= abilitiesDatabase.LessAbilitiesOfTypeWeightMultiplier; + if (ability.IsEvolution) weight *= abilitiesDatabase.EvolutionAbilityWeightMultiplier; + } else + { + if (IsRequiredForAquiredEvolution(ability.AbilityType)) weight *= abilitiesDatabase.RequiredForEvolutionWeightMultiplier; + if (moreActive) weight *= abilitiesDatabase.LessAbilitiesOfTypeWeightMultiplier; + } + + weightedAbilities.Add(new WeightedAbility() { abilityData = ability, weight = weight }); + } + + while (abilities.Count > 0 && selectedAbilities.Count < 3) + { + // Here we're evening out weights so that their sum was exactly 1 + + float weightSum = 0f; + foreach(var container in weightedAbilities) weightSum += container.weight; + + foreach (var container in weightedAbilities) container.weight /= weightSum; + + // Getting random value between 0 and 1, + // Iteraing abilities until the sum of ther weight is more than the random value + // if the random value is 0, we'll select the first ability + // if it is 1, we'll select the last one + + float random = Random.value; + float progress = 0; + + AbilityData selectedAbility = null; + + foreach (var container in weightedAbilities) + { + progress += container.weight; + + if(random <= progress) + { + selectedAbility = container.abilityData; + break; + } + } + + // If we've successfully selected an ability (as we should have been), were removing it from the pool of available abilities + // If something gone wrong, we have a failsafe - just completely randomly selecting one of the available abilities + if(selectedAbility != null) + { + abilities.Remove(selectedAbility); + } else + { + selectedAbility = abilities.PopRandom(); + } + + // Removing selected ability from the weighted abilities list + + foreach (var container in weightedAbilities) + { + if(container.abilityData == selectedAbility) + { + weightedAbilities.Remove(container); + break; + } + } + + selectedAbilities.Add(selectedAbility); + } + + if(selectedAbilities.Count > 0) + { + StageController.GameScreen.ShowAbilitiesPanel(selectedAbilities, true); + } + } + + protected virtual List GetAvailableAbilities() + { + var result = new List(); + + // Counting the number of passive and active aquired abilities. + // We have a max amount of each type of abilities specified in the abilities database + + int activeAbilitiesCount = 0; + int passiveAbilitiesCount = 0; + + for(int i = 0; i < aquiredAbilities.Count; i++) + { + var abilityBehavior = aquiredAbilities[i]; + var abilityData = abilitiesDatabase.GetAbility(abilityBehavior.AbilityType); + + if (abilityData.IsActiveAbility) + { + activeAbilitiesCount++; + } else + { + passiveAbilitiesCount++; + } + } + + for (int i = 0; i < abilitiesDatabase.AbilitiesCount; i++) + { + var abilityData = abilitiesDatabase.GetAbility(i); + + // This ability only shows up when the are no more other abilities left. + // Usually it's some kind of heal or gold + + if (abilityData.IsEndgameAbility) continue; + + // The ability is at it's last level. There are no way to upgrade it further + + if (save.GetAbilityLevel(abilityData.AbilityType) >= abilityData.LevelsCount - 1) continue; + + // The ability was evolved + + if (removedAbilities.Contains(abilityData.AbilityType)) continue; + + if (abilityData.IsEvolution) + { + // If the ability is an evolution, we're checking if it's requirements are met + + bool fulfilled = true; + for (int j = 0; j < abilityData.EvolutionRequirements.Count; j++) + { + var evolutionRequirements = abilityData.EvolutionRequirements[j]; + + var isRequiredAbilityAquired = IsAbilityAquired(evolutionRequirements.AbilityType); + var requiredAbilityReachedLevel = save.GetAbilityLevel(evolutionRequirements.AbilityType) >= evolutionRequirements.RequiredAbilityLevel; + + if (!isRequiredAbilityAquired || !requiredAbilityReachedLevel) + { + // Found a requirement that is not fulfilled + + fulfilled = false; + break; + } + } + + if (!fulfilled) continue; + } else + { + var isAbilityAquired = IsAbilityAquired(abilityData.AbilityType); + + // The player can only have one weapon ability at a time + + if (abilityData.IsWeaponAbility && !isAbilityAquired) continue; + + // There are no available active abilities slots left + + if (abilityData.IsActiveAbility && activeAbilitiesCount >= abilitiesDatabase.ActiveAbilitiesCapacity && !isAbilityAquired) continue; + + // There are no available passive abilities slots left + + if (!abilityData.IsActiveAbility && passiveAbilitiesCount >= abilitiesDatabase.PassiveAbilitiesCapacity && !isAbilityAquired) continue; + } + + result.Add(abilityData); + } + + if (result.Count == 0) + { + // There are no more abilities left, time for endgame abilities :) + + for (int i = 0; i < abilitiesDatabase.AbilitiesCount; i++) + { + var abilityData = abilitiesDatabase.GetAbility(i); + + if (abilityData.IsEndgameAbility) + { + result.Add(abilityData); + } + } + } + + return result; + } + + public virtual int GetAbilityLevel(AbilityType abilityType) + { + return save.GetAbilityLevel(abilityType); + } + + public virtual IAbilityBehavior GetAquiredAbility(AbilityType abilityType) + { + for (int i = 0; i < aquiredAbilities.Count; i++) + { + if (aquiredAbilities[i].AbilityType == abilityType) return aquiredAbilities[i]; + } + + return null; + } + + public virtual bool IsAbilityAquired(AbilityType ability) + { + for (int i = 0; i < aquiredAbilities.Count; i++) + { + if (aquiredAbilities[i].AbilityType == ability) return true; + } + + return false; + } + + public virtual bool IsRequiredForAquiredEvolution(AbilityType abilityType) + { + // Looking through every aquired ability to find an ability that can evolve and has this ability type in requirements + foreach(var ability in aquiredAbilities) + { + if (!ability.AbilityData.IsActiveAbility || ability.AbilityData.IsEvolution) continue; + + foreach(var requirement in ability.AbilityData.EvolutionRequirements) + { + if (requirement.AbilityType == abilityType) return true; + } + } + + return false; + } + + public virtual bool HasEvolution(AbilityType abilityType, out AbilityType otherRequiredAbilityType) + { + // We wokring under the assumption that each evolution requires one active and one passive ability. + // If this is not the case than the logic will break + // There will be no errors but the ui ability cards won't show correct info regarding evolution + + otherRequiredAbilityType = abilityType; + + for (int i = 0; i < abilitiesDatabase.AbilitiesCount; i++) + { + // Going through every active evolution ability in the database, checking for requirements + + var ability = abilitiesDatabase.GetAbility(i); + + if (!ability.IsEvolution) continue; + + for(int j = 0; j < ability.EvolutionRequirements.Count; j++) + { + var requirement = ability.EvolutionRequirements[j]; + + if(requirement.AbilityType == abilityType) + { + for(int k = 0; k < ability.EvolutionRequirements.Count; k++) + { + if (k == j) continue; + + otherRequiredAbilityType = ability.EvolutionRequirements[k].AbilityType; + return true; + } + } + } + } + + return false; + } + + public virtual bool HasAvailableAbilities() + { + var abilities = GetAvailableAbilities(); + + return abilities.Count > 0; + } + + public virtual AbilityData GetAbilityData(AbilityType abilityType) + { + return abilitiesDatabase.GetAbility(abilityType); + } + + public virtual List GetAquiredAbilityTypes() + { + // Simply going through evert aquired abilities and getting their types + + var result = new List(); + + for(int i = 0; i < aquiredAbilities.Count; i++) + { + result.Add(aquiredAbilities[i].AbilityType); + } + + return result; + } + + public virtual void ShowChest() + { + Time.timeScale = 0; + + // Collecting every ability and numbers of its levels that are still available. + // For example, if ability has 5 levels, and it's on level 3 (counting from 0), the number will be (5 - 3 - 1) = 1 + // It works with not aquired abilities as well. (5 - -1 - 1) = 5 + + var availableAbilities = GetAvailableAbilities(); + var dictionary = new Dictionary(); + + // Populating Dictionary + // Also we're counting how many upgrades to the abilities there still can be in the game + + var counter = 0; + foreach (var ability in availableAbilities) + { + int levelsLeft = ability.LevelsCount - save.GetAbilityLevel(ability.AbilityType) - 1; + dictionary.Add(ability, levelsLeft); + + counter += levelsLeft; + } + + // We've got 3 tiers of chests, with 5, 3, or 1 abilities + // We're randomly selecting the tier, but minding the counter from above + // We won't be able to show the best tier chest with 5 abilities is we only have 4 upgrades left + + var selectedAbilitiesCount = 1; + var tierId = 0; + if(counter >= 5 && Random.value < chestChanceTier5) + { + selectedAbilitiesCount = 5; + tierId = 2; + } else if(counter >= 3 && Random.value < chestChanceTier3) + { + selectedAbilitiesCount = 3; + tierId = 1; + } + + int activeAbilitiesCount = GetActiveAbilitiesCount(); + int passiveAbilitiesCount = GetPassiveAbilitiesCount(); + + // Randomly selecting abilities + var selectedAbilities = new List(); + for (int i = 0; i < selectedAbilitiesCount; i++) + { + // Getting random ability from dictionary + var abilityPair = dictionary.Random(); + var ability = abilityPair.Key; + + dictionary[ability] -= 1; + if (dictionary[ability] <= 0) dictionary.Remove(ability); + + // There is a possibility that we are reached the available capacity with this one ability that we have selected. + // If the ability has been selected already or an evolution than it's ok + if (!selectedAbilities.Contains(ability) && !ability.IsEvolution) + { + selectedAbilities.Add(ability); + + // Only checking the new abilities + if (!IsAbilityAquired(ability.AbilityType)) + { + var abilitiesToRemove = new List(); + + if (ability.IsActiveAbility) + { + // There is a new active ability + activeAbilitiesCount++; + + // We've reached the capacity for the active abilities + if(activeAbilitiesCount == ActiveAbilitiesCapacity) + { + foreach(var savedAbility in dictionary.Keys) + { + // This one ability is no longer available for us to win from the chest + if(savedAbility.IsActiveAbility && !IsAbilityAquired(savedAbility.AbilityType) && !selectedAbilities.Contains(savedAbility)) + { + abilitiesToRemove.Add(savedAbility); + } + } + } + } else + { + // There is a new passive ability + passiveAbilitiesCount++; + + // We've reached the capacity for the active abilities + if (passiveAbilitiesCount == PassiveAbilitiesCapacity) + { + foreach (var savedAbility in dictionary.Keys) + { + // This one ability is no longer available for us to win from the chest + if (!savedAbility.IsActiveAbility && !IsAbilityAquired(savedAbility.AbilityType) && !selectedAbilities.Contains(savedAbility)) + { + abilitiesToRemove.Add(savedAbility); + } + } + } + } + + foreach(var abilityToRemove in abilitiesToRemove) + { + dictionary.Remove(abilityToRemove); + } + } + } else + { + selectedAbilities.Add(ability); + } + + if (dictionary.Count == 0) break; + } + + // We might have removed some abilities in the previous step and there might not be enough abilities for selected chest tier + while(selectedAbilities.Count < selectedAbilitiesCount) + { + tierId--; + selectedAbilitiesCount -= 2; + + for(int i = selectedAbilitiesCount; i < selectedAbilities.Count; i++) + { + selectedAbilities.RemoveAt(i); + i--; + } + } + StageController.GameScreen.ShowChestWindow(tierId, availableAbilities, selectedAbilities); + + // Applying abilities + foreach (var ability in selectedAbilities) + { + if (IsAbilityAquired(ability.AbilityType)) + { + var level = save.GetAbilityLevel(ability.AbilityType); + + if (!ability.IsEndgameAbility) level++; + + if (level < 0) level = 0; + + save.SetAbilityLevel(ability.AbilityType, level); + + ability.Upgrade(level); + } + else + { + AddAbility(ability); + } + } + } + +#if UNITY_EDITOR + + public virtual List GetAllAbilitiesDev() + { + var abilities = new List(); + + for (int i = 0; i < abilitiesDatabase.AbilitiesCount; i++) + { + abilities.Add(abilitiesDatabase.GetAbility(i)); + } + + return abilities; + } + + public virtual int GetAbilityLevelDev(AbilityType type) + { + return save.GetAbilityLevel(type); + } + + public virtual void RemoveAbilityDev(AbilityData abilityData) + { + for (int i = 0; i < aquiredAbilities.Count; i++) + { + var ability = aquiredAbilities[i]; + + if (ability.AbilityData == abilityData) + { + ability.Clear(); + + aquiredAbilities.RemoveAt(i); + + save.RemoveAbility(abilityData.AbilityType); + + break; + } + } + } + + public virtual void DecreaseAbilityLevelDev(AbilityData abilityData) + { + var level = save.GetAbilityLevel(abilityData.AbilityType); + if (level > 0) + { + save.SetAbilityLevel(abilityData.AbilityType, level - 1); + + for (int i = 0; i < aquiredAbilities.Count; i++) + { + var ability = aquiredAbilities[i]; + + if (ability.AbilityData == abilityData) + { + abilityData.Upgrade(level - 1); + + break; + } + } + } + } + + public virtual void IncreaseAbilityLevelDev(AbilityData abilityData) + { + var level = save.GetAbilityLevel(abilityData.AbilityType); + if (level < abilityData.LevelsCount - 1) + { + save.SetAbilityLevel(abilityData.AbilityType, level + 1); + + for (int i = 0; i < aquiredAbilities.Count; i++) + { + var ability = aquiredAbilities[i]; + + if (ability.AbilityData == abilityData) + { + abilityData.Upgrade(level + 1); + + break; + } + } + } + } + +#endif + } + + [System.Serializable] + public class AbilityDev + { + public AbilityType abilityType; + public int level; + } + + public class WeightedAbility + { + public AbilityData abilityData; + public float weight; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Data/AbilityManager.cs.meta b/Assets/Common/Scripts/Abilities/Data/AbilityManager.cs.meta new file mode 100644 index 0000000..99034a1 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Data/AbilityManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dcee6e1aeda4d9e42ae8e7d501eaec5b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Data/AbilityType.cs b/Assets/Common/Scripts/Abilities/Data/AbilityType.cs new file mode 100644 index 0000000..bb178d7 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Data/AbilityType.cs @@ -0,0 +1,49 @@ +namespace OctoberStudio +{ + public enum AbilityType + { + ShootingStar = 0, + GuardianEye = 1, + LightningAmulet = 2, + RollingStone = 3, + IceShard = 4, + MagicRune = 5, + Fireball = 6, + Boomerang = 7, + FlyingDagger = 8, + SolarMagnifier = 9, + + Magnet = 100, + MoveSpeed = 101, + Damage = 102, + MaxHP = 103, + XP = 104, + Cooldown = 105, + RestoreHP = 106, + DamageReduction = 107, + ProjectileSpeed = 108, + Size = 109, + Duration = 110, + IncreasedGold = 111, + + VoidStar = 200, + TimeGazer = 201, + ThunderRing = 202, + MaceBall = 203, + SilverStakes = 204, + SpikyTrap = 205, + Meteor = 206, + Recoiler = 207, + TwinDagger = 208, + LunarProjector = 209, + + WoodenWand = 1000, + SteelSword = 1001, + + AncientScepter = 1100, + SacredBlade = 1101, + + HealEndgame = 2001, + GoldEndgame = 2002, + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Data/AbilityType.cs.meta b/Assets/Common/Scripts/Abilities/Data/AbilityType.cs.meta new file mode 100644 index 0000000..1045813 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Data/AbilityType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4aab94e6640dbf94a81b6299d070ddd4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Data/GenericAbilityData.cs b/Assets/Common/Scripts/Abilities/Data/GenericAbilityData.cs new file mode 100644 index 0000000..ba751e2 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Data/GenericAbilityData.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +namespace OctoberStudio.Abilities +{ + public class GenericAbilityData: AbilityData where T : AbilityLevel + { + [SerializeField] T[] levels; + public override AbilityLevel[] Levels => levels; + + public new T GetLevel(int index) + { + return levels[index]; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/Data/GenericAbilityData.cs.meta b/Assets/Common/Scripts/Abilities/Data/GenericAbilityData.cs.meta new file mode 100644 index 0000000..fdaa2e2 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Data/GenericAbilityData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e4988037223aded4da99f2431ac65be1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/Editor.meta b/Assets/Common/Scripts/Abilities/Editor.meta new file mode 100644 index 0000000..2d0c26f --- /dev/null +++ b/Assets/Common/Scripts/Abilities/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1cf4be9dbbec5f54d969f5dc86b96793 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/UI.meta b/Assets/Common/Scripts/Abilities/UI.meta new file mode 100644 index 0000000..d239056 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/UI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 53efce1c890b86e41996b9c3efb8ef29 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/UI/AbilitiesIndicatorsListBehavior.cs b/Assets/Common/Scripts/Abilities/UI/AbilitiesIndicatorsListBehavior.cs new file mode 100644 index 0000000..738fc31 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/UI/AbilitiesIndicatorsListBehavior.cs @@ -0,0 +1,85 @@ +using OctoberStudio.Easing; +using OctoberStudio.Extensions; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Abilities.UI +{ + public class AbilitiesIndicatorsListBehavior : MonoBehaviour + { + [SerializeField] bool isActiveaAbilities; + [SerializeField] GameObject abilityIndicatorPrefab; + private List indicators; + + [Header("Refs")] + [SerializeField] CanvasGroup canvasGroup; + + private IEasingCoroutine alphaCoroutine; + + private void Awake() + { + canvasGroup.alpha = 0; + + Init(); + } + + private void Init(){ + var capacity = isActiveaAbilities ? + StageController.AbilityManager.ActiveAbilitiesCapacity : + StageController.AbilityManager.PassiveAbilitiesCapacity; + + indicators = new List(capacity); + + for(int i = 0 ; i < capacity; i++) + { + var indicator = Instantiate(abilityIndicatorPrefab).GetComponent(); + indicator.transform.SetParent(transform); + indicator.transform.ResetLocal(); + + indicators.Add(indicator); + } + } + + public void Refresh() + { + var abilityTypes = StageController.AbilityManager.GetAquiredAbilityTypes(); + + int counter = 0; + for(int i = 0; i < abilityTypes.Count; i++) + { + var abilityType = abilityTypes[i]; + var abilityData = StageController.AbilityManager.GetAbilityData(abilityType); + + if (abilityData.IsActiveAbility == isActiveaAbilities) + { + indicators[counter++].Show(abilityData.Icon, StageController.AbilityManager.GetAbilityLevel(abilityType), !abilityData.IsEvolution); + } + } + + var capacity = isActiveaAbilities ? StageController.AbilityManager.ActiveAbilitiesCapacity : StageController.AbilityManager.PassiveAbilitiesCapacity; + + for (int i = counter; i < capacity; i++) + { + indicators[i].Show(); + } + + for(int i = capacity; i < indicators.Count; i++) + { + indicators[i].Hide(); + } + } + + public void Show() + { + gameObject.SetActive(true); + alphaCoroutine.StopIfExists(); + alphaCoroutine = canvasGroup.DoAlpha(1f, 0.2f).SetUnscaledTime(true); + } + + public void Hide() + { + alphaCoroutine.StopIfExists(); + alphaCoroutine = canvasGroup.DoAlpha(0, 0.2f).SetOnFinish(() => gameObject.SetActive(false)).SetUnscaledTime(true); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/UI/AbilitiesIndicatorsListBehavior.cs.meta b/Assets/Common/Scripts/Abilities/UI/AbilitiesIndicatorsListBehavior.cs.meta new file mode 100644 index 0000000..995128c --- /dev/null +++ b/Assets/Common/Scripts/Abilities/UI/AbilitiesIndicatorsListBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 84aff293857c18e4e83232beace894be +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/UI/AbilitiesWindowBehavior.cs b/Assets/Common/Scripts/Abilities/UI/AbilitiesWindowBehavior.cs new file mode 100644 index 0000000..d2ebb6b --- /dev/null +++ b/Assets/Common/Scripts/Abilities/UI/AbilitiesWindowBehavior.cs @@ -0,0 +1,167 @@ +using OctoberStudio.Easing; +using OctoberStudio.Extensions; +using OctoberStudio.Input; +using OctoberStudio.Pool; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace OctoberStudio.Abilities.UI +{ + public class AbilitiesWindowBehavior : MonoBehaviour + { + [SerializeField] GameObject levelUpTextObject; + [SerializeField] GameObject weaponSelectTextObject; + + [Space] + [SerializeField] RectTransform panelRect; + private Vector2 panelPosition; + private Vector2 panelHiddenPosition = Vector2.up * 2000; + private IEasingCoroutine panelCoroutine; + + [SerializeField] GameObject abilityCardPrefab; + + [SerializeField] RectTransform abilitiesHolder; + + private PoolComponent cardsPool; + + private List cards = new List(); + + private AbilitiesSave abilitiesSave; + + public UnityAction onPanelClosed; + public UnityAction onPanelStartedClosing; + + public void Init() + { + cardsPool = new PoolComponent(abilityCardPrefab, 3); + abilitiesSave = GameController.SaveManager.GetSave("Abilities Save"); + + panelPosition = panelRect.anchoredPosition; + panelRect.anchoredPosition = panelHiddenPosition; + } + + public void SetData(List abilities) + { + for(int i = 0; i < cards.Count; i++) + { + var card = cards[i]; + + card.transform.SetParent(null); + card.gameObject.SetActive(false); + } + cards.Clear(); + + for (int i = 0; i < abilities.Count; i++) + { + var card = cardsPool.GetEntity(); + + card.transform.SetParent(abilitiesHolder); + card.transform.ResetLocal(); + card.transform.SetAsLastSibling(); + + card.Init(OnAbilitySelected); + + var abilityLevel = abilitiesSave.GetAbilityLevel(abilities[i].AbilityType); + card.SetData(abilities[i], abilityLevel); + + cards.Add(card); + } + } + + public void Show(bool isLevelUp) + { + Time.timeScale = 0; + + gameObject.SetActive(true); + + levelUpTextObject.SetActive(isLevelUp); + weaponSelectTextObject.SetActive(!isLevelUp); + + panelCoroutine.StopIfExists(); + panelCoroutine = panelRect.DoAnchorPosition(panelPosition, 0.3f).SetEasing(EasingType.SineOut).SetUnscaledTime(true); + + for(int i = 0; i < cards.Count; i++) + { + cards[i].Show(i * 0.1f + 0.15f); + } + + EasingManager.DoNextFrame(() => { + for (int i = 0; i < cards.Count; i++) + { + var navigation = new Navigation(); + navigation.mode = Navigation.Mode.Explicit; + + if (i != 0) navigation.selectOnUp = cards[i - 1].Selectable; + if (i != cards.Count - 1) navigation.selectOnDown = cards[i + 1].Selectable; + + cards[i].Selectable.navigation = navigation; + } + + EventSystem.current.SetSelectedGameObject(cards[0].gameObject); + }); + + GameController.InputManager.onInputChanged += OnInputChanged; + } + + public void Hide() + { + onPanelStartedClosing?.Invoke(); + + panelCoroutine.StopIfExists(); + panelCoroutine = panelRect.DoAnchorPosition(panelHiddenPosition, 0.3f).SetEasing(EasingType.SineIn).SetUnscaledTime(true).SetOnFinish(() => { + Time.timeScale = 1; + + for(int i = 0; i < cards.Count; i++) + { + cards[i].transform.SetParent(null); + cards[i].gameObject.SetActive(false); + } + cards.Clear(); + + gameObject.SetActive(false); + + onPanelClosed?.Invoke(); + }); + + GameController.InputManager.onInputChanged -= OnInputChanged; + } + + private void OnInputChanged(InputType prevInput, InputType inputType) + { + if (prevInput == InputType.UIJoystick) + { + EventSystem.current.SetSelectedGameObject(cards[0].gameObject); + } + } + + private void OnAbilitySelected(AbilityData ability) + { + if (StageController.AbilityManager.IsAbilityAquired(ability.AbilityType)) + { + var level = abilitiesSave.GetAbilityLevel(ability.AbilityType); + + if(!ability.IsEndgameAbility) level++; + + if (level < 0) level = 0; + if (level >= ability.LevelsCount) level = ability.LevelsCount - 1; + + abilitiesSave.SetAbilityLevel(ability.AbilityType, level); + + ability.Upgrade(level); + } else + { + StageController.AbilityManager.AddAbility(ability); + } + + Hide(); + } + + private void OnDestroy() + { + cardsPool.Destroy(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/UI/AbilitiesWindowBehavior.cs.meta b/Assets/Common/Scripts/Abilities/UI/AbilitiesWindowBehavior.cs.meta new file mode 100644 index 0000000..87e42af --- /dev/null +++ b/Assets/Common/Scripts/Abilities/UI/AbilitiesWindowBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f0a37516e8fc8b948bfccc22ee6578ed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/UI/AbilityCardBehavior.cs b/Assets/Common/Scripts/Abilities/UI/AbilityCardBehavior.cs new file mode 100644 index 0000000..e932992 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/UI/AbilityCardBehavior.cs @@ -0,0 +1,120 @@ +using OctoberStudio.Audio; +using OctoberStudio.Easing; +using System; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +namespace OctoberStudio.Abilities.UI +{ + public class AbilityCardBehavior : MonoBehaviour + { + [SerializeField] Image abilityIcon; + + [Space] + [SerializeField] TMP_Text titleText; + [SerializeField] TMP_Text descriptionText; + + [Header("Level Text")] + [SerializeField] TMP_Text levelText; + [SerializeField] Image levelBackgroundImage; + [SerializeField] Color levelBackgroundColor; + [SerializeField] Color levelBackgroundNewColor; + [SerializeField] Color levelBackgroundEvoColor; + + [Space] + [SerializeField] GameObject evolutionBlock; + [SerializeField] Image evolutionIcon; + + [Space] + [SerializeField] Button button; + public Selectable Selectable => button; + + [Space] + [SerializeField] RectTransform shineRect; + + [Header("Icon Background")] + [SerializeField] Image iconBackgroundImage; + [SerializeField] Color iconBackgroundColor; + [SerializeField] Color iconBackgroundEvoColor; + + private Vector2 shineStartPosition; + + public AbilityData Data { get; private set; } + + private Action onAbilitySelected; + + private void Awake() + { + button.onClick.AddListener(OnAbilitySelected); + + shineStartPosition = shineRect.anchoredPosition; + } + + public void Init(Action onAbilitySelected) + { + this.onAbilitySelected = onAbilitySelected; + } + + public void SetData(AbilityData abilityData, int level) + { + Data = abilityData; + + abilityIcon.sprite = abilityData.Icon; + + titleText.text = abilityData.Title; + descriptionText.text = abilityData.Description; + + if (abilityData.IsEvolution) + { + levelBackgroundImage.color = levelBackgroundEvoColor; + levelText.text = $"EVO"; + } + else if(level == -1 || abilityData.IsEndgameAbility) + { + levelBackgroundImage.color = levelBackgroundNewColor; + levelText.text = $"NEW!"; + } + else + { + levelBackgroundImage.color = levelBackgroundColor; + levelText.text = $"LVL {level + 2}"; + } + + if (abilityData.IsEvolution) + { + iconBackgroundImage.color = iconBackgroundEvoColor; + } else + { + iconBackgroundImage.color = iconBackgroundColor; + } + + if(StageController.AbilityManager.HasEvolution(Data.AbilityType, out var otherType)) + { + var otherData = StageController.AbilityManager.GetAbilityData(otherType); + var otherIcon = otherData.Icon; + + evolutionBlock.SetActive(true); + evolutionIcon.sprite = otherIcon; + } else + { + evolutionBlock.SetActive(false); + } + } + + public void Show(float delay) + { + var targetShinePosition = shineStartPosition; + targetShinePosition.x *= -1; + + shineRect.anchoredPosition = shineStartPosition; + shineRect.DoAnchorPosition(targetShinePosition, 0.5f, delay).SetUnscaledTime(true); + } + + private void OnAbilitySelected() + { + GameController.AudioManager.PlaySound(AudioManager.BUTTON_CLICK_HASH); + onAbilitySelected?.Invoke(Data); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/UI/AbilityCardBehavior.cs.meta b/Assets/Common/Scripts/Abilities/UI/AbilityCardBehavior.cs.meta new file mode 100644 index 0000000..8a55e13 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/UI/AbilityCardBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f6d9c3e157d8216469e59141018a695f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Abilities/UI/AbilityIndicatorBehavior.cs b/Assets/Common/Scripts/Abilities/UI/AbilityIndicatorBehavior.cs new file mode 100644 index 0000000..068e612 --- /dev/null +++ b/Assets/Common/Scripts/Abilities/UI/AbilityIndicatorBehavior.cs @@ -0,0 +1,39 @@ +using OctoberStudio.Extensions; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +namespace OctoberStudio.Abilities.UI +{ + public class AbilityIndicatorBehavior : MonoBehaviour + { + [SerializeField] Image iconImage; + [SerializeField] TMP_Text levelText; + + public void Show(Sprite icon, int level, bool showLevel) + { + gameObject.SetActive(true); + + iconImage.sprite = icon; + iconImage.SetAlpha(1); + + levelText.gameObject.SetActive(showLevel); + levelText.text = (level + 1).ToString(); + } + + public void Show() + { + gameObject.SetActive(true); + + iconImage.sprite = null; + iconImage.SetAlpha(0f); + + levelText.text = ""; + } + + public void Hide() + { + gameObject.SetActive(false); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Abilities/UI/AbilityIndicatorBehavior.cs.meta b/Assets/Common/Scripts/Abilities/UI/AbilityIndicatorBehavior.cs.meta new file mode 100644 index 0000000..04b007d --- /dev/null +++ b/Assets/Common/Scripts/Abilities/UI/AbilityIndicatorBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b669bf7080f015947a4052828e5c9fcd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Boss Fight.meta b/Assets/Common/Scripts/Boss Fight.meta new file mode 100644 index 0000000..cc45442 --- /dev/null +++ b/Assets/Common/Scripts/Boss Fight.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 126be9faf06fbf04ba2fe0d00cdce93b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Boss Fight/BossFenceBehavior.cs b/Assets/Common/Scripts/Boss Fight/BossFenceBehavior.cs new file mode 100644 index 0000000..e5dd75a --- /dev/null +++ b/Assets/Common/Scripts/Boss Fight/BossFenceBehavior.cs @@ -0,0 +1,42 @@ +using OctoberStudio.Pool; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio +{ + public abstract class BossFenceBehavior : MonoBehaviour + { + [SerializeField] protected GameObject fenceLink; + [SerializeField] protected float linkDistance; + + protected PoolObject fenceLinkPool; + protected List fenceLinks; + + public Vector2 Center { get; protected set; } + + protected int FencePoolSize { get; set; } + + public virtual void Init() + { + if (FencePoolSize < 1) FencePoolSize = 1; + + fenceLinkPool = new PoolObject(fenceLink, FencePoolSize); + } + + public virtual void SpawnFence(Vector2 center) + { + Center = center; + + fenceLinks = new List(); + } + + public virtual void RemoveFence() + { + fenceLinkPool.DisableAllEntities(); + } + + public abstract bool ValidatePosition(Vector2 position, Vector2 offset); + public abstract Vector2 GetIntersectionPoint(Vector2 start, Vector2 end, float offset); + public abstract Vector2 GetRandomPointInside(float offset); + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Boss Fight/BossFenceBehavior.cs.meta b/Assets/Common/Scripts/Boss Fight/BossFenceBehavior.cs.meta new file mode 100644 index 0000000..86b8505 --- /dev/null +++ b/Assets/Common/Scripts/Boss Fight/BossFenceBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a71c4d4fb6e08344bb195127805e2925 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Boss Fight/BossType.cs b/Assets/Common/Scripts/Boss Fight/BossType.cs new file mode 100644 index 0000000..4f94bba --- /dev/null +++ b/Assets/Common/Scripts/Boss Fight/BossType.cs @@ -0,0 +1,12 @@ +namespace OctoberStudio.Bossfight +{ + public enum BossType + { + Mask = 0, + MegaSlime = 1, + QueenWasp = 2, + Crab = 3, + Void = 4, + Bell = 5, + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Boss Fight/BossType.cs.meta b/Assets/Common/Scripts/Boss Fight/BossType.cs.meta new file mode 100644 index 0000000..84c798e --- /dev/null +++ b/Assets/Common/Scripts/Boss Fight/BossType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e5bdac282b7fd584d846b43f32f3abcd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Boss Fight/BossfightData.cs b/Assets/Common/Scripts/Boss Fight/BossfightData.cs new file mode 100644 index 0000000..76b1a35 --- /dev/null +++ b/Assets/Common/Scripts/Boss Fight/BossfightData.cs @@ -0,0 +1,23 @@ +using UnityEngine; + +namespace OctoberStudio.Bossfight +{ + [System.Serializable] + public class BossfightData + { + [Tooltip("Unique type of the boss")] + [SerializeField] BossType bossType; + public BossType BossType => bossType; + + [SerializeField] string displayName; + public string DisplayName => displayName; + + [Tooltip("Prefab of the boss. Should have BossBehavior script or it's descendant attached to it's root GameObject")] + [SerializeField] GameObject bossPrefab; + public GameObject BossPrefab => bossPrefab; + + [Tooltip("Prefab of the fence. Should have BossfightFenceBehavior attached to it's root GameObject")] + [SerializeField] GameObject fencePrefab; + public GameObject FencePrefab => fencePrefab; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Boss Fight/BossfightData.cs.meta b/Assets/Common/Scripts/Boss Fight/BossfightData.cs.meta new file mode 100644 index 0000000..f5d3b72 --- /dev/null +++ b/Assets/Common/Scripts/Boss Fight/BossfightData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dd211efefaf78d844b072b63fb80c40b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Boss Fight/BossfightDatabase.cs b/Assets/Common/Scripts/Boss Fight/BossfightDatabase.cs new file mode 100644 index 0000000..3aff8e1 --- /dev/null +++ b/Assets/Common/Scripts/Boss Fight/BossfightDatabase.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Bossfight +{ + [CreateAssetMenu(fileName = "Bossfight Database", menuName = "October/Bossfight Database")] + public class BossfightDatabase : ScriptableObject + { + [SerializeField] List bossfights; + + public int BossfightsCount => bossfights.Count; + + public BossfightData GetBossfight(BossType bossType) + { + for(int i = 0; i < bossfights.Count; i++) + { + var bossfight = bossfights[i]; + + if(bossfight.BossType == bossType) return bossfight; + } + + return null; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Boss Fight/BossfightDatabase.cs.meta b/Assets/Common/Scripts/Boss Fight/BossfightDatabase.cs.meta new file mode 100644 index 0000000..99c80d3 --- /dev/null +++ b/Assets/Common/Scripts/Boss Fight/BossfightDatabase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8c56553a9f6e0f8439953e4008fa4833 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Boss Fight/CircleFenceBehavior.cs b/Assets/Common/Scripts/Boss Fight/CircleFenceBehavior.cs new file mode 100644 index 0000000..d15eb97 --- /dev/null +++ b/Assets/Common/Scripts/Boss Fight/CircleFenceBehavior.cs @@ -0,0 +1,107 @@ +using UnityEngine; + +namespace OctoberStudio +{ + public class CircleFenceBehavior : BossFenceBehavior + { + [SerializeField] float radius = 5f; + public float Radius { get; private set; } + + public override void Init() + { + Radius = radius; + + float perimeter = 2 * Mathf.PI * radius; + FencePoolSize = Mathf.CeilToInt(perimeter / linkDistance); + + base.Init(); + } + + public override void SpawnFence(Vector2 center) + { + base.SpawnFence(center); + + float angleStep = 360f / FencePoolSize; + + for(int i = 0; i < FencePoolSize; i++) + { + var position = Center + (Vector2)(Quaternion.Euler(0, 0, angleStep * i) * Vector2.up * Radius); + + if (StageController.FieldManager.ValidatePosition(position, Vector2.zero, false)) + { + var link = fenceLinkPool.GetEntity(); + link.transform.position = position; + link.transform.rotation = Quaternion.identity; + + fenceLinks.Add(link); + } + } + } + + public override Vector2 GetRandomPointInside(float offset) + { + return Center + Random.insideUnitCircle * (Radius - offset); + } + + public override bool ValidatePosition(Vector2 position, Vector2 offset) + { + var biggerOffset = Mathf.Max(offset.x, offset.y); + + return Vector2.Distance(Center, position) < (Radius - biggerOffset); + } + + public override Vector2 GetIntersectionPoint(Vector2 start, Vector2 end, float offset) + { + var path = end - start; + var distance = path.magnitude; + + if(distance < Mathf.Epsilon) return start; + + var startToCenter = start - Center; + + var offsetRadius = Radius - offset; + + var a = Vector2.Dot(path, path); + var b = 2 * Vector2.Dot(startToCenter, path); + var c = Vector2.Dot(startToCenter, startToCenter) - offsetRadius * offsetRadius; + + var discriminant = b * b - 4 * a * c; + + if (discriminant < 0) return start; + + var sqrtDisc = Mathf.Sqrt(discriminant); + + // Two roots + var t1 = (-b - sqrtDisc) / (2 * a); + var t2 = (-b + sqrtDisc) / (2 * a); + + var t = Mathf.Max(t1, t2); + if (t < 0) return start; + + return start + path * t; + } + + public void SetRadiusOverride(float radiusOverride) + { + Radius = radiusOverride; + + float perimeter = 2 * Mathf.PI * Radius; + FencePoolSize = Mathf.CeilToInt(perimeter / linkDistance); + } + + public void ResetRadiusOverride() + { + Radius = radius; + + float perimeter = 2 * Mathf.PI * Radius; + FencePoolSize = Mathf.CeilToInt(perimeter / linkDistance); + } + + public override void RemoveFence() + { + base.RemoveFence(); + + ResetRadiusOverride(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Boss Fight/CircleFenceBehavior.cs.meta b/Assets/Common/Scripts/Boss Fight/CircleFenceBehavior.cs.meta new file mode 100644 index 0000000..7987398 --- /dev/null +++ b/Assets/Common/Scripts/Boss Fight/CircleFenceBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c21cb0ea3310f714aa2a5688eca4136c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Boss Fight/RectFenceBehavior.cs b/Assets/Common/Scripts/Boss Fight/RectFenceBehavior.cs new file mode 100644 index 0000000..d031536 --- /dev/null +++ b/Assets/Common/Scripts/Boss Fight/RectFenceBehavior.cs @@ -0,0 +1,203 @@ +using UnityEngine; + +namespace OctoberStudio +{ + public class RectFenceBehavior : BossFenceBehavior + { + [SerializeField] float height; + [SerializeField] float width; + + public float Height { get; private set; } + public float Width { get; private set; } + + private int horyzontalCount; + private int verticalCount; + + private float halfHeight; + private float halfWidth; + + public override void Init() + { + Height = height; + Width = width; + + horyzontalCount = Mathf.RoundToInt(Width / linkDistance); + verticalCount = Mathf.RoundToInt(Height / linkDistance); + + halfHeight = Height / 2; + halfWidth = Width / 2; + + FencePoolSize = verticalCount * 2 + horyzontalCount * 2; + + base.Init(); + } + + public override void SpawnFence(Vector2 center) + { + base.SpawnFence(center); + + for(int i = 0 ; i < horyzontalCount; i++) + { + var x = -halfWidth + i * linkDistance; + + var topPosition = center + new Vector2(x, halfHeight); + var bottomPosition = center + new Vector2(x, -halfHeight); + + if (StageController.FieldManager.ValidatePosition(topPosition, Vector2.zero, false)) + { + var link = fenceLinkPool.GetEntity(); + link.transform.position = topPosition; + link.transform.rotation = Quaternion.identity; + + fenceLinks.Add(link); + } + + if (StageController.FieldManager.ValidatePosition(bottomPosition, Vector2.zero, false)) + { + var link = fenceLinkPool.GetEntity(); + link.transform.position = bottomPosition; + link.transform.rotation = Quaternion.identity; + + fenceLinks.Add(link); + } + } + + for (int i = 0; i < verticalCount; i++) + { + var y = -halfHeight + i * linkDistance; + + var leftPosition = center + new Vector2(-halfWidth, y); + var rightposition = center + new Vector2(halfWidth, y); + + if (StageController.FieldManager.ValidatePosition(leftPosition, Vector2.zero, false)) + { + var link = fenceLinkPool.GetEntity(); + link.transform.position = leftPosition; + link.transform.rotation = Quaternion.identity; + + fenceLinks.Add(link); + } + + if (StageController.FieldManager.ValidatePosition(rightposition, Vector2.zero, false)) + { + var link = fenceLinkPool.GetEntity(); + link.transform.position = rightposition; + link.transform.rotation = Quaternion.identity; + + fenceLinks.Add(link); + } + } + } + + public override bool ValidatePosition(Vector2 position, Vector2 offset) + { + float halfWidthOffset = halfWidth - offset.x; + float halfHeightOffset = halfHeight - offset.y; + + if (position.x > Center.x + halfWidthOffset) return false; + if (position.x < Center.x - halfWidthOffset) return false; + + if (position.y > Center.y + halfHeightOffset) return false; + if (position.y < Center.y - halfHeightOffset) return false; + + return true; + } + + public override Vector2 GetIntersectionPoint(Vector2 start, Vector2 end, float offset) + { + var path = end - start; + var distance = path.magnitude; + + // start == end + if (distance < Mathf.Epsilon) return start; + + var direction = path.normalized; + + float tx1, tx2, ty1, ty2; + + // Create rectangle with offset + var rect = new Rect(Center.x - halfWidth + offset, Center.y - halfHeight + offset, (halfWidth - offset) * 2, (halfHeight - offset) * 2); + + // X axis + if (Mathf.Abs(path.x) > Mathf.Epsilon) + { + // Calculate intersection points + tx1 = (rect.xMin - start.x) / path.x; + tx2 = (rect.xMax - start.x) / path.x; + + // Swapping if needed + if (tx1 > tx2) (tx1, tx2) = (tx2, tx1); + } + else + { + // No intersection + tx1 = float.NegativeInfinity; + tx2 = float.PositiveInfinity; + } + + // Y axis + if (Mathf.Abs(path.y) > Mathf.Epsilon) + { + // Calculate intersection points + ty1 = (rect.yMin - start.y) / path.y; + ty2 = (rect.yMax - start.y) / path.y; + + // Swapping if needed + if (ty1 > ty2) (ty1, ty2) = (ty2, ty1); + } + else + { + // No intersection + ty1 = float.NegativeInfinity; + ty2 = float.PositiveInfinity; + } + + var tEnter = Mathf.Max(tx1, ty1); + var tExit = Mathf.Min(tx2, ty2); + + // No intersection + if (tExit < 0f || tEnter > tExit) return start; + + return start + path * tExit; + } + + public override Vector2 GetRandomPointInside(float offset) + { + float halfWidthOffset = halfWidth - offset; + float halfHeightOffset = halfHeight - offset; + + return Center + new Vector2(Random.Range(-1f, 1f) * halfWidthOffset, Random.Range(-1f, 1f) * halfHeightOffset); + } + + public void SetSizeOverride(float widthOverride, float heightOverride) + { + Height = heightOverride; + Width = widthOverride; + + horyzontalCount = Mathf.RoundToInt(Width / linkDistance); + verticalCount = Mathf.RoundToInt(Height / linkDistance); + + halfHeight = Height / 2; + halfWidth = Width / 2; + } + + public void ResetSizeOverride() + { + Height = height; + Width = width; + + horyzontalCount = Mathf.RoundToInt(Width / linkDistance); + verticalCount = Mathf.RoundToInt(Height / linkDistance); + + halfHeight = Height / 2; + halfWidth = Width / 2; + } + + public override void RemoveFence() + { + base.RemoveFence(); + + ResetSizeOverride(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Boss Fight/RectFenceBehavior.cs.meta b/Assets/Common/Scripts/Boss Fight/RectFenceBehavior.cs.meta new file mode 100644 index 0000000..7b34d75 --- /dev/null +++ b/Assets/Common/Scripts/Boss Fight/RectFenceBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9ddce1a122dec694aabfba754157378f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Boss Fight/UI.meta b/Assets/Common/Scripts/Boss Fight/UI.meta new file mode 100644 index 0000000..3aed176 --- /dev/null +++ b/Assets/Common/Scripts/Boss Fight/UI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: da2d95295a5e3c74e82d97226eb1c60f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Boss Fight/UI/BossfightHealthbarBehavior.cs b/Assets/Common/Scripts/Boss Fight/UI/BossfightHealthbarBehavior.cs new file mode 100644 index 0000000..94f2b4a --- /dev/null +++ b/Assets/Common/Scripts/Boss Fight/UI/BossfightHealthbarBehavior.cs @@ -0,0 +1,61 @@ +using OctoberStudio.Easing; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +namespace OctoberStudio.Bossfight +{ + public class BossfightHealthbarBehavior : MonoBehaviour + { + [SerializeField] RectMask2D rectMask; + [SerializeField] TMP_Text bossNameLabel; + [SerializeField] CanvasGroup canvasGroup; + + public EnemyBehavior Boss { get ; private set; } + + public void Show() + { + gameObject.SetActive(true); + canvasGroup.alpha = 0f; + canvasGroup.DoAlpha(1f, 0.3f); + } + + public void Hide() + { + canvasGroup.DoAlpha(0f, 0.3f).SetOnFinish(() => gameObject.SetActive(false)); + } + + public void SetBoss(EnemyBehavior boss) + { + Boss = boss; + + Boss.onEnemyDied += OnBossDied; + Boss.onHealthChanged += OnBossHealthChanged; + } + + private void OnBossHealthChanged(float hp, float maxHP) + { + SetProgress(hp / maxHP); + } + + private void OnBossDied(EnemyBehavior enemy) + { + Boss.onEnemyDied -= OnBossDied; + Boss.onHealthChanged -= OnBossHealthChanged; + } + + public void Init(BossfightData data) + { + bossNameLabel.text = data.DisplayName; + + SetProgress(1); + } + + private void SetProgress(float progress) + { + Vector4 padding = rectMask.padding; + padding.z = rectMask.rectTransform.rect.width * (1 - progress); + rectMask.padding = padding; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Boss Fight/UI/BossfightHealthbarBehavior.cs.meta b/Assets/Common/Scripts/Boss Fight/UI/BossfightHealthbarBehavior.cs.meta new file mode 100644 index 0000000..f2dfdf3 --- /dev/null +++ b/Assets/Common/Scripts/Boss Fight/UI/BossfightHealthbarBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 20523745cbe27b440841287eb6de4740 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Drop.meta b/Assets/Common/Scripts/Drop.meta new file mode 100644 index 0000000..ef9b5bc --- /dev/null +++ b/Assets/Common/Scripts/Drop.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 833aa933e7980744e86727ae2844ebc0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Drop/DropDatabase.cs b/Assets/Common/Scripts/Drop/DropDatabase.cs new file mode 100644 index 0000000..c18ed61 --- /dev/null +++ b/Assets/Common/Scripts/Drop/DropDatabase.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio +{ + [CreateAssetMenu(fileName = "Drop Database", menuName = "October/Drop Database")] + public class DropDatabase : ScriptableObject + { + [SerializeField] List gems; + + public int GemsCount => gems.Count; + + public DropData GetGemData(int index) + { + return gems[index]; + } + + public DropData GetGemData(DropType dropType) + { + for(int i = 0; i < gems.Count; i++) + { + if (gems[i].DropType == dropType) return gems[i]; + } + return null; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Drop/DropDatabase.cs.meta b/Assets/Common/Scripts/Drop/DropDatabase.cs.meta new file mode 100644 index 0000000..e379a7a --- /dev/null +++ b/Assets/Common/Scripts/Drop/DropDatabase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c9243079d1d16af49907120c059b995c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Drop/DropManager.cs b/Assets/Common/Scripts/Drop/DropManager.cs new file mode 100644 index 0000000..9cf0c24 --- /dev/null +++ b/Assets/Common/Scripts/Drop/DropManager.cs @@ -0,0 +1,210 @@ +using OctoberStudio.Drop; +using OctoberStudio.Easing; +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using System.Collections.Generic; +using Unity.Burst; +using Unity.Collections; +using Unity.Jobs; +using Unity.Mathematics; +using UnityEngine; + +namespace OctoberStudio +{ + public class DropManager : MonoBehaviour + { + [SerializeField] DropDatabase database; + + public Dictionary> dropPools = new Dictionary>(); + public Dictionary lastTimeDropped = new Dictionary(); + + public List dropList = new List(); + protected List waitingDrop = new List(); + + protected NativeList dropPositions; + protected NativeList isInside; + + protected JobHandle insideMagnetJobHandle; + protected InsideMagnetJob insideMagnetJob; + + protected bool isJobRunning; + protected int cachedCapacity; + + protected bool pickUpAllWhenFinished = false; + + public virtual void Init() + { + for (int i = 0; i < database.GemsCount; i++) + { + var data = database.GetGemData(i); + + var pool = new PoolComponent($"Drop_{data.DropType}", data.Prefab, 100); + + dropPools.Add(data.DropType, pool); + lastTimeDropped.Add(data.DropType, 0); + } + + dropPositions = new NativeList(500, Allocator.Persistent); + isInside = new NativeList(500, Allocator.Persistent); + + cachedCapacity = dropPositions.Capacity; + + insideMagnetJob = new InsideMagnetJob(); + insideMagnetJob.positions = dropPositions.AsDeferredJobArray(); + insideMagnetJob.isInside = isInside.AsDeferredJobArray(); + } + + protected virtual void Update() + { + if (dropList.Count == 0) return; + + insideMagnetJob.playerPosition = PlayerBehavior.CenterPosition; + insideMagnetJob.magnetDistanceSqr = PlayerBehavior.Player.MagnetRadiusSqr; + + insideMagnetJobHandle = insideMagnetJob.Schedule(dropList.Count, 64); + JobHandle.ScheduleBatchedJobs(); + + isJobRunning = true; + } + + protected virtual void LateUpdate() + { + if (!isJobRunning) + { + pickUpAllWhenFinished = false; + + MoveWaitingDropToActive(); + + return; + } + isJobRunning = false; + + insideMagnetJobHandle.Complete(); + + if (pickUpAllWhenFinished) + { + PickUpAll(); + } else + { + var delay = 0f; + for (int i = 0; i < dropList.Count; i++) + { + if (isInside[i]) + { + dropList[i].transform.DoPositionJob(PlayerBehavior.CenterTransform, 0.25f, delay, false, EasingType.BackIn).SetOnFinish(dropList[i].OnPickedUp); + delay += 0.002f; + + dropList.RemoveAtSwapBack(i); + dropPositions.RemoveAtSwapBack(i); + isInside.RemoveAtSwapBack(i); + + i--; + } + } + } + + MoveWaitingDropToActive(); + } + + protected virtual void MoveWaitingDropToActive() + { + if (waitingDrop != null && waitingDrop.Count > 0) + { + for (int i = 0; i < waitingDrop.Count; i++) + { + AddDropToList(waitingDrop[i]); + } + + waitingDrop.Clear(); + } + } + + public virtual void PickUpAllDrop() + { + if (isJobRunning) + { + pickUpAllWhenFinished = true; + } else + { + PickUpAll(); + } + } + + protected virtual void PickUpAll() + { + var delay = 0f; + for (int i = 0; i < dropList.Count; i++) + { + if (dropList[i].DropData.AffectedByMagnet) + { + dropList[i].transform.DoPositionJob(PlayerBehavior.CenterTransform, 0.25f, delay, false, EasingType.BackIn).SetOnFinish(dropList[i].OnPickedUp); + delay += 0.001f; + + dropList.RemoveAtSwapBack(i); + dropPositions.RemoveAtSwapBack(i); + isInside.RemoveAtSwapBack(i); + + i--; + } + } + } + + public virtual bool CheckDropCooldown(DropType dropType) + { + return Time.time - lastTimeDropped[dropType] >= database.GetGemData(dropType).DropCooldown; + } + + public virtual void Drop(DropType dropType, Vector3 position) + { + var drop = dropPools[dropType].GetEntity(); + + drop.Init(database.GetGemData(dropType)); + drop.transform.position = position; + + lastTimeDropped[dropType] = Time.time; + + if (!isJobRunning) + { + AddDropToList(drop); + } + else + { + waitingDrop.Add(drop); + } + } + + protected virtual void AddDropToList(DropBehavior drop) + { + dropList.Add(drop); + dropPositions.Add(drop.transform.position.XY()); + isInside.Add(false); + + if (cachedCapacity != isInside.Capacity) + { + insideMagnetJob.positions = dropPositions.AsDeferredJobArray(); + insideMagnetJob.isInside = isInside.AsDeferredJobArray(); + } + } + + protected virtual void OnDestroy() + { + dropPositions.Dispose(); + isInside.Dispose(); + } + + [BurstCompile(OptimizeFor = OptimizeFor.Performance)] + protected struct InsideMagnetJob : IJobParallelFor + { + [ReadOnly] public NativeArray positions; + [ReadOnly] public float2 playerPosition; + [ReadOnly] public float magnetDistanceSqr; + + [WriteOnly] public NativeArray isInside; + + public void Execute(int index) + { + isInside[index] = math.distancesq(positions[index], playerPosition) <= magnetDistanceSqr; + } + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Drop/DropManager.cs.meta b/Assets/Common/Scripts/Drop/DropManager.cs.meta new file mode 100644 index 0000000..c16099e --- /dev/null +++ b/Assets/Common/Scripts/Drop/DropManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 56728313aefc89c47b72c27064d07f18 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Drop/Gem.meta b/Assets/Common/Scripts/Drop/Gem.meta new file mode 100644 index 0000000..6afc71e --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a1b6064a783ad5247a3dfbcf06aa30bc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Drop/Gem/BombDropBehavior.cs b/Assets/Common/Scripts/Drop/Gem/BombDropBehavior.cs new file mode 100644 index 0000000..8acf637 --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem/BombDropBehavior.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +namespace OctoberStudio.Drop +{ + public class BombDropBehavior : DropBehavior + { + [SerializeField] float damageMultiplier = 100; + + public override void OnPickedUp() + { + base.OnPickedUp(); + + StageController.EnemiesSpawner.DealDamageToAllEnemies(PlayerBehavior.Player.Damage * damageMultiplier); + + gameObject.SetActive(false); + } + } +} + diff --git a/Assets/Common/Scripts/Drop/Gem/BombDropBehavior.cs.meta b/Assets/Common/Scripts/Drop/Gem/BombDropBehavior.cs.meta new file mode 100644 index 0000000..6cbd38b --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem/BombDropBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3076046cbdd3a3b4faa68f2b77715d61 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Drop/Gem/ChestDropBehavior.cs b/Assets/Common/Scripts/Drop/Gem/ChestDropBehavior.cs new file mode 100644 index 0000000..4767ba6 --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem/ChestDropBehavior.cs @@ -0,0 +1,14 @@ +namespace OctoberStudio.Drop +{ + public class ChestDropBehavior : DropBehavior + { + public override void OnPickedUp() + { + base.OnPickedUp(); + + gameObject.SetActive(false); + + StageController.AbilityManager.ShowChest(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Drop/Gem/ChestDropBehavior.cs.meta b/Assets/Common/Scripts/Drop/Gem/ChestDropBehavior.cs.meta new file mode 100644 index 0000000..c410419 --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem/ChestDropBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: abf4d45a6798f9441bbca44ec20e2258 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Drop/Gem/CoinDropBehavior.cs b/Assets/Common/Scripts/Drop/Gem/CoinDropBehavior.cs new file mode 100644 index 0000000..8cddd7d --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem/CoinDropBehavior.cs @@ -0,0 +1,24 @@ +using UnityEngine; + +namespace OctoberStudio.Drop +{ + public class CoinDropBehavior : DropBehavior + { + [SerializeField] int amount; + + private static float leftoverDifference; + + public override void OnPickedUp() + { + base.OnPickedUp(); + + gameObject.SetActive(false); + + var gold = amount * PlayerBehavior.Player.GoldMultiplier + leftoverDifference; + var clampedGold = Mathf.FloorToInt(gold); + leftoverDifference = gold - clampedGold; + + GameController.TempGold.Deposit(clampedGold); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Drop/Gem/CoinDropBehavior.cs.meta b/Assets/Common/Scripts/Drop/Gem/CoinDropBehavior.cs.meta new file mode 100644 index 0000000..0724c7b --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem/CoinDropBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6d6cfc9e852a7324abe98f964e0b7fc8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Drop/Gem/DropBehavior.cs b/Assets/Common/Scripts/Drop/Gem/DropBehavior.cs new file mode 100644 index 0000000..8547d32 --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem/DropBehavior.cs @@ -0,0 +1,65 @@ +using OctoberStudio.Easing; +using OctoberStudio.Pool; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Drop +{ + public abstract class DropBehavior : MonoBehaviour + { + [SerializeField] GameObject pickUpParticle; + [SerializeField] float particleDisableDelay; + [SerializeField] string pickUpSoundName; + private int pickUpSoundHash; + + private static Dictionary> particlePools = new Dictionary>(); + + private DropData dropData; + public DropData DropData => dropData; + + public DropType DropType => dropData.DropType; + + private void Awake() + { + pickUpSoundHash = pickUpSoundName.GetHashCode(); + } + + public virtual void Init(DropData dropData) + { + this.dropData = dropData; + + if (!particlePools.ContainsKey(dropData.DropType) && pickUpParticle != null) + { + var particlePool = new PoolComponent(pickUpParticle, 2); + + particlePools[dropData.DropType] = particlePool; + } + } + + public virtual void OnPickedUp() + { + if(particlePools.TryGetValue(dropData.DropType, out var particlePool)) + { + var particle = particlePool.GetEntity(); + particle.transform.position = transform.position; + particle.Play(); + + EasingManager.DoAfter(particleDisableDelay, () => { particle.gameObject.SetActive(false); }); + } + + GameController.AudioManager.PlaySound(pickUpSoundHash); + } + + private void OnDestroy() + { + if (particlePools != null){ + foreach(var pool in particlePools.Values) + { + pool.Destroy(); + } + + particlePools.Clear(); + } + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Drop/Gem/DropBehavior.cs.meta b/Assets/Common/Scripts/Drop/Gem/DropBehavior.cs.meta new file mode 100644 index 0000000..0dc0ac6 --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem/DropBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ed77dd42f61a0184e959766f31fa5daa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Drop/Gem/DropData.cs b/Assets/Common/Scripts/Drop/Gem/DropData.cs new file mode 100644 index 0000000..ccc6d17 --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem/DropData.cs @@ -0,0 +1,18 @@ +using UnityEngine; + +namespace OctoberStudio +{ + [System.Serializable] + public class DropData + { + [SerializeField] DropType dropType; + [SerializeField] GameObject prefab; + [SerializeField] bool affectedByMagnet; + [SerializeField, Min(0)] float dropCooldown; + + public DropType DropType => dropType; + public GameObject Prefab => prefab; + public bool AffectedByMagnet => affectedByMagnet; + public float DropCooldown => dropCooldown; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Drop/Gem/DropData.cs.meta b/Assets/Common/Scripts/Drop/Gem/DropData.cs.meta new file mode 100644 index 0000000..3b84a8d --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem/DropData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 02c7bf0e6bb5db740ba1fd4cec7ef97f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Drop/Gem/DropType.cs b/Assets/Common/Scripts/Drop/Gem/DropType.cs new file mode 100644 index 0000000..3002fcf --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem/DropType.cs @@ -0,0 +1,20 @@ +namespace OctoberStudio +{ + public enum DropType + { + SmallGem = 0, + MediumGem = 1, + BigGem = 2, + LargeGem = 3, + + Magnet = 10, + + Bomb = 20, + + Food = 30, + + Coin = 40, + + Chest = 100, + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Drop/Gem/DropType.cs.meta b/Assets/Common/Scripts/Drop/Gem/DropType.cs.meta new file mode 100644 index 0000000..4874b39 --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem/DropType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9948a740171591a46a4f66c9dd9c2328 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Drop/Gem/FoodDropBehavior.cs b/Assets/Common/Scripts/Drop/Gem/FoodDropBehavior.cs new file mode 100644 index 0000000..fc77fdd --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem/FoodDropBehavior.cs @@ -0,0 +1,18 @@ +using UnityEngine; + +namespace OctoberStudio.Drop +{ + public class FoodDropBehavior : DropBehavior + { + [SerializeField] float hp; + + public override void OnPickedUp() + { + base.OnPickedUp(); + + PlayerBehavior.Player.Heal(hp); + + gameObject.SetActive(false); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Drop/Gem/FoodDropBehavior.cs.meta b/Assets/Common/Scripts/Drop/Gem/FoodDropBehavior.cs.meta new file mode 100644 index 0000000..0f51f34 --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem/FoodDropBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8751ba8d35ce9634f9495c4269a28379 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Drop/Gem/GemBehavior.cs b/Assets/Common/Scripts/Drop/Gem/GemBehavior.cs new file mode 100644 index 0000000..7c215f8 --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem/GemBehavior.cs @@ -0,0 +1,19 @@ +using OctoberStudio.Drop; +using UnityEngine; + +namespace OctoberStudio +{ + public class GemBehavior : DropBehavior + { + [SerializeField] int xp; + public float XP => xp; + + public override void OnPickedUp() + { + base.OnPickedUp(); + + gameObject.SetActive(false); + StageController.ExperienceManager.AddXP(XP); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Drop/Gem/GemBehavior.cs.meta b/Assets/Common/Scripts/Drop/Gem/GemBehavior.cs.meta new file mode 100644 index 0000000..c69637b --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem/GemBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d33c90e504e7974439c5d79f19970eb7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Drop/Gem/MagnetDropBehavior.cs b/Assets/Common/Scripts/Drop/Gem/MagnetDropBehavior.cs new file mode 100644 index 0000000..5f6491b --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem/MagnetDropBehavior.cs @@ -0,0 +1,14 @@ +namespace OctoberStudio.Drop +{ + public class MagnetDropBehavior : DropBehavior + { + public override void OnPickedUp() + { + base.OnPickedUp(); + + StageController.DropManager.PickUpAllDrop(); + + gameObject.SetActive(false); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Drop/Gem/MagnetDropBehavior.cs.meta b/Assets/Common/Scripts/Drop/Gem/MagnetDropBehavior.cs.meta new file mode 100644 index 0000000..79d9517 --- /dev/null +++ b/Assets/Common/Scripts/Drop/Gem/MagnetDropBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4caf7a38d683989438d167c8a8ef94bd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Editor.meta b/Assets/Common/Scripts/Editor.meta new file mode 100644 index 0000000..9b4d83b --- /dev/null +++ b/Assets/Common/Scripts/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fa8dc2d9d25229c42a6305eefeca37a5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies.meta b/Assets/Common/Scripts/Enemies.meta new file mode 100644 index 0000000..3096d46 --- /dev/null +++ b/Assets/Common/Scripts/Enemies.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: da63f36008241894191169374e9878b8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Crab.meta b/Assets/Common/Scripts/Enemies/Boss Crab.meta new file mode 100644 index 0000000..f9d99ca --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Crab.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 61282ad0761fd1142b07a18008f7c88d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Crab/CrabBehavior.cs b/Assets/Common/Scripts/Enemies/Boss Crab/CrabBehavior.cs new file mode 100644 index 0000000..c4e63b5 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Crab/CrabBehavior.cs @@ -0,0 +1,232 @@ +using OctoberStudio.Easing; +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + public class CrabBehavior : EnemyBehavior + { + private static readonly int IS_BURROWED_BOOL = Animator.StringToHash("Is Burrowed"); + private static readonly int IS_CHARGING_BOOL = Animator.StringToHash("Is Charging"); + + [SerializeField] Animator animator; + + [Header("Particles")] + [Tooltip("This particle plays when crab burrows into the ground")] + [SerializeField] ParticleSystem burrowingParticle; + [Tooltip("This particle plays during underground movement of the crab")] + [SerializeField] ParticleSystem burrowingTrail; + [Tooltip("This particle plays every tome the crab hits the ground with it's claw")] + [SerializeField] ParticleSystem hitParticle; + + [Header("Burrowing")] + [Tooltip("Amount of time the crab stays burrowed underground")] + [SerializeField] float burrowedDuration = 4f; + [Tooltip("How fast does the crab moves while burrowed")] + [SerializeField] float burrowedMoveSpeed = 3f; + + [Header("Charging")] + [Tooltip("The prefab of the earth spike")] + [SerializeField] GameObject spikePrefab; + [Tooltip("From this point the spikes will start spawning")] + [SerializeField] Transform spikeStartPoint; + [Tooltip("Amount of waves of the earth spikes attack")] + [SerializeField] float chargingWavesCount = 3; + [Tooltip("The speed of the spikes moving from the crab")] + [SerializeField] float spikeSpeed; + [Tooltip("Spike Spawns each 'value' seconds")] + [SerializeField] float timeBetweenSpikes; + [SerializeField] float spikeDamage; + + private PoolComponent spikesPool; + private List spikes = new List(); + + private Coroutine behaviorCoroutine; + + private bool IsHittingClaw { get; set; } + + protected override void Awake() + { + base.Awake(); + + spikesPool = new PoolComponent(spikePrefab, 50); + } + + public override void Play() + { + base.Play(); + + behaviorCoroutine = StartCoroutine(BehaviorCoroutine()); + } + + private IEnumerator BehaviorCoroutine() + { + while (IsAlive) + { + yield return Movement(); + + yield return SpikesAttack(); + + yield return Movement(); + + yield return BurrowAttack(); + } + } + + private IEnumerator Movement() + { + IsMoving = true; + + var randomPoint = StageController.FieldManager.Fence.GetRandomPointInside(1); + + while(Vector2.Distance(randomPoint, PlayerBehavior.Player.transform.position) > 2) + { + randomPoint = StageController.FieldManager.Fence.GetRandomPointInside(1); + } + + IsMovingToCustomPoint = true; + CustomPoint = randomPoint; + + yield return new WaitUntil(() => Vector2.Distance(transform.position, randomPoint) < 0.2f); + + IsMovingToCustomPoint = false; + + IsMoving = false; + } + + private IEnumerator BurrowAttack() + { + animator.SetBool(IS_BURROWED_BOOL, true); + + IsMoving = false; + + burrowingParticle.Play(); + + yield return new WaitForSeconds(0.7f); + + IsMoving = true; + + IsInvulnerable = true; + + burrowingTrail.Play(); + + var cacheSpeed = speed; + speed = burrowedMoveSpeed; + + yield return new WaitForSeconds(burrowedDuration); + + IsInvulnerable = false; + + IsMoving = false; + animator.SetBool(IS_BURROWED_BOOL, false); + speed = cacheSpeed; + + burrowingTrail.Stop(); + + yield return new WaitForSeconds(0.7f); + } + + private IEnumerator SpikesAttack() + { + IsMoving = false; + animator.SetBool(IS_CHARGING_BOOL, true); + + IsHittingClaw = true; + + for (int i = 0; i < chargingWavesCount; i++) + { + var spikeStartPosition = spikeStartPoint.position; + var playerPosition = PlayerBehavior.Player.transform.position; + + var distance = Vector2.Distance(spikeStartPosition, playerPosition); + if (distance < 2f) distance = 2f; + + var direction = Vector3.up; + var endPosition = spikeStartPosition + direction * (distance + 1f); + + var duration = Vector2.Distance(spikeStartPosition, endPosition) / spikeSpeed; + var coroutine = spikeStartPoint.DoPosition(endPosition, duration); + + float lastTimeSpawned = Time.time; + + var singleSpikes = new List(); + + var startAngle = 360f / 5f / 3f * i; + + while (coroutine.IsActive) + { + if (lastTimeSpawned + timeBetweenSpikes < Time.time) + { + lastTimeSpawned = Time.time; + + Vector3 vector = spikeStartPoint.position - spikeStartPosition; + + for (int j = 0; j < 5; j++) + { + var angle = startAngle + (360f / 5f) * j; + + var position = spikeStartPosition + Quaternion.Euler(0, 0, angle) * vector; + + if (StageController.FieldManager.ValidatePosition(position, Vector2.one * 0.2f)) + { + var spike = spikesPool.GetEntity(); + + spike.transform.position = position; + spike.Spawn(0); + spike.Damage = spikeDamage * StageController.Stage.EnemyDamage; + singleSpikes.Add(spike); + spikes.Add(spike); + } + } + } + + yield return null; + } + + spikeStartPoint.position = spikeStartPosition; + + coroutine = EasingManager.DoAfter(1f, () => + { + for (int i = 0; i < singleSpikes.Count; i++) + { + singleSpikes[i].Hide(); + spikes.Remove(singleSpikes[i]); + } + + singleSpikes.Clear(); + }); + + yield return new WaitForSeconds(0.3f); + } + + yield return new WaitForSeconds(0.7f); + + animator.SetBool(IS_CHARGING_BOOL, false); + + IsHittingClaw = false; + + IsMoving = true; + } + + protected override void Die(bool flash) + { + if(behaviorCoroutine != null) StopCoroutine(behaviorCoroutine); + + for(int i = 0; i < spikes.Count; i++) + { + spikes[i].Clear(); + } + + spikes.Clear(); + + base.Die(flash); + } + + public void PlayClawHitParticle() + { + if (hitParticle != null && IsHittingClaw) hitParticle.Play(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/Boss Crab/CrabBehavior.cs.meta b/Assets/Common/Scripts/Enemies/Boss Crab/CrabBehavior.cs.meta new file mode 100644 index 0000000..094e9a5 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Crab/CrabBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eff2cf25968b89b45aae6d3c7b561981 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Crab/CrabEventsHandler.cs b/Assets/Common/Scripts/Enemies/Boss Crab/CrabEventsHandler.cs new file mode 100644 index 0000000..e83e9d7 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Crab/CrabEventsHandler.cs @@ -0,0 +1,14 @@ +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + public class CrabEventsHandler : MonoBehaviour + { + [SerializeField] CrabBehavior crab; + + public void ClawHit() + { + crab.PlayClawHitParticle(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/Boss Crab/CrabEventsHandler.cs.meta b/Assets/Common/Scripts/Enemies/Boss Crab/CrabEventsHandler.cs.meta new file mode 100644 index 0000000..58547e1 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Crab/CrabEventsHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9d7f5d85d4a55f54a8d657576c0dab0b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Crab/EarthSpikeBehavior.cs b/Assets/Common/Scripts/Enemies/Boss Crab/EarthSpikeBehavior.cs new file mode 100644 index 0000000..aacefce --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Crab/EarthSpikeBehavior.cs @@ -0,0 +1,78 @@ +using OctoberStudio.Easing; +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio.Enemy +{ + public class EarthSpikeBehavior : SimpleEnemyProjectileBehavior + { + private static readonly int HIDE_TRIGGER = Animator.StringToHash("Hide"); + + [SerializeField] Animator animator; + [SerializeField] SpriteRenderer visuals; + [SerializeField] Collider2D spikeCollider; + [SerializeField] ParticleSystem particle; + + bool isHiding = false; + + private WarningCircleBehavior warningCircle; + + public event UnityAction onHidden; + + public float Lifetime { get; private set; } + + public void Spawn(float lifetime) + { + visuals.enabled = false; + spikeCollider.enabled = false; + + warningCircle = StageController.PoolsManager.GetEntity("Warning Circle"); + + warningCircle.transform.position = transform.position; + + warningCircle.Play(1f, 0.3f, 0.3f, ShowVisuals); + + isHiding = false; + + Lifetime = lifetime; + } + + private void ShowVisuals() + { + visuals.enabled = true; + spikeCollider.enabled = true; + + animator.Rebind(); + animator.Update(0); + + particle.Play(); + + if (Lifetime > 0) + { + EasingManager.DoAfter(Lifetime, Hide); + } + } + + public void Clear() + { + warningCircle.gameObject.SetActive(false); + gameObject.SetActive(false); + } + + public void Hide() + { + animator.SetTrigger(HIDE_TRIGGER); + + isHiding = true; + } + + public void OnHidden() + { + if(isHiding) + { + onHidden?.Invoke(this); + gameObject.SetActive(false); + } + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/Boss Crab/EarthSpikeBehavior.cs.meta b/Assets/Common/Scripts/Enemies/Boss Crab/EarthSpikeBehavior.cs.meta new file mode 100644 index 0000000..afe8f0e --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Crab/EarthSpikeBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 53997dcae32e03546bce38c203f32111 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Mask.meta b/Assets/Common/Scripts/Enemies/Boss Mask.meta new file mode 100644 index 0000000..f8003b5 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Mask.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5f17da8c3ce8c724c9fce4c88db747bc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskBehavior.cs b/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskBehavior.cs new file mode 100644 index 0000000..d411004 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskBehavior.cs @@ -0,0 +1,158 @@ +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + public class EnemyMaskBehavior : EnemyBehavior + { + private static readonly int IS_CHARING_BOOL = Animator.StringToHash("Is Charging"); + + [SerializeField] GameObject projectilePrefab; + [SerializeField] GameObject handPrefab; + + [SerializeField] float attackCooldown = 3f; + [SerializeField] int projectilesCount = 4; + + [SerializeField] Animator animator; + [SerializeField] float handDamage; + + private PoolComponent projectilePool; + private PoolComponent handPool; + + private List projectiles = new List(); + + private Coroutine attackCoroutine; + + protected override void Awake() + { + base.Awake(); + + projectilePool = new PoolComponent("Mask Enemy Projectile", projectilePrefab, projectilesCount * 3); + handPool = new PoolComponent("Mask Enemy Hand", handPrefab, 6); + } + + public override void Play() + { + base.Play(); + + attackCoroutine = StartCoroutine(BossBehavior()); + } + + private IEnumerator BossBehavior() + { + while (IsAlive) + { + yield return new WaitForSeconds(attackCooldown); + + IsMoving = false; + + for (int i = 0; i < 3; i++) + { + var playerPosition = PlayerBehavior.Player.transform.position.XY(); + + Vector2 position = Vector2.zero; + bool foundPosition = false; + + for (int j = 0; j < 20; j++) + { + position = playerPosition + Random.insideUnitCircle.normalized * 2; + + if(StageController.FieldManager.ValidatePosition(position, Vector2.one * 0.2f)) + { + foundPosition = true; + break; + } + } + + if (foundPosition) + { + var hand = handPool.GetEntity(); + hand.transform.position = position; + hand.Damage = handDamage * StageController.Stage.EnemyDamage; + + var direction = (playerPosition - position).normalized; + + hand.Init(playerPosition + direction * 2f, 5); + + hand.onFinished += OnProjectileFinished; + + projectiles.Add(hand); + } + + yield return new WaitForSeconds(0.7f); + } + + IsMoving = true; + + yield return new WaitForSeconds(attackCooldown); + + IsMoving = false; + + animator.SetBool(IS_CHARING_BOOL, true); + + yield return new WaitForSeconds(attackCooldown); + + animator.SetBool(IS_CHARING_BOOL, false); + + IsMoving = true; + } + } + + public void WaveAttack() + { + var playerDirection = (PlayerBehavior.CenterPosition - transform.position.XY()).normalized; + + var attackRotation = Quaternion.FromToRotation(Vector2.up, playerDirection); + var stepAngle = 360f / projectilesCount; + + for (int i = 0; i < projectilesCount; i++) + { + var rotation = attackRotation * Quaternion.Euler(0, 0, stepAngle * i); + + var direction = rotation * Vector2.up; + + var projectile = projectilePool.GetEntity(); + + projectile.Init(transform.position, direction); + projectile.Damage = GetDamage(); + + projectile.onFinished += OnProjectileFinished; + + projectiles.Add(projectile); + } + } + + private void OnProjectileFinished(SimpleEnemyProjectileBehavior projectile) + { + projectile.onFinished -= OnProjectileFinished; + + projectiles.Remove(projectile); + } + + protected override void Die(bool flash) + { + base.Die(flash); + + if (attackCoroutine != null) + { + StopCoroutine(attackCoroutine); + attackCoroutine = null; + } + + for(int i = 0; i < projectiles.Count; i++) + { + var projectile = projectiles[i]; + projectile.onFinished -= OnProjectileFinished; + projectile.Disable(); + } + + projectiles.Clear(); + + projectilePool.Destroy(); + handPool.Destroy(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskBehavior.cs.meta b/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskBehavior.cs.meta new file mode 100644 index 0000000..f8a60ef --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9b5cb9d69c0a8144e8b5463cb85d4b90 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskEventsrHandler.cs b/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskEventsrHandler.cs new file mode 100644 index 0000000..6ca3230 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskEventsrHandler.cs @@ -0,0 +1,14 @@ +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + public class EnemyMaskEventsrHandler : MonoBehaviour + { + [SerializeField] EnemyMaskBehavior mask; + + public void WaveAttack() + { + if(mask != null) mask.WaveAttack(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskEventsrHandler.cs.meta b/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskEventsrHandler.cs.meta new file mode 100644 index 0000000..19af4b7 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskEventsrHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ef73cfb3efdea014ba1683109f396f32 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskHandBehavior.cs b/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskHandBehavior.cs new file mode 100644 index 0000000..894a559 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskHandBehavior.cs @@ -0,0 +1,54 @@ +using OctoberStudio.Easing; +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + public class EnemyMaskHandBehavior : SimpleEnemyProjectileBehavior + { + private static readonly int HIDE_TRIGGER = Animator.StringToHash("Hide"); + + [SerializeField] Animator animator; + + private bool IsHiding { get; set; } + + private Vector3 Destination { get; set; } + private float Duration { get; set; } + + private bool IsAppearing { get; set; } + + public void Init(Vector3 destination, float speed) + { + Destination = destination; + + Init(transform.position, (destination - transform.position).normalized); + Duration = Vector3.Distance(transform.position, destination) / speed; + + IsAppearing = true; + } + + public void OnAppeared() + { + if (IsAppearing) + { + IsAppearing = false; + transform.DoPosition(Destination, Duration).SetEasing(EasingType.SineInOut).SetOnFinish(Hide); + } + } + + public void Hide() + { + animator.SetTrigger(HIDE_TRIGGER); + + IsHiding = true; + } + + public void OnHidden() + { + if (IsHiding) + { + IsHiding = false; + Disable(); + } + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskHandBehavior.cs.meta b/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskHandBehavior.cs.meta new file mode 100644 index 0000000..1f383be --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskHandBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 538264dbd3eae6246bb398b2b6245bbd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskProjectile.cs b/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskProjectile.cs new file mode 100644 index 0000000..7ff0942 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskProjectile.cs @@ -0,0 +1,20 @@ +using UnityEngine; + +namespace OctoberStudio +{ + public class EnemyMaskProjectile : SimpleEnemyProjectileBehavior + { + [SerializeField] SpriteRenderer visuals; + [SerializeField] SpriteRenderer shadow; + + public override void Init(Vector2 position, Vector2 direction) + { + base.Init(position, direction); + + var rotation = Quaternion.FromToRotation(Vector2.left, direction); + + visuals.transform.rotation = rotation; + shadow.transform.rotation = rotation; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskProjectile.cs.meta b/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskProjectile.cs.meta new file mode 100644 index 0000000..5f07ce9 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Mask/EnemyMaskProjectile.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ab20d0c3393f6054c9ff514af55c68fa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Mask/HandEventsHandler.cs b/Assets/Common/Scripts/Enemies/Boss Mask/HandEventsHandler.cs new file mode 100644 index 0000000..76bdaf7 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Mask/HandEventsHandler.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + public class HandEventsHandler : MonoBehaviour + { + [SerializeField] EnemyMaskHandBehavior hand; + + public void HandAppeared() + { + if(hand != null) hand.OnAppeared(); + } + + public void HandHidden() + { + if (hand != null) hand.OnHidden(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/Boss Mask/HandEventsHandler.cs.meta b/Assets/Common/Scripts/Enemies/Boss Mask/HandEventsHandler.cs.meta new file mode 100644 index 0000000..b9d473e --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Mask/HandEventsHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0a0cd58db56e14e46ac6cf573d0645ce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Mega Slime.meta b/Assets/Common/Scripts/Enemies/Boss Mega Slime.meta new file mode 100644 index 0000000..8cfced8 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Mega Slime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4471b53bc3d9d3c44bbc8c495014a16c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Mega Slime/EnemyMegaSlimeBehavior.cs b/Assets/Common/Scripts/Enemies/Boss Mega Slime/EnemyMegaSlimeBehavior.cs new file mode 100644 index 0000000..79fa349 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Mega Slime/EnemyMegaSlimeBehavior.cs @@ -0,0 +1,184 @@ +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + public class EnemyMegaSlimeBehavior : EnemyBehavior + { + private static readonly int SPAWN_TRIGGER = Animator.StringToHash("Spawn"); + private static readonly int CHARGE_TRIGGER = Animator.StringToHash("Charge"); + + [SerializeField] Animator animator; + + [Header("Swords")] + [Tooltip("The prefab of the sword")] + [SerializeField] GameObject swordProjectilePrefab; + [Tooltip("The amount of waves of the sword attack")] + [SerializeField] int swordsWavesCount = 3; + [Tooltip("Time between waves of the sword attack")] + [SerializeField] float durationBetweenSwordWaves = 1f; + [Tooltip("The damage of each sword")] + [SerializeField] float swordDamage = 10f; + [Tooltip("The swords will spawn at this points")] + [SerializeField] List swordSpawnPoints; + + [Header("Moving")] + [Tooltip("Time the slime moves between attacks")] + [SerializeField] float movingDuration = 3f; + + [Header("Spawning")] + [Tooltip("The type of an enemy that will be spawned during this attack")] + [SerializeField] EnemyType spawnedEnemyType = EnemyType.Slime; + [Tooltip("The amount of waves of the spawn attack")] + [SerializeField] int spawningWavesCount; + [Tooltip("The amount of enemies that will be spawned in one wave of the spawn attack")] + [SerializeField] int spawnedEnemiesCount; + [Tooltip("The time between waves of spawnAttacks")] + [SerializeField] float durationBetweenSpawning = 1f; + [Tooltip("The time the warning circle is active before the enemy is spawned")] + [SerializeField] float durationBetweenWarningAndSpawning = 0.5f; + + [Space] + [SerializeField] ParticleSystem spawningParticle; + + List warningCircles = new List(); + + private PoolComponent swordsPool; + + private List swords = new List(); + + protected override void Awake() + { + base.Awake(); + + swordsPool = new PoolComponent(swordProjectilePrefab, 6); + } + + public override void Play() + { + base.Play(); + + StartCoroutine(BehaviorCoroutine()); + } + + private IEnumerator BehaviorCoroutine() + { + while(true) + { + IsMoving = false; + + for (int i = 0; i < swordsWavesCount; i++) { + + animator.SetTrigger(CHARGE_TRIGGER); + yield return new WaitForSeconds(durationBetweenSwordWaves); + } + IsMoving = true; + + yield return new WaitForSeconds(movingDuration); + + IsMoving = false; + + for (int i = 0; i < spawningWavesCount; i++) + { + StartCoroutine(SpawnCoroutine()); + + yield return new WaitForSeconds(durationBetweenSpawning); + } + + IsMoving = true; + + yield return new WaitForSeconds(movingDuration); + } + } + + public void SwordsAttack() + { + StartCoroutine(SwordsAttackCoroutine()); + } + + private IEnumerator SpawnCoroutine() + { + spawningParticle.Play(); + + animator.SetTrigger(SPAWN_TRIGGER); + + for (int j = 0; j < spawnedEnemiesCount; j++) + { + var spawnPosition = StageController.FieldManager.Fence.GetRandomPointInside(0.5f); + + var warningCircle = StageController.PoolsManager.GetEntity("Warning Circle"); + + warningCircle.transform.position = spawnPosition; + + warningCircle.Play(1f, 0.3f, 100, null); + + warningCircles.Add(warningCircle); + } + + yield return new WaitForSeconds(durationBetweenWarningAndSpawning); + + for(int i = 0; i < spawnedEnemiesCount; i++) + { + var warningCircle = warningCircles[i]; + + StageController.EnemiesSpawner.Spawn(spawnedEnemyType, warningCircle.transform.position); + + warningCircle.gameObject.SetActive(false); + } + + warningCircles.Clear(); + + spawningParticle.Stop(); + } + + private IEnumerator SwordsAttackCoroutine() + { + for(int i = 0; i < swordSpawnPoints.Count; i++) + { + var spawnPoint = swordSpawnPoints[i]; + + var sword = swordsPool.GetEntity(); + + sword.Init(spawnPoint.transform.position, Vector2.zero); + sword.Damage = StageController.Stage.EnemyDamage * swordDamage; + sword.onFinished += OnSwordFinished; + + swords.Add(sword); + + yield return new WaitForSeconds(0.2f); + } + } + + private void OnSwordFinished(EnemyMegaSlimeProjectileBehavior sword) + { + sword.onFinished -= OnSwordFinished; + + swords.Remove(sword); + } + + protected override void Die(bool flash) + { + base.Die(flash); + + for(int i = 0; i < swords.Count; i++) + { + var sword = swords[i]; + + sword.onFinished -= OnSwordFinished; + + sword.Clear(); + } + + for(int i = 0; i < warningCircles.Count; i++) + { + warningCircles[i].gameObject.SetActive(false); + } + + warningCircles.Clear(); + + StopAllCoroutines(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/Boss Mega Slime/EnemyMegaSlimeBehavior.cs.meta b/Assets/Common/Scripts/Enemies/Boss Mega Slime/EnemyMegaSlimeBehavior.cs.meta new file mode 100644 index 0000000..4b68d87 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Mega Slime/EnemyMegaSlimeBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4dc913d52c8913c4eb3638801ccb292e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Mega Slime/EnemyMegaSlimeProjectileBehavior.cs b/Assets/Common/Scripts/Enemies/Boss Mega Slime/EnemyMegaSlimeProjectileBehavior.cs new file mode 100644 index 0000000..45fa490 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Mega Slime/EnemyMegaSlimeProjectileBehavior.cs @@ -0,0 +1,104 @@ +using OctoberStudio.Easing; +using OctoberStudio.Extensions; +using System.Collections; +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio.Enemy +{ + public class EnemyMegaSlimeProjectileBehavior : SimpleEnemyProjectileBehavior + { + private static readonly int IS_FLYING_DOWN_BOOL = Animator.StringToHash("Is Flying Down"); + + [SerializeField] Collider2D projectileCollider; + [SerializeField] GameObject visuals; + [SerializeField] Animator animator; + [SerializeField] ParticleSystem hitParticle; + + private Coroutine attackCoroutine; + public new UnityAction onFinished; + + private WarningCircleBehavior warningCircle; + + private IEasingCoroutine easingCoroutine; + + public override void Init(Vector2 position, Vector2 direction) + { + base.Init(position, direction); + + projectileCollider.enabled = false; + + Vector3 upPosition = transform.position.SetY(CameraManager.TopBound + 2f); + + easingCoroutine = transform.DoPosition(upPosition, 0.3f).SetEasing(EasingType.SineIn).SetOnFinish(SwordHiddlen); + } + + private void SwordHiddlen() + { + visuals.gameObject.SetActive(false); + + attackCoroutine = StartCoroutine(AttackCoroutine()); + } + + private IEnumerator AttackCoroutine() + { + warningCircle = StageController.PoolsManager.GetEntity("Warning Circle"); + + warningCircle.transform.position = PlayerBehavior.Player.transform.position; + + warningCircle.Play(1f, 0.3f, 100, null); + warningCircle.Follow(PlayerBehavior.Player.transform, Vector3.zero, Time.deltaTime * 3); + + yield return new WaitForSeconds(2f); + + warningCircle.StopFollowing(); + + Vector2 targetPosition = warningCircle.transform.position; + + transform.position = targetPosition.SetY(CameraManager.TopBound + 2f); + + visuals.gameObject.SetActive(true); + + animator.SetBool(IS_FLYING_DOWN_BOOL, true); + + easingCoroutine = transform.DoPosition(targetPosition, 0.5f).SetOnFinish(() => + { + animator.SetBool(IS_FLYING_DOWN_BOOL, false); + projectileCollider.enabled = true; + + hitParticle.Play(); + + warningCircle.gameObject.SetActive(false); + warningCircle = null; + + easingCoroutine = EasingManager.DoAfter(0.3f, () => projectileCollider.enabled = false); + }); + + yield return new WaitForSeconds(2); + + gameObject.SetActive(false); + onFinished?.Invoke(this); + + attackCoroutine = null; + } + + protected override void Update() + { + + } + + public void Clear() + { + if (attackCoroutine != null) StopCoroutine(attackCoroutine); + + if(warningCircle != null) + { + warningCircle.gameObject.SetActive(false); + } + + easingCoroutine.StopIfExists(); + + gameObject.SetActive(false); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/Boss Mega Slime/EnemyMegaSlimeProjectileBehavior.cs.meta b/Assets/Common/Scripts/Enemies/Boss Mega Slime/EnemyMegaSlimeProjectileBehavior.cs.meta new file mode 100644 index 0000000..a9b434c --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Mega Slime/EnemyMegaSlimeProjectileBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dba561cb2d6b3a740a7385f95300c219 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Mega Slime/MegaSlimeEventsHandler.cs b/Assets/Common/Scripts/Enemies/Boss Mega Slime/MegaSlimeEventsHandler.cs new file mode 100644 index 0000000..02aceb1 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Mega Slime/MegaSlimeEventsHandler.cs @@ -0,0 +1,14 @@ +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + public class MegaSlimeEventsHandler : MonoBehaviour + { + [SerializeField] EnemyMegaSlimeBehavior megaSlime; + + public void SwordsAttack() + { + megaSlime.SwordsAttack(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/Boss Mega Slime/MegaSlimeEventsHandler.cs.meta b/Assets/Common/Scripts/Enemies/Boss Mega Slime/MegaSlimeEventsHandler.cs.meta new file mode 100644 index 0000000..8359f45 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Mega Slime/MegaSlimeEventsHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8a5541af052d6e843ab111525a9705fe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Void.meta b/Assets/Common/Scripts/Enemies/Boss Void.meta new file mode 100644 index 0000000..60b6199 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Void.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4ccfd0908b608bc4c888766a77513201 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Void/BlackHoleEventsHandler.cs b/Assets/Common/Scripts/Enemies/Boss Void/BlackHoleEventsHandler.cs new file mode 100644 index 0000000..abd8102 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Void/BlackHoleEventsHandler.cs @@ -0,0 +1,14 @@ +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + public class BlackHoleEventsHandler : MonoBehaviour + { + [SerializeField] VoidBlackHoleBehavior blackHole; + + public void Hidden() + { + blackHole.OnHidden(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/Boss Void/BlackHoleEventsHandler.cs.meta b/Assets/Common/Scripts/Enemies/Boss Void/BlackHoleEventsHandler.cs.meta new file mode 100644 index 0000000..5cde98c --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Void/BlackHoleEventsHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1a1c1bdb6aa67254a816abfb00f1076b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Void/VoidBehavior.cs b/Assets/Common/Scripts/Enemies/Boss Void/VoidBehavior.cs new file mode 100644 index 0000000..19db8f8 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Void/VoidBehavior.cs @@ -0,0 +1,218 @@ +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + public class VoidBehavior : EnemyBehavior + { + private static readonly int TELEPORT_TRIGGER = Animator.StringToHash("Teleport"); + private static readonly int IS_CHARGING_BOOL = Animator.StringToHash("Is Charging"); + + [SerializeField] GameObject blackHolePrefab; + [SerializeField] Animator animator; + [SerializeField] GameObject projectilePrefab; + [SerializeField] float blackHoleDamage = 5f; + + private PoolComponent blackHolesPool; + private List blackHoles = new List(); + + private PoolComponent projectilesPool; + + private bool isTeleporting; + private Vector2 teleportDestination; + + private bool IsHolesActive { get; set; } + private bool IsCharging { get; set; } + + private Coroutine teleportCoroutine; + private Coroutine behaviorCoroutine; + + private List shades = new List(); + + protected override void Awake() + { + base.Awake(); + + blackHolesPool = new PoolComponent(blackHolePrefab, 5); + projectilesPool = new PoolComponent(projectilePrefab, 5); + } + + public override void Play() + { + base.Play(); + + IsMoving = false; + + behaviorCoroutine = StartCoroutine(BehaviorCoroutine()); + teleportCoroutine = StartCoroutine(TeleportCoroutine()); + } + + private IEnumerator TeleportCoroutine() + { + while (true) + { + yield return new WaitForSeconds(5); + + for(int i = 0; i < 50; i++) + { + var position = StageController.FieldManager.Fence.GetRandomPointInside(1); + + bool collides = false; + foreach(var blackHole in blackHoles) + { + if (blackHole.Contains(position)){ + collides = true; + break; + } + } + + if (!collides) + { + isTeleporting = true; + teleportDestination = position; + + animator.SetTrigger(TELEPORT_TRIGGER); + + break; + } + } + + yield return new WaitForSeconds(4); + + if (IsHolesActive) + { + IsCharging = true; + + animator.SetBool(IS_CHARGING_BOOL, true); + + for(int i = 0; i < 3; i++) + { + foreach (var blackHole in blackHoles) + { + blackHole.Charge(projectilesPool); + } + + yield return new WaitForSeconds(0.6f); + } + animator.SetBool(IS_CHARGING_BOOL, false); + IsCharging = false; + } + } + } + + private IEnumerator BehaviorCoroutine() + { + while (true) + { + for (int i = 0; i < 5; i++) + { + var blackHole = blackHolesPool.GetEntity(); + blackHole.Damage = blackHoleDamage * StageController.Stage.EnemyDamage; + bool placed = true; + + int counter = 0; + while (true) + { + var position = StageController.FieldManager.Fence.GetRandomPointInside(1); + + blackHole.transform.position = position; + + bool isPlaceAvailable = true; + for (int j = 0; j < blackHoles.Count; j++) + { + if (blackHoles[j].Intersects(blackHole)) + { + isPlaceAvailable = false; + break; + } + } + + if (isPlaceAvailable && !blackHole.Contains(transform.position) && !blackHole.Contains(PlayerBehavior.Player.transform.position)) + { + blackHoles.Add(blackHole); + break; + } + + counter++; + if (counter == 20) + { + placed = false; + break; + } + } + + if (!placed) blackHole.gameObject.SetActive(false); + yield return new WaitForSeconds(0.1f); + } + + IsHolesActive = true; + + for (int i = 0; i < 5; i++) + { + yield return new WaitForSeconds(2f); + + var blackHole = blackHoles[i % blackHoles.Count]; + + var shade = StageController.EnemiesSpawner.Spawn(EnemyType.Shade, blackHole.transform.position, OnShadeDied); + shades.Add(shade); + } + + yield return new WaitWhile(() => IsCharging); + + IsHolesActive = false; + + for (int i = 0; i < blackHoles.Count; i++) + { + blackHoles[i].Hide(); + } + + blackHoles.Clear(); + + yield return new WaitForSeconds(1f); + } + + } + + private void OnShadeDied(EnemyBehavior shade) + { + shade.onEnemyDied -= OnShadeDied; + + shades.Remove(shade); + } + + public void Teleport() + { + if (isTeleporting) + { + isTeleporting = false; + + transform.position = teleportDestination; + } + } + + protected override void Die(bool flash) + { + StopCoroutine(teleportCoroutine); + StopCoroutine(behaviorCoroutine); + + for(int i = 0; i < blackHoles.Count; i++) + { + blackHoles[i].Clear(); + } + + blackHoles.Clear(); + + for(int i = 0; i < shades.Count; i++) + { + shades[i].onEnemyDied -= OnShadeDied; + shades[i].Kill(); + } + + shades.Clear(); + + base.Die(flash); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/Boss Void/VoidBehavior.cs.meta b/Assets/Common/Scripts/Enemies/Boss Void/VoidBehavior.cs.meta new file mode 100644 index 0000000..a6af92c --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Void/VoidBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5af4ed050f145904d8722c48f2decf47 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Void/VoidBlackHoleBehavior.cs b/Assets/Common/Scripts/Enemies/Boss Void/VoidBlackHoleBehavior.cs new file mode 100644 index 0000000..ea211ea --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Void/VoidBlackHoleBehavior.cs @@ -0,0 +1,117 @@ +using OctoberStudio.Easing; +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + public class VoidBlackHoleBehavior : MonoBehaviour + { + protected static readonly int HIDE_TRIGGER = Animator.StringToHash("Hide"); + + [SerializeField] protected Animator animator; + [SerializeField] protected SpriteRenderer spriteRenderer; + [SerializeField] protected ParticleSystem chargeParticle; + + [SerializeField] protected float projectileDamage = 10f; + + protected Coroutine damageCoroutine; + + public float Damage { get; set; } + + protected bool IsHiding { get; set; } + + protected List projectiles = new List(); + + public virtual void Hide() + { + animator.SetTrigger(HIDE_TRIGGER); + + IsHiding = true; + } + + public virtual void OnHidden() + { + if(IsHiding) + { + IsHiding = false; + gameObject.SetActive(false); + } + } + + public virtual void Charge(PoolComponent projectilePool) + { + chargeParticle.Play(); + + EasingManager.DoAfter(0.6f, () => + { + for(int i = 0; i < 10; i++) + { + var angle = 360f / 10 * i; + var projectile = projectilePool.GetEntity(); + projectile.onFinished += OnProjectileFinished; + projectile.Damage = projectileDamage * StageController.Stage.EnemyDamage; + projectiles.Add(projectile); + projectile.Init(transform.position, Quaternion.Euler(0, 0, angle) * Vector2.up); + } + }); + } + + protected virtual void OnProjectileFinished(SimpleEnemyProjectileBehavior projectile) + { + projectile.onFinished -= OnProjectileFinished; + projectiles.Remove(projectile); + } + + protected virtual IEnumerator DamageCoroutine() + { + while(true) + { + yield return new WaitForSeconds(1f); + + PlayerBehavior.Player.TakeDamage(Damage); + } + } + + public virtual bool Intersects(VoidBlackHoleBehavior other) + { + return spriteRenderer.bounds.Intersects(other.spriteRenderer.bounds); + } + + public virtual bool Contains(Vector2 position) + { + Vector3 position3d = ((Vector3)position).SetZ(spriteRenderer.bounds.center.z); + return spriteRenderer.bounds.Contains(position3d); + } + + protected virtual void OnTriggerEnter2D(Collider2D collision) + { + if (collision.GetComponent() != null) + { + damageCoroutine = StartCoroutine(DamageCoroutine()); + } + } + + protected virtual void OnTriggerExit2D(Collider2D collision) + { + if (collision.GetComponent() != null) + { + StopCoroutine(damageCoroutine); + } + } + + public virtual void Clear() + { + for(int i = 0; i < projectiles.Count; i++) + { + projectiles[i].onFinished -= OnProjectileFinished; + projectiles[i].Disable(); + } + + projectiles.Clear(); + gameObject.SetActive(false); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/Boss Void/VoidBlackHoleBehavior.cs.meta b/Assets/Common/Scripts/Enemies/Boss Void/VoidBlackHoleBehavior.cs.meta new file mode 100644 index 0000000..5cf3e7d --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Void/VoidBlackHoleBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 530f189089ac53d47a8f8faedc06a011 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Void/VoidEventsHandler.cs b/Assets/Common/Scripts/Enemies/Boss Void/VoidEventsHandler.cs new file mode 100644 index 0000000..b03b043 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Void/VoidEventsHandler.cs @@ -0,0 +1,14 @@ +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + public class VoidEventsHandler : MonoBehaviour + { + [SerializeField] VoidBehavior boss; + + public void Teleport() + { + boss.Teleport(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/Boss Void/VoidEventsHandler.cs.meta b/Assets/Common/Scripts/Enemies/Boss Void/VoidEventsHandler.cs.meta new file mode 100644 index 0000000..5135390 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Void/VoidEventsHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4a7624ff2a910374ca9a6bbeb4976bf2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Wasp Queen.meta b/Assets/Common/Scripts/Enemies/Boss Wasp Queen.meta new file mode 100644 index 0000000..35f847d --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Wasp Queen.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b3c32883d0067a2428fdc64ba4b40ed9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Wasp Queen/HoneyMineBehavior.cs b/Assets/Common/Scripts/Enemies/Boss Wasp Queen/HoneyMineBehavior.cs new file mode 100644 index 0000000..b56d525 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Wasp Queen/HoneyMineBehavior.cs @@ -0,0 +1,92 @@ +using OctoberStudio.Easing; +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio.Enemy +{ + public class HoneyMineBehavior : MonoBehaviour + { + private static readonly int LAND_HASH = Animator.StringToHash("Land"); + private static readonly int SHAKE_HASH = Animator.StringToHash("Shake"); + + [SerializeField] Animator animator; + [SerializeField] ParticleSystem explosionParticle; + [SerializeField] Collider2D mineCollider; + [SerializeField] AnimationCurve movementCurve; + [SerializeField] float damageRadius; + [SerializeField] GameObject blobObject; + + public event UnityAction onExploded; + + public float Damage { get; set; } + + IEasingCoroutine coroutine; + private bool isShaking = false; + + private void Awake() + { + mineCollider.enabled = false; + } + + public void Spawn(Vector2 position, Vector2 direction, Vector2 landingPosition) + { + var startPosition = position - direction * 0.3f; + transform.position = startPosition; + var key = position + direction * 1; + + transform.localScale = Vector3.one * 0.1f; + transform.DoLocalScale(Vector3.one, 0.3f); + + coroutine = EasingManager.DoFloat(0, 1, 0.5f, (t) => { + transform.position = EvaluateQuadratic(startPosition, key, landingPosition, t); + }).SetEasingCurve(movementCurve).SetOnFinish(() => + { + animator.SetTrigger(LAND_HASH); + mineCollider.enabled = true; + }); + + blobObject.SetActive(true); + isShaking = false; + } + + private void OnTriggerEnter2D(Collider2D other) + { + if (isShaking) return; + if (other.GetComponent() == null) return; + + isShaking = true; + animator.SetTrigger(SHAKE_HASH); + coroutine = EasingManager.DoAfter(1f, () => { + explosionParticle.Play(); + blobObject.SetActive(false); + + if (Vector2.Distance(transform.position, PlayerBehavior.Player.transform.position) < damageRadius) + { + PlayerBehavior.Player.TakeDamage(Damage); + } + + coroutine = EasingManager.DoAfter(5f,() => { + Clear(); + onExploded?.Invoke(this); + }); + }); + } + + public void Clear() + { + coroutine.StopIfExists(); + mineCollider.enabled = false; + gameObject.SetActive(false); + blobObject.SetActive(true); + + isShaking = false; + } + + private static Vector2 EvaluateQuadratic(Vector2 p1, Vector2 key, Vector2 p2, float t) + { + Vector3 c1 = Vector3.Lerp(p1, key, t); + Vector3 c2 = Vector3.Lerp(key, p2, t); + return Vector3.Lerp(c1, c2, t); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/Boss Wasp Queen/HoneyMineBehavior.cs.meta b/Assets/Common/Scripts/Enemies/Boss Wasp Queen/HoneyMineBehavior.cs.meta new file mode 100644 index 0000000..51aa574 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Wasp Queen/HoneyMineBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b42bf04c969115c4299e1dc1bbb2648d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Wasp Queen/QueenWaspBehavior.cs b/Assets/Common/Scripts/Enemies/Boss Wasp Queen/QueenWaspBehavior.cs new file mode 100644 index 0000000..229de87 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Wasp Queen/QueenWaspBehavior.cs @@ -0,0 +1,201 @@ +using OctoberStudio.Easing; +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + public class QueenWaspBehavior : EnemyBehavior + { + private static readonly int IS_CHARGING_HASH = Animator.StringToHash("IsCharging"); + private static readonly int IS_SHOOTING_HASH = Animator.StringToHash("IsShooting"); + + private Coroutine behaviorCoroutine; + + [SerializeField] Animator animator; + [SerializeField] Vector2 fenceOffset; + + [Header("Charge")] + [SerializeField] SpriteRenderer chargeSprite; + [SerializeField] float chargeSpriteDistance; + [SerializeField] float chargeWarningDuration; + [SerializeField] float chargeMovementDuration; + [SerializeField] float chargeMovementSpeed; + [SerializeField] int chargesCount; + + [Header("Shooting")] + [SerializeField] ParticleSystem shootParticle; + [SerializeField] int minesAmount; + [SerializeField] int attacksCount; + [SerializeField] float timeBetweenAttacks; + [SerializeField] GameObject minePrefab; + [SerializeField] Transform mineSpawnPosition; + [SerializeField] float mineDamageMultiplier; + + [Header("Following")] + [SerializeField] float followingPlayerDuration; + + private int placedMines = 0; + + private PoolComponent minesPool; + private List activeMines = new List(); + + protected override void Awake() + { + base.Awake(); + + minesPool = new PoolComponent(minePrefab, 10); + } + + public override void Play() + { + base.Play(); + + behaviorCoroutine = StartCoroutine(BehaviorCoroutine()); + } + + private IEnumerator BehaviorCoroutine() + { + while (IsAlive) + { + yield return MoveToPlayer(); + for(int i = 0; i < chargesCount; i++) + { + yield return Charge(); + } + + yield return MoveToPlayer(); + yield return PlaceMines(); + } + } + + private IEnumerator MoveToPlayer() + { + IsMoving = true; + + yield return new WaitForSeconds(followingPlayerDuration); + + IsMoving = false; + } + + private IEnumerator Charge() + { + float time = 0; + + chargeSprite.gameObject.SetActive(true); + var movementDirection = Vector2.up; + + while (time < chargeWarningDuration) + { + time += Time.deltaTime; + + movementDirection = (PlayerBehavior.Player.transform.position - chargeSprite.transform.position).normalized; + chargeSprite.transform.rotation = Quaternion.FromToRotation(Vector2.up, movementDirection); + chargeSprite.size = chargeSprite.size.SetY(time / chargeWarningDuration * chargeSpriteDistance); + + if (!scaleCoroutine.ExistsAndActive()) + { + var scale = transform.localScale; + + if (movementDirection.x > 0 && scale.x < 0 || movementDirection.x < 0 && scale.x > 0) + { + scale.x *= -1; + transform.localScale = scale; + } + } + yield return null; + } + + chargeSprite.gameObject.SetActive(false); + animator.SetBool(IS_CHARGING_HASH, true); + + time = 0; + + while (time < chargeMovementDuration) + { + var position = transform.position.XY() + Time.deltaTime * movementDirection * chargeMovementSpeed; + if (StageController.FieldManager.ValidatePosition(position, fenceOffset)) + { + transform.position = position; + } + + time += Time.deltaTime; + + yield return null; + } + + animator.SetBool(IS_CHARGING_HASH, false); + } + + private IEnumerator PlaceMines() + { + for (int i = 0; i < attacksCount; i++) + { + placedMines = 0; + animator.SetBool(IS_SHOOTING_HASH, true); + + while (placedMines < minesAmount) + { + yield return null; + } + + animator.SetBool(IS_SHOOTING_HASH, false); + + yield return new WaitForSeconds(timeBetweenAttacks); + } + + if (!scaleCoroutine.ExistsAndActive()) + { + var scale = transform.localScale; + var movementDirection = (PlayerBehavior.CenterPosition - transform.position.XY()).normalized; + + if (movementDirection.x > 0 && scale.x < 0 || movementDirection.x < 0 && scale.x > 0) + { + scale.x *= -1; + transform.localScale = scale; + } + } + } + + public void Shoot() + { + if(shootParticle != null) shootParticle.Play(); + + placedMines++; + + var mine = minesPool.GetEntity(); + var direction = Vector3.right * transform.localScale.x; + + var landingPosition = PlayerBehavior.CenterPosition; + + mine.Damage = StageController.Stage.EnemyDamage * mineDamageMultiplier; + mine.Spawn(mineSpawnPosition.position, direction, landingPosition); + mine.onExploded += OnMineExploded; + activeMines.Add(mine); + } + + private void OnMineExploded(HoneyMineBehavior mine) + { + mine.onExploded -= OnMineExploded; + } + + protected override void Die(bool flash) + { + StopCoroutine(behaviorCoroutine); + + for(int i = 0; i < activeMines.Count; i++) + { + activeMines[i].Clear(); + activeMines[i].onExploded -= OnMineExploded; + } + + activeMines.Clear(); + + chargeSprite.gameObject.SetActive(false); + + base.Die(flash); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/Boss Wasp Queen/QueenWaspBehavior.cs.meta b/Assets/Common/Scripts/Enemies/Boss Wasp Queen/QueenWaspBehavior.cs.meta new file mode 100644 index 0000000..ce56a44 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Wasp Queen/QueenWaspBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 271bd886669c6a84eac825caab65d07d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/Boss Wasp Queen/QueenWaspEventsHandler.cs b/Assets/Common/Scripts/Enemies/Boss Wasp Queen/QueenWaspEventsHandler.cs new file mode 100644 index 0000000..e290924 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Wasp Queen/QueenWaspEventsHandler.cs @@ -0,0 +1,14 @@ +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + public class QueenWaspEventsHandler : MonoBehaviour + { + [SerializeField] QueenWaspBehavior queenWasp; + + public void Shoot() + { + queenWasp.Shoot(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/Boss Wasp Queen/QueenWaspEventsHandler.cs.meta b/Assets/Common/Scripts/Enemies/Boss Wasp Queen/QueenWaspEventsHandler.cs.meta new file mode 100644 index 0000000..b6f29ee --- /dev/null +++ b/Assets/Common/Scripts/Enemies/Boss Wasp Queen/QueenWaspEventsHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9cc5e78f079a62844812a5c0cf7349d0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/DissolveSettings.cs b/Assets/Common/Scripts/Enemies/DissolveSettings.cs new file mode 100644 index 0000000..2483976 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/DissolveSettings.cs @@ -0,0 +1,17 @@ +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + [CreateAssetMenu(fileName = "Enemy Dissolve Settings", menuName = "October/Enemy/Dissolve Settings")] + public class DissolveSettings : ScriptableObject + { + [SerializeField] float duration = 0.5f; + public float Duration => duration; + + [SerializeField] Color dissolveColor = Color.black; + public Color DissolveColor => dissolveColor; + + [SerializeField] AnimationCurve dissolveCurve; + public AnimationCurve DissolveCurve => dissolveCurve; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/DissolveSettings.cs.meta b/Assets/Common/Scripts/Enemies/DissolveSettings.cs.meta new file mode 100644 index 0000000..1ecd48e --- /dev/null +++ b/Assets/Common/Scripts/Enemies/DissolveSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fa3c00a7748473b43bfa8030d1a3a903 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/EnemiesDatabase.cs b/Assets/Common/Scripts/Enemies/EnemiesDatabase.cs new file mode 100644 index 0000000..362d014 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/EnemiesDatabase.cs @@ -0,0 +1,88 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio +{ + [CreateAssetMenu(menuName = "October/Enemies Database", fileName = "Enemies Database")] + public class EnemiesDatabase : ScriptableObject + { + [SerializeField] List enemies; + + public int EnemiesCount => enemies.Count; + + public EnemyData GetEnemyData(int index) + { + return enemies[index]; + } + + public EnemyData GetEnemyData(EnemyType type) + { + for(int i = 0; i < enemies.Count; i++) + { + if (enemies[i].Type == type) return enemies[i]; + } + + return null; + } + + public Dictionary GetEnemyDataDictionary() + { + var dictionary = new Dictionary(); + + for(int i = 0; i < enemies.Count; i++) + { + if (!dictionary.ContainsKey(enemies[i].Type)) + { + dictionary.Add(enemies[i].Type, enemies[i]); + } + } + + return dictionary; + } + } + + [System.Serializable] + public class EnemyData + { + [SerializeField] EnemyType type; + [SerializeField] GameObject prefab; + [SerializeField] Sprite icon; + [SerializeField] List enemyDrop; + + public EnemyType Type => type; + public GameObject Prefab => prefab; + public Sprite Icon => icon; + public List EnemyDrop => enemyDrop; + } + + [System.Serializable] + public class EnemyDropData + { + [SerializeField] DropType dropType; + [SerializeField, Range(0, 100)] float chance; + + public DropType DropType => dropType; + public float Chance => chance; + } + + public enum EnemyType + { + Pumpkin = 0, + Bat = 1, + Slime = 2, + Vampire = 3, + Plant = 4, + Jellyfish = 5, + Bug = 8, + Wasp = 9, + Hand = 10, + Eye = 11, + FireSlime = 12, + PurpleJellyfish = 13, + StagBeetle = 14, + Shade = 15, + ShadeJellyfish = 16, + ShadeBat = 17, + ShadeVampire = 18, + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/EnemiesDatabase.cs.meta b/Assets/Common/Scripts/Enemies/EnemiesDatabase.cs.meta new file mode 100644 index 0000000..6a6a79b --- /dev/null +++ b/Assets/Common/Scripts/Enemies/EnemiesDatabase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9fb969dd50a438d45b9176e14626575f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/EnemiesSpawner.cs b/Assets/Common/Scripts/Enemies/EnemiesSpawner.cs new file mode 100644 index 0000000..81b6998 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/EnemiesSpawner.cs @@ -0,0 +1,448 @@ +using OctoberStudio.Bossfight; +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using OctoberStudio.Timeline; +using OctoberStudio.UI; +using System.Collections.Generic; +using Unity.Collections; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.Playables; + +namespace OctoberStudio +{ + [DefaultExecutionOrder(-10)] + public class EnemiesSpawner : MonoBehaviour + { + protected List enemies = new List(); + + [SerializeField] protected EnemiesDatabase database; + [SerializeField] protected BossfightDatabase bossfightDatabase; + + [Space] + [SerializeField] protected ScalingLabelBehavior enemiesDiedLabel; + + [Space] + [Tooltip("Maximum amount of alive enemies at a time. No more enemies will be spawned until some of existing aren't defeated")] + [SerializeField] protected int enemiesCap = 2000; + + [Header("Offscreen Teleport")] + [Tooltip("When enabled, enemies that are behaind of the player will teleport to the front")] + [SerializeField] protected bool isOffscreenTeleportEnabled = true; + [Tooltip("Distance from the player to enemy, where 1 is a camera diagonal length")] + [SerializeField] protected float diagonalDistanceMultiplier = 1.3f; + [SerializeField, Range(0, 1f)] protected float teleportConeSize = 0.8f; + + [Tooltip("Enemy will stop teleporting if there are more than this amount of enemies")] + [SerializeField] protected int enemiesTeleportCap = 100; + + protected int enemiesDiedCounter; + + protected Dictionary> enemyPools; + protected Dictionary enemyDataDictionary; + + protected StageSave stageSave; + + public bool IsBossfightActive { get; set; } + + protected Camera mainCamera; + + protected virtual void Awake() + { + mainCamera = Camera.main; + } + + // Were creating pools only for the enemies that are present in the Stage Timeline + public virtual void Init(PlayableDirector director) + { + enemyDataDictionary = database.GetEnemyDataDictionary(); + + stageSave = GameController.SaveManager.GetSave("Stage"); + + Dictionary enemiesOnLevel = new Dictionary(); + + var waves = director.GetAssets(); + + for(int i = 0; i < waves.Count; i++) + { + var wave = waves[i]; + var enemyType = wave.EnemyType; + var enemiesCount = wave.EnemiesCount; + + if (enemiesOnLevel.ContainsKey(enemyType)) + { + if (enemiesOnLevel[enemyType] < enemiesCount) + { + enemiesOnLevel[enemyType] = enemiesCount; + } + } + else + { + enemiesOnLevel.Add(enemyType, enemiesCount); + } + } + + var trackEnemies = new List(); + foreach (var output in director.playableAsset.outputs) + { + if(output.sourceObject is WaveTrack waveTrack) + { + if (!trackEnemies.Contains(waveTrack.EnemyType)) + { + trackEnemies.Add(waveTrack.EnemyType); + } + } + } + + enemyPools = new Dictionary>(); + + foreach(var enemyType in enemiesOnLevel.Keys) + { + var data = database.GetEnemyData(enemyType); + + var amount = enemiesOnLevel[enemyType]; + if (amount > 100) amount = 100; + if (amount < 0) amount = 1; + + var pool = new PoolComponent($"Enemy {enemyType}", data.Prefab, amount); + + enemyPools.Add(data.Type, pool); + } + + foreach(var enemyType in trackEnemies) + { + if (!enemyPools.ContainsKey(enemyType)) + { + var data = database.GetEnemyData(enemyType); + var pool = new PoolComponent($"Enemy {enemyType}", data.Prefab, 1); + + enemyPools.Add(data.Type, pool); + } + } + + enemiesDiedCounter = 0; + if (!stageSave.ResetStageData) + { + enemiesDiedCounter = stageSave.EnemiesKilled; + } + + enemiesDiedLabel.SetAmount(enemiesDiedCounter); + } + + protected virtual void Update() + { + if (!isOffscreenTeleportEnabled || IsBossfightActive || enemies.Count > enemiesTeleportCap) return; + + var diagonalSqr = (CameraManager.HalfWidth * CameraManager.HalfWidth + CameraManager.HalfHeight * CameraManager.HalfHeight) * diagonalDistanceMultiplier; + var diagonal = Mathf.Sqrt(diagonalSqr); + + var dotValue = teleportConeSize - 1; + var modValue = Mathf.Clamp(enemies.Count / 20, 1, 100); + int frame = Time.frameCount % modValue; + for(int i = frame; i < enemies.Count; i += modValue) + { + var enemy = enemies[i]; + + if (enemy.WaveOverride != null && enemy.WaveOverride.DisableOffscreenTeleport) continue; + + var enemyToPlayer = enemy.transform.position - PlayerBehavior.Player.transform.position; + var direction = enemyToPlayer.normalized; + var dot = Vector2.Dot(direction, PlayerBehavior.Player.LookDirection); + + if(diagonalSqr < enemyToPlayer.sqrMagnitude && dot < dotValue) + { + var teleportPosition = PlayerBehavior.Player.transform.position + Quaternion.Euler(0, 0, Random.Range(-45, 45)) * PlayerBehavior.Player.LookDirection * diagonal; + enemy.transform.position = teleportPosition; + } + } + } + + public virtual EnemyBehavior GetClosestEnemy(Vector2 point) + { + EnemyBehavior closestEnemy = null; + float closestDistance = float.MaxValue; + + for(int i = 0; i < enemies.Count; i++) + { + if (enemies[i] == null) + { + enemies.RemoveAt(i); + i--; + continue; + } + + float distance = (point - enemies[i].transform.position.XY()).sqrMagnitude; + + if(distance < closestDistance) + { + closestEnemy = enemies[i]; + closestDistance = distance; + } + } + + return closestEnemy; + } + + public virtual EnemyBehavior Spawn(EnemyType enemyType, Vector2 position, UnityAction onEnemyDiedCallback = null) + { + if (enemies.Count >= enemiesCap) return null; + + var enemyData = enemyDataDictionary[enemyType]; + + if (!enemyPools.ContainsKey(enemyType)) + { + var pool = new PoolComponent($"Enemy {enemyType}", enemyData.Prefab, 10); + + enemyPools.Add(enemyData.Type, pool); + } + + var enemy = enemyPools[enemyType].GetEntity(); + + enemy.SetData(enemyData); + + enemy.transform.position = position; + + enemy.onEnemyDied += OnEnemyDied; + if (onEnemyDiedCallback != null) enemy.onEnemyDied += onEnemyDiedCallback; + + enemy.Play(); + + enemies.Add(enemy); + + return enemy; + } + + public virtual void Spawn(EnemyType type, WaveOverride waveOverride, bool circularSpawn = false, int amount = 1, UnityAction onEnemyDiedCallback = null) + { + var cameraHeight = mainCamera.orthographicSize; + var cameraWidth = cameraHeight * mainCamera.aspect; + var cameraDiagonal = Mathf.Sqrt(cameraWidth * cameraWidth + cameraHeight * cameraHeight); + + for (int i = 0; i < amount; i++) + { + if (enemies.Count >= enemiesCap) return; + + var enemy = enemyPools[type].GetEntity(); + + enemy.SetData(enemyDataDictionary[type]); + enemy.SetWaveOverride(waveOverride); + + var triesCount = 0; + var maxTriesCount = 10; + + var position = Vector3.zero; + var foundPosition = false; + + while(triesCount < maxTriesCount) + { + triesCount++; + + // when spawning a lot of enemies at once we want to offset them to not overload physics computations + var additionalDistance = amount > 100 ? Mathf.Sqrt(enemies.Count) * 0.1f : 0; + if (circularSpawn) + { + position = PlayerBehavior.Player.transform.position + Random.onUnitSphere.SetZ(0).normalized * (cameraDiagonal * 1.05f + Random.value * 0.2f + additionalDistance); + } else + { + position = CameraManager.GetRandomPointOutsideCamera(0.5f + Random.value * 0.2f + additionalDistance); + } + + if(StageController.FieldManager.ValidatePosition(position, Vector2.zero)) + { + foundPosition = true; + break; + } + } + + if (!foundPosition) + { + for (int j = 1; j < 10; j++) + { + var middlePosition = Vector3.Lerp(position, PlayerBehavior.Player.transform.position, 1 - j / 10f); + + if (StageController.FieldManager.ValidatePosition(middlePosition, Vector2.zero)) + { + foundPosition = true; + position = middlePosition; + break; + } + } + } + + if (!foundPosition) + { + position = StageController.FieldManager.GetRandomPositionOnBorder(); + } + + enemy.transform.position = position; + + enemy.onEnemyDied += OnEnemyDied; + if (onEnemyDiedCallback != null) enemy.onEnemyDied += onEnemyDiedCallback; + + enemy.Play(); + + enemies.Add(enemy); + } + } + + public virtual EnemyBehavior GetRandomVisibleEnemy() + { + if (enemies.Count == 0) return null; + + // Trying to find random visible enemy 10 times + for(int i = 0; i < 10; i++) + { + var randomIndex = Random.Range(0, enemies.Count); + + var enemy = enemies[randomIndex]; + + if (enemy.IsVisible) return enemy; + } + + for(int i = 0; i < enemies.Count; i++) + { + var enemy = enemies[i]; + + if (enemy.IsVisible) return enemy; + } + + return null; + } + + public virtual List GetEnemiesInRadius(Vector2 position, float radius) + { + var result = new List(); + + float radiusSqr = radius * radius; + + for(int i = 0; i < enemies.Count; i++) + { + if ((enemies[i].transform.position.XY() - position).sqrMagnitude <= radiusSqr) + { + result.Add(enemies[i]); + } + } + + return result; + } + + public virtual void KillEveryEnemy() + { + foreach(var enemy in enemies) + { + enemy.onEnemyDied -= OnEnemyDied; + enemy.Kill(); + } + + enemiesDiedCounter += enemies.Count; + stageSave.EnemiesKilled = enemiesDiedCounter; + + enemiesDiedLabel.SetAmount(enemiesDiedCounter); + + enemies.Clear(); + } + + public virtual void DealDamageToAllEnemies(float damage) + { + var aliveEnemies = new List(); + + foreach(var enemy in enemies) + { + if(enemy.HP <= damage) + { + // if enemy is not a boss + if(enemy.Data != null) + { + enemy.onEnemyDied -= OnEnemyDied; + enemy.Kill(); + + foreach (var dropData in enemy.GetDropData()) + { + if (dropData.Chance == 0) continue; + + if (Random.value * 100 <= dropData.Chance && StageController.DropManager.CheckDropCooldown(dropData.DropType)) + { + StageController.DropManager.Drop(dropData.DropType, enemy.transform.position.XY() + Random.insideUnitCircle * 0.2f); + } + } + } else + { + aliveEnemies.Add(enemy); + } + } + else + { + // if enemy is not a boss + if (enemy.Data != null) + { + enemy.TakeDamage(damage); + } + aliveEnemies.Add(enemy); + } + } + + enemiesDiedCounter += enemies.Count - aliveEnemies.Count; + + stageSave.EnemiesKilled = enemiesDiedCounter; + enemiesDiedLabel.SetAmount(enemiesDiedCounter); + + enemies.Clear(); + enemies.AddRange(aliveEnemies); + } + + protected virtual void OnEnemyDied(EnemyBehavior enemy) + { + enemies.RemoveSwapBack(enemy); + enemy.onEnemyDied -= OnEnemyDied; + + foreach(var dropData in enemy.GetDropData()) + { + if(dropData.Chance == 0) continue; + if(Random.value * 100 <= dropData.Chance && StageController.DropManager.CheckDropCooldown(dropData.DropType)) + { + StageController.DropManager.Drop(dropData.DropType, enemy.transform.position.XY() + Random.insideUnitCircle * 0.2f); + } + } + + enemiesDiedCounter++; + stageSave.EnemiesKilled = enemiesDiedCounter; + enemiesDiedLabel.SetAmount(enemiesDiedCounter); + } + + protected virtual void OnBossDied(EnemyBehavior boss) + { + enemies.RemoveSwapBack(boss); + boss.onEnemyDied -= OnBossDied; + + if (boss.ShouldSpawnChestOnDeath && StageController.AbilityManager.HasAvailableAbilities()) StageController.DropManager.Drop(DropType.Chest, boss.transform.position.XY() + Random.insideUnitCircle); + StageController.DropManager.Drop(DropType.Magnet, boss.transform.position.XY() + Random.insideUnitCircle); + StageController.DropManager.Drop(DropType.Food, boss.transform.position.XY() + Random.insideUnitCircle); + + enemiesDiedCounter++; + stageSave.EnemiesKilled = enemiesDiedCounter; + enemiesDiedLabel.SetAmount(enemiesDiedCounter); + } + + public virtual EnemyBehavior SpawnBoss(BossType bossType, Vector2 spawnPosition, UnityAction onBossDied = null) + { + var bossData = bossfightDatabase.GetBossfight(bossType); + + var boss = Instantiate(bossData.BossPrefab).GetComponent(); + boss.transform.position = spawnPosition; + + boss.Play(); + + boss.onEnemyDied += OnBossDied; + boss.onEnemyDied += onBossDied; + + enemies.Add(boss); + + return boss; + } + + public virtual BossfightData GetBossData(BossType bossType) + { + return bossfightDatabase.GetBossfight(bossType); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/EnemiesSpawner.cs.meta b/Assets/Common/Scripts/Enemies/EnemiesSpawner.cs.meta new file mode 100644 index 0000000..d9b5af8 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/EnemiesSpawner.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dcaffe2b41627d04f8cfb643c7f7006f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/EnemyBehavior.cs b/Assets/Common/Scripts/Enemies/EnemyBehavior.cs new file mode 100644 index 0000000..1a9be61 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/EnemyBehavior.cs @@ -0,0 +1,413 @@ +using OctoberStudio.Easing; +using OctoberStudio.Enemy; +using OctoberStudio.Extensions; +using OctoberStudio.Timeline; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.Serialization; + +namespace OctoberStudio +{ + public class EnemyBehavior : MonoBehaviour + { + protected static readonly int _Overlay = Shader.PropertyToID("_Overlay"); + protected static readonly int _Disolve = Shader.PropertyToID("_Disolve"); + + private static readonly int HIT_HASH = "Hit".GetHashCode(); + + [Header("Settings")] + [Tooltip("The speed of the enemy")] + [SerializeField] protected float speed; + public float Speed { get; protected set; } + + [Tooltip("The LevelData's 'Enemy Damage' is multiplied by this value to determine the damage of the enemy on each level")] + [SerializeField] float damage = 1f; + + [Tooltip("The LevelData's 'Enemy HP' is multiplied by this value to determine the HP of the enemy on each level")] + [SerializeField] float hp; + + [FormerlySerializedAs("canBekickedBack")] + [SerializeField] bool canBeKickedBack = true; + + [SerializeField] bool shouldFadeIn; + + [Header("References")] + [SerializeField] Rigidbody2D rb; + [SerializeField] SpriteRenderer spriteRenderer; + [SerializeField] DissolveSettings dissolveSettings; + [SerializeField] SpriteRenderer shadowSprite; + [SerializeField] Collider2D enemyCollider; + + public Vector2 Center => enemyCollider.bounds.center; + + [Header("Hit")] + [SerializeField] float hitScaleAmount = 0.2f; + [SerializeField] Color hitColor = Color.white; + + public EnemyData Data { get; private set; } + public WaveOverride WaveOverride { get; protected set; } + + public bool IsVisible => spriteRenderer.isVisible; + public bool IsAlive => HP > 0; + // The enemy does not receive damage when this property is true + public bool IsInvulnerable { get; protected set; } + + public float HP { get; private set; } + public float MaxHP { get; private set; } + + public bool ShouldSpawnChestOnDeath { get; set; } + + IEasingCoroutine fallBackCoroutine; + + private Dictionary> appliedEffects = new Dictionary>(); + + protected bool IsMoving { get; set; } + public bool IsMovingToCustomPoint { get; protected set; } + public Vector2 CustomPoint { get; protected set; } + + public float LastTimeDamagedPlayer { get; set; } + + private Material sharedMaterial; + private Material effectsMaterial; + + private float shadowAlpha; + + public event UnityAction onEnemyDied; + public event UnityAction onHealthChanged; + + // VAT 适配器(如 EnemyVATAttachment)挂载时,接管朝向 → EnemyBehavior 不再写 transform.localScale.x, + // sign 通过 event 推给适配器,适配器走 VATAnimationController.SetFacing 用 Y 旋转转身。 + // +1 = 朝右,-1 = 朝左。 + public event System.Action OnFacingSignChanged; + private int currentFacingSign = 1; + // 接管开关(EnemyVATAttachment.Awake 中置 true 即关闭 localScale 翻转) + public bool ExternalFacingOverride { get; set; } + + private float lastTimeSwitchedDirection = 0; + + IEasingCoroutine damageCoroutine; + protected IEasingCoroutine scaleCoroutine; + IEasingCoroutine fadeInCoroutine; + + private float damageTextValue; + private float lastTimeDamageText; + + private static int lastFrameHitSound; + private float lastTimeHitSound; + + protected virtual void Awake() + { + sharedMaterial = spriteRenderer.sharedMaterial; + effectsMaterial = Instantiate(sharedMaterial); + + shadowAlpha = shadowSprite.color.a; + } + + public void SetData(EnemyData data) + { + Data = data; + } + + public void SetWaveOverride(WaveOverride waveOverride) + { + WaveOverride = waveOverride; + } + + public virtual void Play() + { + MaxHP = StageController.Stage.EnemyHP * hp; + Speed = speed; + if (WaveOverride != null) + { + MaxHP = WaveOverride.ApplyHPOverride(MaxHP); + Speed = WaveOverride.ApplySpeedOverride(Speed); + } + + HP = MaxHP; + IsMoving = true; + + shadowSprite.SetAlpha(shadowAlpha); + + enemyCollider.enabled = true; + if (shouldFadeIn) + { + spriteRenderer.SetAlpha(0); + fadeInCoroutine = spriteRenderer.DoAlpha(1, 0.2f); + } + } + + protected virtual void Update() + { + if(!IsAlive || !IsMoving || PlayerBehavior.Player == null) return; + + Vector3 target = IsMovingToCustomPoint ? CustomPoint : PlayerBehavior.Player.transform.position; + + Vector3 direction = (target - transform.position).normalized; + + float speed = Speed; + + if (appliedEffects.TryGetValue(EffectType.Speed, out var speedEffects)) + { + for(int i = 0; i < speedEffects.Count; i++) + { + Effect effect = speedEffects[i]; + speed *= effect.Modifier; + } + } + + transform.position += direction * Time.deltaTime * speed; + + // Enemy looks in the direction it's moving + if (!scaleCoroutine.ExistsAndActive()) + { + int wantSign = direction.x >= 0 ? 1 : -1; + if (wantSign != currentFacingSign && + Time.unscaledTime - lastTimeSwitchedDirection > 0.1f) + { + currentFacingSign = wantSign; + if (ExternalFacingOverride) + { + // VAT 模式: 不写 localScale,把符号事件推给适配器(EnemyVATAttachment → VATAnimationController.SetFacing) + OnFacingSignChanged?.Invoke(currentFacingSign); + } + else + { + // 原 2D 行为: 直接翻 scale.x + var scale = transform.localScale; + scale.x = Mathf.Abs(scale.x) * wantSign; + transform.localScale = scale; + } + lastTimeSwitchedDirection = Time.unscaledTime; + } + } + } + + private void OnTriggerEnter2D(Collider2D other) + { + ProjectileBehavior projectile = other.GetComponent(); + + if(projectile != null) + { + TakeDamage(PlayerBehavior.Player.Damage * projectile.DamageMultiplier); + + if(HP > 0) + { + if (projectile.KickBack && canBeKickedBack) + { + KickBack(PlayerBehavior.CenterPosition); + } + + if(projectile.Effects != null && projectile.Effects.Count > 0) + { + AddEffects(projectile.Effects); + } + } + } + } + + public float GetDamage() + { + var damage = this.damage; + if(WaveOverride != null) damage = WaveOverride.ApplyDamageOverride(damage); + + var baseDamage = StageController.Stage.EnemyDamage * damage; + + if (appliedEffects.ContainsKey(EffectType.Damage)) + { + var damageEffects = appliedEffects[EffectType.Damage]; + + for (int i = 0; i < damageEffects.Count; i++) + { + var effect = damageEffects[i]; + + baseDamage *= effect.Modifier; + } + } + + return baseDamage; + } + + public List GetDropData() + { + if (WaveOverride != null) return WaveOverride.ApplyDropOverride(Data.EnemyDrop); + return Data.EnemyDrop; + } + + public void TakeDamage(float damage) + { + if (!IsAlive) return; + if (IsInvulnerable) return; + + HP -= damage; + + onHealthChanged?.Invoke(HP, MaxHP); + + // Showing Damage Text + damageTextValue += damage; + if (Time.unscaledTime - lastTimeDamageText > 0.2f && damageTextValue >= 1) + { + var damageText = Mathf.RoundToInt(damageTextValue).ToString(); + StageController.WorldSpaceTextManager.SpawnText(transform.position + new Vector3(Random.Range(-0.1f, 0.1f), Random.value * 0.1f), damageText); + + damageTextValue = 0; + lastTimeDamageText = Time.unscaledTime; + } else + { + damageTextValue += damage; + } + + // Playing Damage Sound + if(Time.frameCount != lastFrameHitSound && Time.unscaledTime - lastTimeHitSound > 0.2f) + { + GameController.AudioManager.PlaySound(HIT_HASH); + + lastFrameHitSound = Time.frameCount; + lastTimeHitSound = Time.unscaledTime; + } + + if (HP <= 0) + { + Die(true); + } + else + { + // Flashing Color on hit + if (!damageCoroutine.ExistsAndActive()) + { + FlashHit(true); + } + + // Scaling on Hit + if (!scaleCoroutine.ExistsAndActive()) + { + var x = transform.localScale.x; + + scaleCoroutine = transform.DoLocalScale(new Vector3(x * (1 - hitScaleAmount), (1 + hitScaleAmount), 1), 0.07f).SetEasing(EasingType.SineOut).SetOnFinish(() => + { + scaleCoroutine = transform.DoLocalScale(new Vector3(x, 1, 1), 0.07f).SetEasing(EasingType.SineInOut); + }); + } + } + } + + private void FlashHit(bool resetMaterial, UnityAction onFinish = null) + { + spriteRenderer.material = effectsMaterial; + + var transparentColor = hitColor; + transparentColor.a = 0; + + // Changin properties of a material creates a new instance of a material. + // We cache the material at the start of a game and assign it back when we're done with it + // This way the batching optimization is restored + effectsMaterial.SetColor(_Overlay, transparentColor); + + damageCoroutine = effectsMaterial.DoColor(_Overlay, hitColor, 0.05f).SetOnFinish(() => + { + damageCoroutine = effectsMaterial.DoColor(_Overlay, transparentColor, 0.05f).SetOnFinish(() => + { + if(resetMaterial) spriteRenderer.material = sharedMaterial; + onFinish?.Invoke(); + }); + }); + } + + public void Kill() + { + HP = 0; + + Die(false); + } + + protected virtual void Die(bool flash) + { + enemyCollider.enabled = false; + + damageCoroutine.StopIfExists(); + + onEnemyDied?.Invoke(this); + fallBackCoroutine.StopIfExists(); + rb.simulated = true; + + fadeInCoroutine.StopIfExists(); + + // Changin properties of a material creates a new instance of a material. + // We cache the material at the start of a game and assign it back when we're done with it + // This way the batching optimization is restored + + spriteRenderer.material = effectsMaterial; + + if (flash) + { + FlashHit(false, () => { + effectsMaterial.SetColor(_Overlay, Color.clear); + effectsMaterial.DoColor(_Overlay, dissolveSettings.DissolveColor, dissolveSettings.Duration - 0.1f); + }); + } else + { + effectsMaterial.SetColor(_Overlay, Color.clear); + effectsMaterial.DoColor(_Overlay, dissolveSettings.DissolveColor, dissolveSettings.Duration); + } + + effectsMaterial.SetFloat(_Disolve, 0); + effectsMaterial.DoFloat(_Disolve, 1, dissolveSettings.Duration + 0.02f).SetEasingCurve(dissolveSettings.DissolveCurve).SetOnFinish(() => + { + effectsMaterial.SetColor(_Overlay, Color.clear); + effectsMaterial.SetFloat(_Disolve, 0); + + gameObject.SetActive(false); + spriteRenderer.material = sharedMaterial; + }); + + shadowSprite.DoAlpha(0, dissolveSettings.Duration); + + appliedEffects.Clear(); + + WaveOverride = null; + } + + public void KickBack(Vector3 position) + { + var direction = (transform.position - position).normalized; + rb.simulated = false; + fallBackCoroutine.StopIfExists(); + fallBackCoroutine = transform.DoPosition(transform.position + direction * 0.6f, 0.15f).SetEasing(EasingType.ExpoOut).SetOnFinish(() => rb.simulated = true); + } + + public void AddEffects(List effects) + { + for(int i = 0; i < effects.Count; i++) + { + AddEffect(effects[i]); + } + } + + public void AddEffect(Effect effect) + { + if (!appliedEffects.ContainsKey(effect.EffectType)) + { + appliedEffects.Add(effect.EffectType, new List()); + } + + List effects = appliedEffects[effect.EffectType]; + + if (!effects.Contains(effect)) + { + effects.Add(effect); + } + } + + public void RemoveEffect(Effect effect) + { + if (!appliedEffects.ContainsKey(effect.EffectType)) return; + + List effects = appliedEffects[effect.EffectType]; + + if (effects.Contains(effect)) + { + effects.Remove(effect); + } + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/EnemyBehavior.cs.meta b/Assets/Common/Scripts/Enemies/EnemyBehavior.cs.meta new file mode 100644 index 0000000..b25c2c8 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/EnemyBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fcd4d5b00373d1a488d383677cd9ca90 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/EnemyBellBehavior.cs b/Assets/Common/Scripts/Enemies/EnemyBellBehavior.cs new file mode 100644 index 0000000..e64c58e --- /dev/null +++ b/Assets/Common/Scripts/Enemies/EnemyBellBehavior.cs @@ -0,0 +1,277 @@ +using OctoberStudio.Easing; +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + public class EnemyBellBehavior : EnemyBehavior + { + public static readonly int IS_ATTACKING_BOOL = Animator.StringToHash("Is Attacking"); + public static readonly int IS_CHARGING_BOOL = Animator.StringToHash("Is Charging"); + + [SerializeField] float attackCooldown = 5f; + [SerializeField] Animator animator; + + private PoolComponent projectilePool; + private PoolComponent smallProjectilePool; + private PoolComponent spikeProjectilePool; + private PoolComponent explosionParticlePool; + + private List projectiles = new List(); + + private Coroutine attackCoroutine; + private Coroutine movementCoroutine; + + [SerializeField] List projectilePositions; + + private List explosionCoroutines = new List(); + + protected override void Awake() + { + base.Awake(); + + projectilePool = new PoolComponent("Bell Enemy Projectile", projectilePrefab, 5); + smallProjectilePool = new PoolComponent("Bell Enemy Small Projectile", smallProjectilePrefab, 30); + spikeProjectilePool = new PoolComponent("Bell Enemy Spike Projectile", spikeProjectilePrefab, 10); + + explosionParticlePool = new PoolComponent("Bell Enemy Projectile Explosion", explosionParticlePrefab, 5); + } + + public override void Play() + { + base.Play(); + + attackCoroutine = StartCoroutine(AttackCoroutine()); + movementCoroutine = StartCoroutine(MovementCoroutine()); + } + + [SerializeField] float movementCooldown = 0.5f; + + private IEnumerator MovementCoroutine() + { + while (true) + { + IsMoving = true; + + var randomPoint = StageController.FieldManager.Fence.GetRandomPointInside(1); + + IsMovingToCustomPoint = true; + CustomPoint = randomPoint; + + yield return new WaitUntil(() => Vector2.Distance(transform.position, randomPoint) < 0.2f); + + IsMovingToCustomPoint = false; + + IsMoving = false; + + yield return new WaitForSeconds(movementCooldown); + } + } + + private IEnumerator AttackCoroutine() + { + while (true) + { + yield return new WaitForSeconds(attackCooldown); + + animator.SetBool(IS_CHARGING_BOOL, true); + yield return SimpleAttackCoroutine(); + animator.SetBool(IS_CHARGING_BOOL, false); + + yield return new WaitForSeconds(attackCooldown); + + animator.SetBool(IS_CHARGING_BOOL, true); + yield return SlowAttackCoroutine(); + animator.SetBool(IS_CHARGING_BOOL, false); + + yield return new WaitForSeconds(attackCooldown); + + animator.SetBool(IS_CHARGING_BOOL, true); + yield return SmallAttackCoroutine(); + animator.SetBool(IS_CHARGING_BOOL, false); + } + } + + [Header("Simple Attack")] + [SerializeField] int simpleAttackWavesCount = 3; + [SerializeField] float simpleAttackDamage = 1; + [SerializeField] float simpleAttackProjectileCooldown = 0.2f; + [SerializeField] float simpleAttackStayDuration = 1f; + [SerializeField] GameObject projectilePrefab; + [SerializeField] GameObject explosionParticlePrefab; + + private IEnumerator SimpleAttackCoroutine() + { + for(int i = 0; i < simpleAttackWavesCount; i++) + { + var simpleProjectiles = new List(); + + for (int j = 0; j < projectilePositions.Count; j++) + { + var projectile = projectilePool.GetEntity(); + + projectile.transform.position = projectilePositions[j].transform.position; + + projectile.StickToTransform(projectilePositions[j]); + projectile.onFinished += OnProjectileFinished; + + projectiles.Add(projectile); + simpleProjectiles.Add(projectile); + + yield return new WaitForSeconds(simpleAttackProjectileCooldown); + } + + yield return new WaitForSeconds(simpleAttackStayDuration); + + foreach (var projectile in simpleProjectiles) + { + var distanceToPlayer = PlayerBehavior.CenterPosition - projectile.transform.position.XY(); + var playerDirection = distanceToPlayer.normalized; + + projectile.LifeTime = distanceToPlayer.magnitude / projectile.Speed; + projectile.Damage = StageController.Stage.EnemyDamage * simpleAttackDamage; + + projectile.Init(projectile.transform.position, playerDirection); + + yield return new WaitForSeconds(simpleAttackProjectileCooldown); + } + } + + } + + [Header("Slow Attack")] + [SerializeField] int slowAttackRadialAmount = 10; + [SerializeField] int slowAttackWavesAmount = 3; + [SerializeField] float slowAttackDamage = 1; + [SerializeField] float slowAttackWaveCooldown = 1; + [SerializeField] GameObject spikeProjectilePrefab; + + private IEnumerator SlowAttackCoroutine() + { + for (int j = 0; j < slowAttackWavesAmount; j++) + { + for (int i = 0; i < slowAttackRadialAmount; i++) + { + var angle = 360f / 10f * i; + + var direction = Quaternion.Euler(0, 0, angle) * Vector2.up; + + var projectile = spikeProjectilePool.GetEntity(); + + projectile.Init(transform.position, direction); + projectile.Damage = StageController.Stage.EnemyDamage * slowAttackDamage; + + projectile.onFinished += OnProjectileFinished; + + projectiles.Add(projectile); + } + + yield return new WaitForSeconds(slowAttackWaveCooldown); + } + + + } + + [Header("Burst Attack")] + [SerializeField] int burstAttackRadialAmount = 10; + [SerializeField] int burstAttackSingleBurstAmount = 3; + [SerializeField] float burstAttackDamage = 1; + [SerializeField] float burstAttackProjectileCooldown = 0.05f; + [SerializeField] GameObject smallProjectilePrefab; + + private IEnumerator SmallAttackCoroutine() + { + for (int i = 0; i < burstAttackRadialAmount; i++) + { + var angle = 360f / 10f * i; + + var direction = Quaternion.Euler(0, 0, angle) * Vector2.up; + + for (int j = 0; j < burstAttackSingleBurstAmount; j++) + { + var projectile = smallProjectilePool.GetEntity(); + + projectile.Init(transform.position, direction); + projectile.Damage = StageController.Stage.EnemyDamage * burstAttackDamage; + + projectile.onFinished += OnProjectileFinished; + + projectiles.Add(projectile); + + yield return new WaitForSeconds(burstAttackProjectileCooldown); + } + } + } + + private void OnProjectileFinished(SimpleEnemyProjectileBehavior projectile) + { + projectile.onFinished -= OnProjectileFinished; + projectiles.Remove(projectile); + + if(projectile is EnemyBellProjectile bellProjectile) + { + var particle = explosionParticlePool.GetEntity(); + if (bellProjectile.Successful) + { + particle.transform.position = PlayerBehavior.Player.transform.position; + } else + { + particle.transform.position = bellProjectile.transform.position; + } + + particle.Play(); + + IEasingCoroutine coroutine = null; + coroutine = EasingManager.DoAfter(5f, () => + { + particle.gameObject.SetActive(false); + explosionCoroutines.Remove(coroutine); + }); + + explosionCoroutines.Add(coroutine); + } + } + + protected override void Die(bool flash) + { + base.Die(flash); + + if (attackCoroutine != null) + { + StopCoroutine(attackCoroutine); + attackCoroutine = null; + } + + if(movementCoroutine != null) + { + StopCoroutine(movementCoroutine); + movementCoroutine = null; + } + + foreach(var projectile in projectiles) + { + projectile.onFinished -= OnProjectileFinished; + projectile.Disable(); + } + + projectiles.Clear(); + + projectilePool.Destroy(); + smallProjectilePool.Destroy(); + spikeProjectilePool.Destroy(); + + foreach(var coroutine in explosionCoroutines) + { + coroutine.StopIfExists(); + } + + explosionCoroutines.Clear(); + + explosionParticlePool.DisableAllEntities(); + explosionParticlePool.Destroy(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/EnemyBellBehavior.cs.meta b/Assets/Common/Scripts/Enemies/EnemyBellBehavior.cs.meta new file mode 100644 index 0000000..912a5a0 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/EnemyBellBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0d686f02d5705844096c4fbd4d67a858 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/EnemyBellProjectile.cs b/Assets/Common/Scripts/Enemies/EnemyBellProjectile.cs new file mode 100644 index 0000000..dc1ae8b --- /dev/null +++ b/Assets/Common/Scripts/Enemies/EnemyBellProjectile.cs @@ -0,0 +1,52 @@ +using OctoberStudio.Easing; +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + public class EnemyBellProjectile : SimpleEnemyProjectileBehavior + { + private IEasingCoroutine scaleCoroutine; + private Transform hiddenParent; + private Vector3 localPosition; + + public bool Successful { get; private set; } + + public void StickToTransform(Transform hiddenParent) + { + this.hiddenParent = hiddenParent; + transform.position = hiddenParent.position; + localPosition = Vector3.zero; + + transform.localScale = Vector3.zero; + scaleCoroutine = transform.DoLocalScale(Vector3.one, 0.3f); + + IsActive = false; + Successful = false; + } + + protected override void Update() + { + base.Update(); + + if (!IsActive) + { + transform.position = hiddenParent.position + localPosition; + } + } + + protected override void SuccessfulHit() + { + Successful = true; + + base.SuccessfulHit(); + } + + public override void Disable() + { + base.Disable(); + + scaleCoroutine.StopIfExists(); + } + } +} + diff --git a/Assets/Common/Scripts/Enemies/EnemyBellProjectile.cs.meta b/Assets/Common/Scripts/Enemies/EnemyBellProjectile.cs.meta new file mode 100644 index 0000000..0aa9ec9 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/EnemyBellProjectile.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 781b0d5e4bb923b458ac50fa9fa911ad +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/EnemyVATAttachment.cs b/Assets/Common/Scripts/Enemies/EnemyVATAttachment.cs new file mode 100644 index 0000000..6d0380f --- /dev/null +++ b/Assets/Common/Scripts/Enemies/EnemyVATAttachment.cs @@ -0,0 +1,121 @@ +using UnityEngine; +using OctoberStudio.VAT; + +namespace OctoberStudio +{ + /// + /// 把 VAT prefab 挂到原 EnemyBehavior 上,作为视觉替换层。 + /// - 隐藏原 SpriteRenderer / Animator(留 Shadow) + /// - Spawn VAT view 作为子物体 + /// - 朝向: 把 EnemyBehavior.ExternalFacingOverride 设 true,EnemyBehavior 不再写 transform.localScale.x, + /// sign 通过 OnFacingSignChanged event 推给本组件 → 调 VATAnimationController.SetFacing。 + /// 一律走 Y 旋转,完全不依赖 localScale。 + /// + [DisallowMultipleComponent] + public class EnemyVATAttachment : MonoBehaviour + { + [Header("VAT Source")] + [Tooltip("烤好的 VAT prefab (e.g. mon1001_VAT.prefab)")] + [SerializeField] private GameObject vatPrefab; + + [Header("View Transform")] + [SerializeField] private Vector3 localOffset = new Vector3(0f, 0.3f, 0f); + [SerializeField] private Vector3 localScale = new Vector3(0.5f, 0.5f, 0.5f); + + [Header("Hide Originals")] + [Tooltip("不禁用名字含此关键字的 SpriteRenderer (默认 Shadow 阴影保留)")] + [SerializeField] private string keepNameContains = "Shadow"; + + private GameObject _spawnedView; + private VATAnimationController _vatCtrl; + private EnemyBehavior _enemy; + + private void Awake() + { + _enemy = GetComponent(); + HideOriginalSprites(); + SpawnVATView(); + if (_spawnedView != null) + { + _vatCtrl = _spawnedView.GetComponent(); + } + + // 接管 EnemyBehavior 朝向:不再写 transform.localScale.x,sign 走 event + if (_enemy != null) + { + _enemy.ExternalFacingOverride = true; + _enemy.OnFacingSignChanged += HandleEnemyFacingChanged; + } + + // 出生时同步一次初始朝向(VATAnimationController.OnEnable 默认 SetFacing(+1) 已先跑过, + // 这里覆盖一次以应对对象池复用或 prefab 上 root.scale.x 非常规情况) + if (_vatCtrl != null) _vatCtrl.SetFacing(1); + } + + private void OnDestroy() + { + if (_enemy != null) _enemy.OnFacingSignChanged -= HandleEnemyFacingChanged; + } + + private void HandleEnemyFacingChanged(int sign) + { + if (_vatCtrl != null) _vatCtrl.SetFacing(sign); + } + + private void HideOriginalSprites() + { + var all = GetComponentsInChildren(true); + foreach (var sr in all) + { + if (!string.IsNullOrEmpty(keepNameContains) && + sr.gameObject.name.IndexOf(keepNameContains, System.StringComparison.OrdinalIgnoreCase) >= 0) + continue; + sr.enabled = false; + } + + // 子物体上的 Animator 也禁用(主 Sprite 那个,Animator 切 Sprite 已无用,省 CPU) + var animators = GetComponentsInChildren(true); + foreach (var an in animators) + { + if (!string.IsNullOrEmpty(keepNameContains) && + an.gameObject.name.IndexOf(keepNameContains, System.StringComparison.OrdinalIgnoreCase) >= 0) + continue; + an.enabled = false; + } + } + + private void SpawnVATView() + { + if (vatPrefab == null) return; + _spawnedView = Instantiate(vatPrefab, transform); + _spawnedView.name = "_VAT_View"; + _spawnedView.transform.localPosition = localOffset; + _spawnedView.transform.localScale = localScale; + // 注意: 不在这里写 localRotation = identity! + // VATAnimationController.OnEnable 已在 Instantiate 中调过 SetFacing(),把 Y 设成了 ±facing 值, + // 这里 reset 会把它抹成 0,导致 LateUpdate 第一次跑之前 view 朝向是错的。 + // VAT prefab 的 root rotation 本身就是 identity,无需重置。 + } + +#if UNITY_EDITOR + // 仅给 Editor 工具读 + public GameObject VATPrefab + { + get => vatPrefab; + set => vatPrefab = value; + } + + public Vector3 LocalScale + { + get => localScale; + set => localScale = value; + } + + public Vector3 LocalOffset + { + get => localOffset; + set => localOffset = value; + } +#endif + } +} diff --git a/Assets/Common/Scripts/Enemies/EnemyVATAttachment.cs.meta b/Assets/Common/Scripts/Enemies/EnemyVATAttachment.cs.meta new file mode 100644 index 0000000..a2b4443 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/EnemyVATAttachment.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 57acf6328dd46a84d96db6cd268ccc1e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/RangedEnemyBehavior.cs b/Assets/Common/Scripts/Enemies/RangedEnemyBehavior.cs new file mode 100644 index 0000000..6d0127c --- /dev/null +++ b/Assets/Common/Scripts/Enemies/RangedEnemyBehavior.cs @@ -0,0 +1,175 @@ +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + public class RangedEnemyBehavior : EnemyBehavior + { + private static readonly int RANGED_ATTACK_TRIGGER = Animator.StringToHash("Ranged Attack"); + + [Header("Ranged Enemy Data")] + [SerializeField] Animator animator; + [SerializeField] AttackType attackType = AttackType.AtPlayer; + + [Space] + [SerializeField, Min(1)] int minProjectilesPerAttack = 1; + [SerializeField, Min(1)] int maxProjectilesPerAttack = 1; + [SerializeField] float timeBetweenProjectiles = 0f; + [SerializeField] float projectileDamage = 1f; + [SerializeField, Range(0, 90f)] float projectileSpread = 0f; + + [Header("Overrides")] + [SerializeField] bool overrideProjectileSpeed = false; + [SerializeField, Min(0.01f)] float projectileSpeed = 1f; + [SerializeField] bool overrideProjectileLifetime = false; + [SerializeField, Min(0.01f)] float projectileLifetime = 1f; + + [Space] + [SerializeField] GameObject projectilePrefab; + + [Header("Shooting Behavior")] + [SerializeField, Min(0)] float rangedAttackCooldown = 3; + [SerializeField] bool useAttackAnimation = false; + [SerializeField, Min(0)] float minDistanceToPlayerForAttacking = 5f; + private float minDistanceToPlayerForAttackingSqr; + + [Space] + [Tooltip("Only works if 'useAttackAnimation' is true")] + [SerializeField] bool changeSpeedDuringAttackAnimation = false; + [SerializeField, Min(0)] float speedDuringAttackAnimation = 1f; + + private static Dictionary> projectilePools = new Dictionary>(); + + private float lastTimeAttacked = 0; + + protected override void Awake() + { + base.Awake(); + + if (!projectilePools.ContainsKey(projectilePrefab)) + { + var pool = new PoolComponent(projectilePrefab, maxProjectilesPerAttack * 2); + projectilePools.Add(projectilePrefab, pool); + } + + minDistanceToPlayerForAttackingSqr = minDistanceToPlayerForAttacking * 2; + } + + public override void Play() + { + base.Play(); + + lastTimeAttacked = Time.time; + } + + protected override void Update() + { + base.Update(); + + var distanceToPlayer = (Center - PlayerBehavior.CenterPosition).sqrMagnitude; + + if(distanceToPlayer < minDistanceToPlayerForAttackingSqr && lastTimeAttacked + rangedAttackCooldown < Time.time) + { + if (useAttackAnimation) + { + animator.SetTrigger(RANGED_ATTACK_TRIGGER); + if (changeSpeedDuringAttackAnimation) + { + Speed = speedDuringAttackAnimation; + } + } else + { + Attack(); + } + + lastTimeAttacked = Time.time; + } + } + + public virtual void Attack() + { + if (!IsAlive) return; + + var projectilesCount = Random.Range(minProjectilesPerAttack, maxProjectilesPerAttack + 1); + + if(attackType == AttackType.Circular) + { + StartCoroutine(CircularAttack(projectilesCount)); + } else + { + StartCoroutine(AtPlayerAttack(projectilesCount)); + } + } + + protected virtual IEnumerator CircularAttack(int projectilesCount) + { + var wait = new WaitForSeconds(timeBetweenProjectiles); + + var enemyToPlayerDirection = (PlayerBehavior.CenterPosition - Center).normalized; + + var step = 360f / projectilesCount; + + for (int i = 0; i < projectilesCount; i++) + { + var projectileDirection = Quaternion.Euler(0, 0, i * step + Random.Range(-projectileSpread, projectileSpread)) * enemyToPlayerDirection; + + LaunchProjectile(projectileDirection); + + if (timeBetweenProjectiles > 0) yield return wait; + } + } + + protected virtual IEnumerator AtPlayerAttack(int projectilesCount) + { + var wait = new WaitForSeconds(timeBetweenProjectiles); + + var enemyToPlayerDirection = (PlayerBehavior.CenterPosition - Center).normalized; + + for (int i = 0; i < projectilesCount; i++) + { + var projectileDirection = Quaternion.Euler(0, 0, Random.Range(-projectileSpread, projectileSpread)) * enemyToPlayerDirection; + + LaunchProjectile(projectileDirection); + + if (timeBetweenProjectiles > 0) yield return wait; + } + } + + protected virtual void LaunchProjectile(Vector2 direction) + { + var projectile = projectilePools[projectilePrefab].GetEntity(); + + if (overrideProjectileLifetime) projectile.LifeTime = projectileLifetime; + if (overrideProjectileSpeed) projectile.Speed = projectileSpeed; + + projectile.Damage = projectileDamage; + projectile.Init(Center, direction); + } + + public void OnAttackAnimationEnded() + { + if (changeSpeedDuringAttackAnimation) + { + Speed = speed; + } + } + + public enum AttackType + { + AtPlayer = 0, + Circular = 1, + } + + protected virtual void OnDestroy() + { + if (projectilePools.ContainsKey(projectilePrefab)) + { + projectilePools[projectilePrefab].Destroy(); + projectilePools.Remove(projectilePrefab); + } + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/RangedEnemyBehavior.cs.meta b/Assets/Common/Scripts/Enemies/RangedEnemyBehavior.cs.meta new file mode 100644 index 0000000..dccbb80 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/RangedEnemyBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d4a4496d11815d848b6014f08b944435 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/RangedEnemyEventsHandler.cs b/Assets/Common/Scripts/Enemies/RangedEnemyEventsHandler.cs new file mode 100644 index 0000000..d7fbfd4 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/RangedEnemyEventsHandler.cs @@ -0,0 +1,26 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Enemy +{ + public class RangedEnemyEventsHandler : MonoBehaviour + { + private RangedEnemyBehavior rangedEnemy; + + private void Awake() + { + rangedEnemy = GetComponentInParent(); + } + + public void RangedAttackEvent() + { + rangedEnemy.Attack(); + } + + public void RangedAttackEndedEvent() + { + rangedEnemy.OnAttackAnimationEnded(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/RangedEnemyEventsHandler.cs.meta b/Assets/Common/Scripts/Enemies/RangedEnemyEventsHandler.cs.meta new file mode 100644 index 0000000..2aca6d4 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/RangedEnemyEventsHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b7041550273e3f345b64cc95b05cf4c2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/SimpleEnemyProjectileBehavior.cs b/Assets/Common/Scripts/Enemies/SimpleEnemyProjectileBehavior.cs new file mode 100644 index 0000000..feabc63 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/SimpleEnemyProjectileBehavior.cs @@ -0,0 +1,83 @@ +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio +{ + public class SimpleEnemyProjectileBehavior : MonoBehaviour + { + [SerializeField] float speed; + [Tooltip("After this amount of time the projectile will get disabled")] + [SerializeField] float lifetime; + [Tooltip("Should the projectile pass through the player or hit him and get disabled")] + [SerializeField] bool hideOnHit = true; + + [Space] + [Tooltip("Reference for clearing the trail on Disable. Can be null")] + [SerializeField] TrailRenderer trail; + + private Vector3 direction; + private float endTime; + + public bool IsActive { get; protected set; } + public float LifeTime { get; set; } + public float Damage { get; set; } + public float Speed { get; set; } + + public event UnityAction onFinished; + + private void Awake() + { + LifeTime = lifetime; + Speed = speed; + } + + public virtual void Init(Vector2 position, Vector2 direction) + { + transform.position = position; + this.direction = direction; + + endTime = Time.time + LifeTime; + + IsActive = true; + } + + protected virtual void Update() + { + if (!IsActive) return; + + if(Time.time > endTime) + { + Disable(); + return; + } + + if(Speed > 0) + { + transform.position += direction * Time.deltaTime * Speed; + } + } + + protected virtual void OnTriggerEnter2D(Collider2D collision) + { + if (hideOnHit) + { + SuccessfulHit(); + } + } + + protected virtual void SuccessfulHit() + { + Disable(); + } + + public virtual void Disable() + { + Speed = speed; + LifeTime = lifetime; + + if(trail != null) trail.Clear(); + gameObject.SetActive(false); + onFinished?.Invoke(this); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/SimpleEnemyProjectileBehavior.cs.meta b/Assets/Common/Scripts/Enemies/SimpleEnemyProjectileBehavior.cs.meta new file mode 100644 index 0000000..c46f65c --- /dev/null +++ b/Assets/Common/Scripts/Enemies/SimpleEnemyProjectileBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fbe3ee9b49261c1408ed8b1058ae0c38 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Enemies/WarningCircleBehavior.cs b/Assets/Common/Scripts/Enemies/WarningCircleBehavior.cs new file mode 100644 index 0000000..265f15f --- /dev/null +++ b/Assets/Common/Scripts/Enemies/WarningCircleBehavior.cs @@ -0,0 +1,67 @@ +using OctoberStudio.Easing; +using System; +using UnityEngine; + +namespace OctoberStudio +{ + public class WarningCircleBehavior : MonoBehaviour + { + [SerializeField] SpriteRenderer sprite; + + private IEasingCoroutine coroutine; + + private bool isFollowing; + private Transform followTarget; + private Vector3 followOffset; + private float followDrag; + + public void Play(float size, float spawnDuration, float stayDuration, Action onFinished) + { + coroutine.StopIfExists(); + + sprite.size = Vector2.zero; + coroutine = EasingManager.DoFloat(0, size, spawnDuration, SetSize).SetEasing(EasingType.SineOut).SetOnFinish(() => DelayBeforeDisable(stayDuration, onFinished)); + } + + public void Follow(Transform target, Vector3 offset, float drag) + { + isFollowing = true; + followTarget = target; + followOffset = offset; + followDrag = drag; + } + + public void StopFollowing() + { + isFollowing = false; + } + + private void SetSize(float size) + { + sprite.size = new Vector2(size, size / 2f); + } + + private void LateUpdate() + { + if (isFollowing) + { + transform.position = Vector3.Lerp(transform.position, followTarget.position + followOffset, followDrag); + } + } + + private void DelayBeforeDisable(float duration, Action onFinished) + { + coroutine = EasingManager.DoAfter(duration, () => { + onFinished?.Invoke(); + gameObject.SetActive(false); + }); + } + + private void OnDisable() + { + coroutine.StopIfExists(); + + isFollowing = false; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Enemies/WarningCircleBehavior.cs.meta b/Assets/Common/Scripts/Enemies/WarningCircleBehavior.cs.meta new file mode 100644 index 0000000..e151ed5 --- /dev/null +++ b/Assets/Common/Scripts/Enemies/WarningCircleBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 38baa991b25686e4c8f8ffa6f38ee91e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/GameController.cs b/Assets/Common/Scripts/GameController.cs new file mode 100644 index 0000000..e8d9721 --- /dev/null +++ b/Assets/Common/Scripts/GameController.cs @@ -0,0 +1,339 @@ +using OctoberStudio.Currency; +using System.Collections; +using UnityEngine; +using UnityEngine.SceneManagement; +using System.Linq; +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace OctoberStudio +{ + using OctoberStudio.Audio; + using OctoberStudio.Easing; + using OctoberStudio.Input; + using Save; + using Upgrades; + using Vibration; + + public class GameController : MonoBehaviour + { + protected static readonly string MAIN_MENU_MUSIC_NAME = "Main Menu Music"; + + private static GameController instance; + + [SerializeField] protected CurrenciesManager currenciesManager; + public static CurrenciesManager CurrenciesManager => instance.currenciesManager; + + [SerializeField] protected UpgradesManager upgradesManager; + public static UpgradesManager UpgradesManager => instance.upgradesManager; + + [SerializeField] protected ProjectSettings projectSettings; + public static ProjectSettings ProjectSettings => instance.projectSettings; + + public static ISaveManager SaveManager { get; private set; } + public static IAudioManager AudioManager { get; private set; } + public static IVibrationManager VibrationManager { get; private set; } + public static IInputManager InputManager { get; private set; } + + public static CurrencySave Gold { get; private set; } + public static CurrencySave TempGold { get; private set; } + + public static AudioSource Music { get; private set; } + + private static StageSave stageSave; + + // Indicates that the main menu is just loaded, and not exited from the game scene + public static bool FirstTimeLoaded { get; private set; } + + protected virtual void Awake() + { + if (instance != null) + { + Destroy(this); + + FirstTimeLoaded = false; + + return; + } + + instance = this; + + FirstTimeLoaded = true; + + currenciesManager.Init(); + + DontDestroyOnLoad(gameObject); + + Application.targetFrameRate = 120; + } + + protected virtual void Start() + { + Gold = SaveManager.GetSave("gold"); + TempGold = SaveManager.GetSave("temp_gold"); + + stageSave = SaveManager.GetSave("Stage"); + + if (!stageSave.loadedBefore) + { + stageSave.loadedBefore = true; + } +#if UNITY_WEBGL && !UNITY_EDITOR + InputManager.InputAsset.UI.Click.performed += MusicStartWebGL; +#else + + EasingManager.DoAfter(0.2f, () => Music = AudioManager.PlayMusic(MAIN_MENU_MUSIC_NAME.GetHashCode())); +#endif + } + +#if UNITY_WEBGL && !UNITY_EDITOR + protected virtual void MusicStartWebGL(UnityEngine.InputSystem.InputAction.CallbackContext context) + { + InputManager.InputAsset.UI.Click.performed -= MusicStartWebGL; + + Music = AudioManager.PlayMusic(MAIN_MENU_MUSIC_NAME.GetHashCode()); + } +#endif + public static void ChangeMusic(string musicName) + { + if (Music != null) + { + var oldMusic = Music; + oldMusic.DoVolume(0, 0.3f).SetOnFinish(() => oldMusic.Stop()); + } + + Music = AudioManager.PlayMusic(musicName.GetHashCode()); + + if(Music != null) + { + var volume = Music.volume; + Music.volume = 0; + Music.DoVolume(volume, 0.3f); + } + } + + public static void ChangeMusic(SoundContainer music) + { + if (Music != null) + { + var oldMusic = Music; + oldMusic.DoVolume(0, 0.3f).SetOnFinish(() => oldMusic.Stop()); + } + + Music = music.Play(true); + + if (Music != null) + { + var volume = Music.volume; + Music.volume = 0; + Music.DoVolume(volume, 0.3f); + } + } + + public static void RegisterInputManager(IInputManager inputManager) + { + InputManager = inputManager; + } + + public static void RegisterSaveManager(ISaveManager saveManager) + { + SaveManager = saveManager; + } + + public static void RegisterVibrationManager(IVibrationManager vibrationManager) + { + VibrationManager = vibrationManager; + } + + public static void RegisterAudioManager(IAudioManager audioManager) + { + AudioManager = audioManager; + } + + public static void LoadStage() + { + if(stageSave.ResetStageData) TempGold.Withdraw(TempGold.Amount); + + instance.StartCoroutine(StageLoadingCoroutine()); + + SaveManager.Save(false); + } + + public static void LoadMainMenu() + { + Gold.Deposit(TempGold.Amount); + TempGold.Withdraw(TempGold.Amount); + + if (instance != null) instance.StartCoroutine(MainMenuLoadingCoroutine()); + + SaveManager.Save(false); + } + + protected static string GetLoadingScreenSceneName() + { + if (ProjectSettings != null && SceneExists(ProjectSettings.LoadingSceneName)) + { + return ProjectSettings.LoadingSceneName; + } + else if (SceneExists("Loading Screen")) + { + return "Loading Screen"; + } + else + { + Debug.LogWarning("Loading screen scene not found. Please add a loading screen scene to the project settings or ensure it exists in the build settings."); + return null; + } + } + + protected static string GetMainMenuSceneName() + { + if (ProjectSettings != null && SceneExists(ProjectSettings.MainMenuSceneName)) + { + return ProjectSettings.MainMenuSceneName; + } + else if (SceneExists("Main Menu")) + { + return "Main Menu"; + } + else + { + Debug.LogError("Main menu scene not found. Please add a main menu scene to the project settings or ensure it exists in the build settings."); + return null; + } + } + + protected static string GetGameSceneName() + { + if (ProjectSettings != null && SceneExists(ProjectSettings.GameSceneName)) + { + return ProjectSettings.GameSceneName; + } + else if (SceneExists("Game")) + { + return "Game"; + } + else + { + Debug.LogError("Game scene not found. Please add a game scene to the project settings or ensure it exists in the build settings."); + return null; + } + } + + protected static IEnumerator StageLoadingCoroutine() + { + var loadingSceneName = GetLoadingScreenSceneName(); + var mainMenuSceneName = GetMainMenuSceneName(); + var gameSceneName = GetGameSceneName(); + + if (loadingSceneName != null) + { + yield return LoadAsyncScene(loadingSceneName, LoadSceneMode.Additive); + } + + yield return UnloadAsyncScene(mainMenuSceneName); + yield return LoadAsyncScene(gameSceneName, LoadSceneMode.Single); + } + + protected static IEnumerator MainMenuLoadingCoroutine() + { + var loadingSceneName = GetLoadingScreenSceneName(); + var mainMenuSceneName = GetMainMenuSceneName(); + var gameSceneName = GetGameSceneName(); + + if (loadingSceneName != null) + { + yield return LoadAsyncScene(loadingSceneName, LoadSceneMode.Additive); + } + + yield return UnloadAsyncScene(gameSceneName); + yield return LoadAsyncScene(mainMenuSceneName, LoadSceneMode.Single); + + if (StageController.Stage.UseCustomMusic) + { + ChangeMusic(MAIN_MENU_MUSIC_NAME); + } + } + + protected static bool SceneExists(string sceneName) + { +#if UNITY_EDITOR + return SceneExistsInAssets(sceneName); +#else + return SceneExistsInBuildSettings(sceneName); +#endif + } + + protected static bool SceneExistsInBuildSettings(string sceneName) + { + int sceneCount = UnityEngine.SceneManagement.SceneManager.sceneCountInBuildSettings; + + for (int i = 0; i < sceneCount; i++) + { + string path = UnityEngine.SceneManagement.SceneUtility.GetScenePathByBuildIndex(i); + string name = System.IO.Path.GetFileNameWithoutExtension(path); + if (name == sceneName) + return true; + } + + return false; + } + +#if UNITY_EDITOR + + public static bool SceneExistsInAssets(string sceneName) + { + string[] guids = AssetDatabase.FindAssets($"t:Scene {sceneName}"); + return guids.Any(guid => + { + string path = AssetDatabase.GUIDToAssetPath(guid); + return System.IO.Path.GetFileNameWithoutExtension(path) == sceneName; + }); + } + +#endif + + protected static IEnumerator UnloadAsyncScene(string sceneName) + { + var asyncLoad = SceneManager.UnloadSceneAsync(sceneName); + asyncLoad.allowSceneActivation = false; + //wait until the asynchronous scene fully loads + while (!asyncLoad.isDone) + { + yield return null; + } + } + + protected static IEnumerator LoadAsyncScene(string sceneName, LoadSceneMode loadSceneMode) + { + var asyncLoad = SceneManager.LoadSceneAsync(sceneName, loadSceneMode); + asyncLoad.allowSceneActivation = false; + //wait until the asynchronous scene fully loads + while (!asyncLoad.isDone) + { + //scene has loaded as much as possible, + // the last 10% can't be multi-threaded + if (asyncLoad.progress >= 0.9f) + { + asyncLoad.allowSceneActivation = true; + } + yield return null; + } + } + + protected virtual void OnApplicationFocus(bool focus) + { +#if UNITY_WEBGL && !UNITY_EDITOR + if (focus) { + EasingManager.DoAfter(0.1f, () => { + if (!Music.isPlaying) + { + Music = AudioManager.AudioDatabase.Music.Play(true); + } + }); + } +#endif + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/GameController.cs.meta b/Assets/Common/Scripts/GameController.cs.meta new file mode 100644 index 0000000..b7dc6c3 --- /dev/null +++ b/Assets/Common/Scripts/GameController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6aaa52e8b9d598b4aae2ff8e06c8bcaa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: -10 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Player.meta b/Assets/Common/Scripts/Player.meta new file mode 100644 index 0000000..55222ba --- /dev/null +++ b/Assets/Common/Scripts/Player.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 32f7199920f9cfb4b8dde36416145fcf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Player/CharacterBehavior.cs b/Assets/Common/Scripts/Player/CharacterBehavior.cs new file mode 100644 index 0000000..aed70aa --- /dev/null +++ b/Assets/Common/Scripts/Player/CharacterBehavior.cs @@ -0,0 +1,122 @@ +using OctoberStudio.Easing; +using OctoberStudio.Rendering; +using OctoberStudio.VAT; +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio +{ + public class CharacterBehavior : MonoBehaviour, ICharacterBehavior + { + protected static readonly int DEFEAT_TRIGGER = Animator.StringToHash("Defeat"); + protected static readonly int REVIVE_TRIGGER = Animator.StringToHash("Revive"); + protected static readonly int SPEED_FLOAT = Animator.StringToHash("Speed"); + + protected static readonly int _Overlay = Shader.PropertyToID("_Overlay"); + + // 把"角色逻辑事件"翻译成"VAT clip 名"。3D 模式下挂 controller 即可,2D 模式留空不影响。 + protected const string VAT_CLIP_IDLE = "Idle"; + protected const string VAT_CLIP_RUN = "Run"; + protected const string VAT_CLIP_DIE = "Die"; + protected const float VAT_SPEED_THRESHOLD = 0.01f; + + [Tooltip("可选:挂载 RendererAdapter 切换 2D/3D 渲染。未挂时回退到下方 SpriteRenderer 字段。")] + [SerializeField] protected RendererAdapter rendererAdapter; + [SerializeField] protected SpriteRenderer playerSpriteRenderer; + [SerializeField] protected Animator animator; + [Tooltip("可选:3D VAT 模式下使用。SetSpeed/PlayDefeatAnimation/PlayReviveAnimation 会同步切换 VAT clip。")] + [SerializeField] protected VATAnimationController vatAnimationController; + [SerializeField] protected Color hitColor; + [SerializeField] protected Transform centerTransform; + public Transform CenterTransform => centerTransform; + + public Transform Transform => transform; + + protected IEasingCoroutine damageCoroutine; + + /// + /// 优先用 RendererAdapter 的 Material,否则回退到 SpriteRenderer.material。 + /// + protected virtual Material HitMaterial + { + get => rendererAdapter != null ? rendererAdapter.Material : playerSpriteRenderer.material; + set + { + if (rendererAdapter != null) rendererAdapter.Material = value; + else playerSpriteRenderer.material = value; + } + } + + protected virtual void Reset() + { + if (rendererAdapter == null) rendererAdapter = GetComponent(); + if (vatAnimationController == null) vatAnimationController = GetComponentInChildren(true); + } + + protected virtual void Awake() + { + // 编辑器没拖时,运行时再尝试自动找(支持 nested prefab 中后挂上来的情况) + if (vatAnimationController == null) vatAnimationController = GetComponentInChildren(true); + } + + public virtual void SetSpeed(float speed) + { + if (animator != null) animator.SetFloat(SPEED_FLOAT, speed); + if (vatAnimationController != null) + { + vatAnimationController.Play(speed > VAT_SPEED_THRESHOLD ? VAT_CLIP_RUN : VAT_CLIP_IDLE); + } + } + + public virtual void SetLocalScale(Vector3 scale) + { + // VAT 3D 模式: PlayerBehavior 传过来的 scale.x=±1 是 2D 翻转语义, + // 3D 模型不能用 scale.x=-1 (会翻转法线 / culling),改用 VATAnimationController.SetFacing 旋转 + if (vatAnimationController != null) + { + vatAnimationController.SetFacing(scale.x >= 0 ? 1 : -1); + return; + } + transform.localScale = scale; + } + + public virtual void PlayReviveAnimation() + { + if (animator != null) animator.SetTrigger(REVIVE_TRIGGER); + if (vatAnimationController != null) vatAnimationController.Play(VAT_CLIP_IDLE); + } + + public virtual void PlayDefeatAnimation() + { + if (animator != null) animator.SetTrigger(DEFEAT_TRIGGER); + if (vatAnimationController != null) vatAnimationController.Play(VAT_CLIP_DIE, loop: false); + } + + public virtual void SetSortingOrder(int order) + { + if (rendererAdapter != null) rendererAdapter.SortingOrder = order; + else if (playerSpriteRenderer != null) playerSpriteRenderer.sortingOrder = order; + } + + public virtual void FlashHit(UnityAction onFinish = null) + { + if (damageCoroutine.ExistsAndActive()) return; + + var transparentColor = hitColor; + transparentColor.a = 0; + + var mat = HitMaterial; + if (mat == null || !mat.HasProperty(_Overlay)) + { + onFinish?.Invoke(); + return; + } + mat.SetColor(_Overlay, transparentColor); + + damageCoroutine = mat.DoColor(_Overlay, hitColor, 0.05f).SetOnFinish(() => + { + damageCoroutine = mat.DoColor(_Overlay, transparentColor, 0.05f).SetOnFinish(onFinish); + }); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Player/CharacterBehavior.cs.meta b/Assets/Common/Scripts/Player/CharacterBehavior.cs.meta new file mode 100644 index 0000000..0dde188 --- /dev/null +++ b/Assets/Common/Scripts/Player/CharacterBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1061c56794a23ad47b3e6846c87c83c4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Player/Data.meta b/Assets/Common/Scripts/Player/Data.meta new file mode 100644 index 0000000..74505fb --- /dev/null +++ b/Assets/Common/Scripts/Player/Data.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0dd612718f227ff40903bb14311e0c60 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Player/Data/CharacterData.cs b/Assets/Common/Scripts/Player/Data/CharacterData.cs new file mode 100644 index 0000000..efc1f8b --- /dev/null +++ b/Assets/Common/Scripts/Player/Data/CharacterData.cs @@ -0,0 +1,36 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio +{ + [System.Serializable] + public class CharacterData + { + [SerializeField] protected string name; + public string Name => name; + + [SerializeField] protected int cost; + public int Cost => cost; + + [SerializeField] protected Sprite icon; + public Sprite Icon => icon; + + [SerializeField] protected GameObject prefab; + public GameObject Prefab => prefab; + + [Space] + [SerializeField] protected bool hasStartingAbility = false; + public bool HasStartingAbility => hasStartingAbility; + + [SerializeField] protected AbilityType startingAbility; + public AbilityType StartingAbility => startingAbility; + + [Space] + [SerializeField, Min(1)] protected float baseHP; + public float BaseHP => baseHP; + + [SerializeField, Min(1f)] protected float baseDamage; + public float BaseDamage => baseDamage; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Player/Data/CharacterData.cs.meta b/Assets/Common/Scripts/Player/Data/CharacterData.cs.meta new file mode 100644 index 0000000..b018f2b --- /dev/null +++ b/Assets/Common/Scripts/Player/Data/CharacterData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e82dc72e3081ee14b8ade372515dd883 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Player/Data/CharactersDatabase.cs b/Assets/Common/Scripts/Player/Data/CharactersDatabase.cs new file mode 100644 index 0000000..692e136 --- /dev/null +++ b/Assets/Common/Scripts/Player/Data/CharactersDatabase.cs @@ -0,0 +1,18 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio +{ + [CreateAssetMenu(fileName = "Characters Database", menuName = "October/Characters Database")] + public class CharactersDatabase : ScriptableObject + { + [SerializeField] protected List characters = new List(); + public int CharactersCount => characters.Count; + + public virtual CharacterData GetCharacterData(int index) + { + return characters[index]; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Player/Data/CharactersDatabase.cs.meta b/Assets/Common/Scripts/Player/Data/CharactersDatabase.cs.meta new file mode 100644 index 0000000..87ae130 --- /dev/null +++ b/Assets/Common/Scripts/Player/Data/CharactersDatabase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6347c4bf45db0cb4b9b95edb3aa5908e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Player/Data/CharactersSave.cs b/Assets/Common/Scripts/Player/Data/CharactersSave.cs new file mode 100644 index 0000000..0618ee7 --- /dev/null +++ b/Assets/Common/Scripts/Player/Data/CharactersSave.cs @@ -0,0 +1,60 @@ +using OctoberStudio.Save; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio +{ + public class CharactersSave : ISave + { + [SerializeField] protected int[] boughtCharacterIds; + [SerializeField] protected int selectedCharacterId; + + public UnityAction onSelectedCharacterChanged; + + public int SelectedCharacterId => selectedCharacterId; + + protected List BoughtCharacterIds { get; set; } + + public virtual void Init() + { + if (boughtCharacterIds == null) + { + boughtCharacterIds = new int[] { 0 }; + + selectedCharacterId = 0; + } + BoughtCharacterIds = new List(boughtCharacterIds); + } + + public virtual bool HasCharacterBeenBought(int id) + { + if (BoughtCharacterIds == null) Init(); + + return BoughtCharacterIds.Contains(id); + } + + public virtual void AddBoughtCharacter(int id) + { + if (BoughtCharacterIds == null) Init(); + + BoughtCharacterIds.Add(id); + } + + public virtual void SetSelectedCharacterId(int id) + { + if (BoughtCharacterIds == null) Init(); + + selectedCharacterId = id; + + onSelectedCharacterChanged?.Invoke(); + } + + public virtual void Flush() + { + if (BoughtCharacterIds == null) Init(); + + boughtCharacterIds = BoughtCharacterIds.ToArray(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Player/Data/CharactersSave.cs.meta b/Assets/Common/Scripts/Player/Data/CharactersSave.cs.meta new file mode 100644 index 0000000..a3d8036 --- /dev/null +++ b/Assets/Common/Scripts/Player/Data/CharactersSave.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2f8fc3b2e579bd447972a7810488e6d3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Player/Effect.cs b/Assets/Common/Scripts/Player/Effect.cs new file mode 100644 index 0000000..be718f5 --- /dev/null +++ b/Assets/Common/Scripts/Player/Effect.cs @@ -0,0 +1,34 @@ +using UnityEngine; + +namespace OctoberStudio +{ + [System.Serializable] + public class Effect + { + [SerializeField] protected EffectType type; + [SerializeField] protected float modifier; + [SerializeField] protected bool useOnEnemies = true; + + public EffectType EffectType => type; + public float Modifier => modifier; + public bool UseOnEnemies => useOnEnemies; + + public Effect(EffectType type, float modifier) + { + this.type = type; + this.modifier = modifier; + } + + public virtual void SetModifier(float modifier) + { + this.modifier = modifier; + } + } + + [System.Serializable] + public enum EffectType + { + Speed = 0, + Damage = 1, + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Player/Effect.cs.meta b/Assets/Common/Scripts/Player/Effect.cs.meta new file mode 100644 index 0000000..a0db4f2 --- /dev/null +++ b/Assets/Common/Scripts/Player/Effect.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8a2b82cc9d51cff4fad2a96b610957bc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Player/FollowPlayerBehavior.cs b/Assets/Common/Scripts/Player/FollowPlayerBehavior.cs new file mode 100644 index 0000000..f0a2f4a --- /dev/null +++ b/Assets/Common/Scripts/Player/FollowPlayerBehavior.cs @@ -0,0 +1,17 @@ +using UnityEngine; + +namespace OctoberStudio +{ + public class FollowPlayerBehavior : MonoBehaviour + { + [SerializeField] protected Vector3 offset; + + protected virtual void Update() + { + if(PlayerBehavior.Player != null) + { + transform.position = PlayerBehavior.Player.transform.position + offset; + } + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Player/FollowPlayerBehavior.cs.meta b/Assets/Common/Scripts/Player/FollowPlayerBehavior.cs.meta new file mode 100644 index 0000000..97a2173 --- /dev/null +++ b/Assets/Common/Scripts/Player/FollowPlayerBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d4a30ceb24ca9c34e8abd861e2dfb4f6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Player/HealthbarBehavior.cs b/Assets/Common/Scripts/Player/HealthbarBehavior.cs new file mode 100644 index 0000000..aa84ece --- /dev/null +++ b/Assets/Common/Scripts/Player/HealthbarBehavior.cs @@ -0,0 +1,169 @@ +using OctoberStudio.Easing; +using OctoberStudio.Extensions; +using UnityEngine; + +namespace OctoberStudio +{ + public class HealthbarBehavior : MonoBehaviour + { + [SerializeField] protected SpriteRenderer fillImage; + [SerializeField] protected SpriteRenderer backgroundImage; + [SerializeField] protected Transform maskTransform; + [SerializeField] protected float maskMaxPosition; + [SerializeField] protected float maskMaxScale; + + public float MaxHP { get; private set; } + public float HP { get; private set; } + + public bool IsZero => HP <= 0; + public bool IsMax => HP >= MaxHP; + + protected bool autoShowOnChaned; + protected bool autoHideWhenMax; + + protected IEasingCoroutine showHideCoroutine; + + protected bool isShown = false; + + public virtual void Init(float maxHP) + { + MaxHP = maxHP; + HP = MaxHP; + + Redraw(); + + } + + public virtual void SetAutoShowOnChanged(bool value) + { + autoShowOnChaned = value; + } + + public virtual void SetAutoHideWhenMax(bool value) + { + autoHideWhenMax = value; + if (HP == MaxHP) ForceHide(); + } + + public virtual void AddHP(float value) + { + if(value < 0) + { + Subtract(-value); + return; + } + + HP += value; + if (HP > MaxHP) + { + HP = MaxHP; + if (autoHideWhenMax) Hide(); + } + + Redraw(); + } + + public virtual void AddPercentage(float percent) + { + AddHP(MaxHP * percent / 100f); + } + + public virtual void Subtract(float value) + { + if (value < 0) + { + AddHP(-value); + return; + } + + HP -= value; + + if (HP <= 0) + { + HP = 0; + Hide(); + } + else + { + if (autoShowOnChaned && !isShown) Show(); + Redraw(); + } + } + + public virtual void ResetHP(float duration = 0) + { + if(duration > 0) + { + EasingManager.DoFloat(0, MaxHP, duration, (hp) => + { + HP = hp; + Redraw(); + }); + + Show(); + } else + { + HP = MaxHP; + Redraw(); + } + } + + public virtual void ChangeMaxHP(float newMaxHP, bool scaleHP = true) + { + var oldMaxHP = MaxHP; + MaxHP = newMaxHP; + + if (scaleHP) + { + var scaleFactor = newMaxHP / oldMaxHP; + + var newHP = HP * scaleFactor; + var difference = newHP - HP; + + AddHP(difference); + } else + { + Redraw(); + } + + } + + public virtual void Redraw() + { + float t = HP / MaxHP; + maskTransform.localPosition = Vector3.left * maskMaxPosition * (1 - t); + maskTransform.localScale = maskTransform.localScale.SetX(maskMaxScale * t); + } + + public virtual void Show() + { + Redraw(); + + isShown = true; + + if (showHideCoroutine != null && showHideCoroutine.IsActive) showHideCoroutine.Stop(); + showHideCoroutine = new FloatEasingCoroutine(fillImage.color.a, 1f, 0.3f, 0, SetAlpha).SetEasing(EasingType.SineOut); + } + + public virtual void Hide() + { + isShown = false; + + if (showHideCoroutine != null && showHideCoroutine.IsActive) showHideCoroutine.Stop(); + showHideCoroutine = new FloatEasingCoroutine(fillImage.color.a, 0f, 0.3f, 0, SetAlpha).SetEasing(EasingType.SineOut); + } + + public virtual void ForceHide() + { + isShown = false; + + SetAlpha(0); + } + + protected virtual void SetAlpha(float alpha) + { + if (fillImage != null) fillImage.SetAlpha(alpha); + if (backgroundImage != null) backgroundImage.SetAlpha(alpha); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Player/HealthbarBehavior.cs.meta b/Assets/Common/Scripts/Player/HealthbarBehavior.cs.meta new file mode 100644 index 0000000..55fcad3 --- /dev/null +++ b/Assets/Common/Scripts/Player/HealthbarBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c808b7ebb29ce7242a2c427899076e94 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Player/ICharacterBehavior.cs b/Assets/Common/Scripts/Player/ICharacterBehavior.cs new file mode 100644 index 0000000..aec9b3e --- /dev/null +++ b/Assets/Common/Scripts/Player/ICharacterBehavior.cs @@ -0,0 +1,21 @@ +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio +{ + public interface ICharacterBehavior + { + Transform Transform { get; } + Transform CenterTransform { get; } + + void SetSpeed(float speed); + + void SetLocalScale(Vector3 scale); + void SetSortingOrder(int order); + + void PlayReviveAnimation(); + void PlayDefeatAnimation(); + + void FlashHit(UnityAction onFinish = null); + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Player/ICharacterBehavior.cs.meta b/Assets/Common/Scripts/Player/ICharacterBehavior.cs.meta new file mode 100644 index 0000000..f4593db --- /dev/null +++ b/Assets/Common/Scripts/Player/ICharacterBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 01030d260228db240b25a588353c7d86 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Player/PlayerBehavior.cs b/Assets/Common/Scripts/Player/PlayerBehavior.cs new file mode 100644 index 0000000..0f9992f --- /dev/null +++ b/Assets/Common/Scripts/Player/PlayerBehavior.cs @@ -0,0 +1,366 @@ +using OctoberStudio.Easing; +using OctoberStudio.Extensions; +using OctoberStudio.Upgrades; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio +{ + public class PlayerBehavior : MonoBehaviour + { + protected static readonly int DEATH_HASH = "Death".GetHashCode(); + protected static readonly int REVIVE_HASH = "Revive".GetHashCode(); + protected static readonly int RECEIVING_DAMAGE_HASH = "Receiving Damage".GetHashCode(); + + protected static PlayerBehavior instance; + public static PlayerBehavior Player => instance; + + [SerializeField] protected CharactersDatabase charactersDatabase; + + [Header("Stats")] + [SerializeField, Min(0.01f)] protected float speed = 2; + [SerializeField, Min(0.1f)] protected float defaultMagnetRadius = 0.75f; + [SerializeField, Min(1f)] protected float xpMultiplier = 1; + [SerializeField, Range(0.1f, 1f)] protected float cooldownMultiplier = 1; + [SerializeField, Range(0, 100)] protected int initialDamageReductionPercent = 0; + [SerializeField, Min(1f)] protected float initialProjectileSpeedMultiplier = 1; + [SerializeField, Min(1f)] protected float initialSizeMultiplier = 1f; + [SerializeField, Min(1f)] protected float initialDurationMultiplier = 1f; + [SerializeField, Min(1f)] protected float initialGoldMultiplier = 1; + + [Header("References")] + [SerializeField] protected HealthbarBehavior healthbar; + [SerializeField] protected Transform centerPoint; + [SerializeField] protected PlayerEnemyCollisionHelper collisionHelper; + + public static Transform CenterTransform => instance.centerPoint; + public static Vector2 CenterPosition { + get + { + if(instance.Character != null && instance.Character.CenterTransform != null) + { + return instance.Character.CenterTransform.position; + } + return instance.centerPoint.position; + } + } + + [Header("Death and Revive")] + [SerializeField] protected ParticleSystem reviveParticle; + + [Space] + [SerializeField] protected SpriteRenderer reviveBackgroundSpriteRenderer; + [SerializeField, Range(0, 1)] protected float reviveBackgroundAlpha; + [SerializeField, Range(0, 1)] protected float reviveBackgroundSpawnDelay; + [SerializeField, Range(0, 1)] protected float reviveBackgroundHideDelay; + + [Space] + [SerializeField] protected SpriteRenderer reviveBottomSpriteRenderer; + [SerializeField, Range(0, 1)] protected float reviveBottomAlpha; + [SerializeField, Range(0, 1)] protected float reviveBottomSpawnDelay; + [SerializeField, Range(0, 1)] protected float reviveBottomHideDelay; + + [Header("Other")] + [SerializeField] protected Vector2 fenceOffset; + [SerializeField] protected Color hitColor; + [SerializeField] protected float enemyInsideDamageInterval = 2f; + + public event UnityAction onPlayerDied; + + public float Damage { get; protected set; } + public float MagnetRadiusSqr { get; protected set; } + public float Speed { get; protected set; } + + public float XPMultiplier { get; protected set; } + public float CooldownMultiplier { get; protected set; } + public float DamageReductionMultiplier { get; protected set; } + public float ProjectileSpeedMultiplier { get; protected set; } + public float SizeMultiplier { get; protected set; } + public float DurationMultiplier { get; protected set; } + public float GoldMultiplier { get; protected set; } + + public Vector2 LookDirection { get; protected set; } + public bool IsMovingAlowed { get; set; } + + protected bool invincible = false; + + protected List enemiesInside = new List(); + + protected CharactersSave charactersSave; + public CharacterData Data { get; set; } + protected ICharacterBehavior Character { get; set; } + + protected virtual void Awake() + { + charactersSave = GameController.SaveManager.GetSave("Characters"); + Data = charactersDatabase.GetCharacterData(charactersSave.SelectedCharacterId); + + Character = Instantiate(Data.Prefab).GetComponent(); + Character.Transform.SetParent(transform); + Character.Transform.ResetLocal(); + + instance = this; + healthbar.Init(Data.BaseHP); + healthbar.SetAutoHideWhenMax(true); + healthbar.SetAutoShowOnChanged(true); + + RecalculateMagnetRadius(1); + RecalculateMoveSpeed(1); + RecalculateDamage(1); + RecalculateMaxHP(1); + RecalculateXPMuliplier(1); + RecalculateCooldownMuliplier(1); + RecalculateDamageReduction(0); + RecalculateProjectileSpeedMultiplier(1f); + RecalculateSizeMultiplier(1f); + RecalculateDurationMultiplier(1); + RecalculateGoldMultiplier(1); + + LookDirection = Vector2.right; + + IsMovingAlowed = true; + } + + protected virtual void Update() + { + if (healthbar.IsZero) return; + + foreach(var enemy in enemiesInside) + { + if (Time.time - enemy.LastTimeDamagedPlayer > enemyInsideDamageInterval) + { + TakeDamage(enemy.GetDamage()); + enemy.LastTimeDamagedPlayer = Time.time; + } + } + + if (!IsMovingAlowed) return; + + var input = GameController.InputManager.MovementValue; + + float joysticPower = input.magnitude; + Character.SetSpeed(joysticPower); + + if (!Mathf.Approximately(joysticPower, 0) && Time.timeScale > 0) + { + var frameMovement = input * Time.deltaTime * Speed; + + if (StageController.FieldManager.ValidatePosition(transform.position + Vector3.right * frameMovement.x, fenceOffset)) + { + transform.position += Vector3.right * frameMovement.x; + } + + if (StageController.FieldManager.ValidatePosition(transform.position + Vector3.up * frameMovement.y, fenceOffset)) + { + transform.position += Vector3.up * frameMovement.y; + } + + collisionHelper.transform.localPosition = Vector3.zero; + + Character.SetLocalScale(new Vector3(input.x > 0 ? 1 : -1, 1, 1)); + + LookDirection = input.normalized; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual bool IsInsideMagnetRadius(Transform target) + { + return (transform.position - target.position).sqrMagnitude <= MagnetRadiusSqr; + } + + public virtual void RecalculateMagnetRadius(float magnetRadiusMultiplier) + { + MagnetRadiusSqr = Mathf.Pow(defaultMagnetRadius * magnetRadiusMultiplier, 2); + } + + public virtual void RecalculateMoveSpeed(float moveSpeedMultiplier) + { + Speed = speed * moveSpeedMultiplier; + } + + public virtual void RecalculateDamage(float damageMultiplier) + { + Damage = Data.BaseDamage * damageMultiplier; + if (GameController.UpgradesManager.IsUpgradeAquired(UpgradeType.Damage)) + { + Damage *= GameController.UpgradesManager.GetUpgadeValue(UpgradeType.Damage); + } + } + + public virtual void RecalculateMaxHP(float maxHPMultiplier) + { + var upgradeValue = GameController.UpgradesManager.GetUpgadeValue(UpgradeType.Health); + healthbar.ChangeMaxHP((Data.BaseHP + upgradeValue) * maxHPMultiplier); + } + + public virtual void RecalculateXPMuliplier(float xpMultiplier) + { + XPMultiplier = this.xpMultiplier * xpMultiplier; + } + + public virtual void RecalculateCooldownMuliplier(float cooldownMultiplier) + { + CooldownMultiplier = this.cooldownMultiplier * cooldownMultiplier; + } + + public virtual void RecalculateDamageReduction(float damageReductionPercent) + { + DamageReductionMultiplier = (100f - initialDamageReductionPercent - damageReductionPercent) / 100f; + + if (GameController.UpgradesManager.IsUpgradeAquired(UpgradeType.Armor)) + { + DamageReductionMultiplier *= GameController.UpgradesManager.GetUpgadeValue(UpgradeType.Armor); + } + } + + public virtual void RecalculateProjectileSpeedMultiplier(float projectileSpeedMultiplier) + { + ProjectileSpeedMultiplier = initialProjectileSpeedMultiplier * projectileSpeedMultiplier; + } + + public virtual void RecalculateSizeMultiplier(float sizeMultiplier) + { + SizeMultiplier = initialSizeMultiplier * sizeMultiplier; + } + + public virtual void RecalculateDurationMultiplier(float durationMultiplier) + { + DurationMultiplier = initialDurationMultiplier * durationMultiplier; + } + + public virtual void RecalculateGoldMultiplier(float goldMultiplier) + { + GoldMultiplier = initialGoldMultiplier * goldMultiplier; + } + + public virtual void RestoreHP(float hpPercent) + { + healthbar.AddPercentage(hpPercent); + } + + public virtual void Heal(float hp) + { + healthbar.AddHP(hp + GameController.UpgradesManager.GetUpgadeValue(UpgradeType.Healing)); + } + + public virtual void Revive() + { + Character.PlayReviveAnimation(); + reviveParticle.Play(); + + invincible = true; + IsMovingAlowed = false; + healthbar.ResetHP(1f); + + Character.SetSortingOrder(102); + + reviveBackgroundSpriteRenderer.DoAlpha(0f, 0.3f, reviveBottomHideDelay).SetUnscaledTime(true).SetOnFinish(() => reviveBackgroundSpriteRenderer.gameObject.SetActive(false)); + reviveBottomSpriteRenderer.DoAlpha(0f, 0.3f, reviveBottomHideDelay).SetUnscaledTime(true).SetOnFinish(() => reviveBottomSpriteRenderer.gameObject.SetActive(false)); + + GameController.AudioManager.PlaySound(REVIVE_HASH); + EasingManager.DoAfter(1f, () => + { + IsMovingAlowed = true; + Character.SetSortingOrder(0); + }); + + EasingManager.DoAfter(3, () => invincible = false); + } + + public virtual void CheckTriggerEnter2D(Collider2D collision) + { + if (collision.gameObject.layer == 7) + { + if (invincible) return; + + var enemy = collision.GetComponent(); + + if (enemy != null) + { + enemiesInside.Add(enemy); + enemy.LastTimeDamagedPlayer = Time.time; + + enemy.onEnemyDied += OnEnemyDied; + TakeDamage(enemy.GetDamage()); + } + } + else + { + if (invincible) return; + + var projectile = collision.GetComponent(); + if (projectile != null) + { + TakeDamage(projectile.Damage); + } + } + } + + public virtual void CheckTriggerExit2D(Collider2D collision) + { + if (collision.gameObject.layer == 7) + { + if (invincible) return; + + var enemy = collision.GetComponent(); + + if (enemy != null) + { + enemiesInside.Remove(enemy); + enemy.onEnemyDied -= OnEnemyDied; + } + } + } + + protected virtual void OnEnemyDied(EnemyBehavior enemy) + { + enemy.onEnemyDied -= OnEnemyDied; + enemiesInside.Remove(enemy); + } + + protected float lastTimeVibrated = 0f; + + public virtual void TakeDamage(float damage) + { + if (invincible || healthbar.IsZero) return; + + healthbar.Subtract(damage * DamageReductionMultiplier); + + Character.FlashHit(); + + if (healthbar.IsZero) + { + Character.PlayDefeatAnimation(); + Character.SetSortingOrder(102); + + reviveBackgroundSpriteRenderer.gameObject.SetActive(true); + reviveBackgroundSpriteRenderer.DoAlpha(reviveBackgroundAlpha, 0.3f, reviveBackgroundSpawnDelay).SetUnscaledTime(true); + reviveBackgroundSpriteRenderer.transform.position = transform.position.SetZ(reviveBackgroundSpriteRenderer.transform.position.z); + + reviveBottomSpriteRenderer.gameObject.SetActive(true); + reviveBottomSpriteRenderer.DoAlpha(reviveBottomAlpha, 0.3f, reviveBottomSpawnDelay).SetUnscaledTime(true); + + GameController.AudioManager.PlaySound(DEATH_HASH); + + EasingManager.DoAfter(0.5f, () => + { + onPlayerDied?.Invoke(); + }).SetUnscaledTime(true); + + GameController.VibrationManager.StrongVibration(); + } else + { + if(Time.time - lastTimeVibrated > 0.05f) + { + GameController.VibrationManager.LightVibration(); + lastTimeVibrated = Time.time; + } + + GameController.AudioManager.PlaySound(RECEIVING_DAMAGE_HASH); + } + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Player/PlayerBehavior.cs.meta b/Assets/Common/Scripts/Player/PlayerBehavior.cs.meta new file mode 100644 index 0000000..f068926 --- /dev/null +++ b/Assets/Common/Scripts/Player/PlayerBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 51eef25c37b06734992070a2ed6b575c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Player/PlayerEnemyCollisionHelper.cs b/Assets/Common/Scripts/Player/PlayerEnemyCollisionHelper.cs new file mode 100644 index 0000000..5d3fc5e --- /dev/null +++ b/Assets/Common/Scripts/Player/PlayerEnemyCollisionHelper.cs @@ -0,0 +1,17 @@ +using UnityEngine; + +namespace OctoberStudio +{ + public class PlayerEnemyCollisionHelper : MonoBehaviour + { + protected virtual void OnTriggerEnter2D(Collider2D collision) + { + PlayerBehavior.Player.CheckTriggerEnter2D(collision); + } + + protected virtual void OnTriggerExit2D(Collider2D collision) + { + PlayerBehavior.Player.CheckTriggerExit2D(collision); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Player/PlayerEnemyCollisionHelper.cs.meta b/Assets/Common/Scripts/Player/PlayerEnemyCollisionHelper.cs.meta new file mode 100644 index 0000000..b642c6f --- /dev/null +++ b/Assets/Common/Scripts/Player/PlayerEnemyCollisionHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4649c6ea49826a84eb36bc7de37dc40c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Player/ProjectileBehavior.cs b/Assets/Common/Scripts/Player/ProjectileBehavior.cs new file mode 100644 index 0000000..62cae6f --- /dev/null +++ b/Assets/Common/Scripts/Player/ProjectileBehavior.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio +{ + public class ProjectileBehavior : MonoBehaviour + { + public List Effects { get; private set; } + + public float DamageMultiplier { get; set; } + public bool KickBack { get; set; } + + public virtual void Init() + { + Effects = new List(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Player/ProjectileBehavior.cs.meta b/Assets/Common/Scripts/Player/ProjectileBehavior.cs.meta new file mode 100644 index 0000000..b0a5e5b --- /dev/null +++ b/Assets/Common/Scripts/Player/ProjectileBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 436da3aee32368148a42bfbc919e9016 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Player/SimplePlayerProjectileBehavior.cs b/Assets/Common/Scripts/Player/SimplePlayerProjectileBehavior.cs new file mode 100644 index 0000000..3782c8b --- /dev/null +++ b/Assets/Common/Scripts/Player/SimplePlayerProjectileBehavior.cs @@ -0,0 +1,104 @@ +using OctoberStudio.Easing; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio +{ + public class SimplePlayerProjectileBehavior : ProjectileBehavior + { + [SerializeField] protected float speed; + [SerializeField] protected SpriteRenderer spriteRenderer; + [SerializeField] protected TrailRenderer trail; + [SerializeField] protected float lifetime = -1; + [SerializeField] protected Transform rotatingPart; + [SerializeField] protected bool selfDestructOnHit = true; + [SerializeField] protected List particles; + + protected Vector3 direction; + protected float spawnTime; + + public float Speed { get; set; } + public float LifeTime { get; set; } + + protected IEasingCoroutine scaleCoroutine; + + public UnityAction onFinished; + + public virtual void Init(Vector2 position, Vector2 direction) + { + Init(); + + transform.position = position; + transform.localScale = Vector3.one * PlayerBehavior.Player.SizeMultiplier; + this.direction = direction; + + for (int i = 0; i < particles.Count; i++) + { + particles[i].Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); + particles[i].Clear(); + particles[i].Play(); + } + + if (rotatingPart != null) rotatingPart.rotation = Quaternion.FromToRotation(Vector2.up, direction); + + Speed = speed * PlayerBehavior.Player.ProjectileSpeedMultiplier; + + spawnTime = Time.time; + + LifeTime = lifetime * PlayerBehavior.Player.DurationMultiplier; + + if (trail != null) trail.Clear(); + } + + protected virtual void Update() + { + if (spriteRenderer != null && !spriteRenderer.isVisible) Clear(); + + transform.position += direction * Time.deltaTime * Speed; + + if (LifeTime > 0) + { + if(Time.time - spawnTime > LifeTime) + { + Clear(); + + onFinished?.Invoke(this); + } + } + } + + public virtual IEasingCoroutine ScaleRotatingPart(Vector3 initialScale, Vector3 targetScale) + { + if (rotatingPart == null) return null; + + rotatingPart.localScale = initialScale; + + scaleCoroutine = rotatingPart.DoLocalScale(targetScale, 0.25f); + + return scaleCoroutine; + } + + public virtual void Clear() + { + for (int i = 0; i < particles.Count; i++) + { + particles[i].Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); + particles[i].Clear(); + } + + scaleCoroutine.StopIfExists(); + gameObject.SetActive(false); + } + + protected virtual void OnTriggerEnter2D(Collider2D collision) + { + if (selfDestructOnHit) + { + Clear(); + + onFinished?.Invoke(this); + } + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Player/SimplePlayerProjectileBehavior.cs.meta b/Assets/Common/Scripts/Player/SimplePlayerProjectileBehavior.cs.meta new file mode 100644 index 0000000..18606c1 --- /dev/null +++ b/Assets/Common/Scripts/Player/SimplePlayerProjectileBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ad779c037e598e44cbce32fbcd01580c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/ProjectSettings.cs b/Assets/Common/Scripts/ProjectSettings.cs new file mode 100644 index 0000000..c69784b --- /dev/null +++ b/Assets/Common/Scripts/ProjectSettings.cs @@ -0,0 +1,34 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio +{ + [CreateAssetMenu(fileName = "ProjectSettings", menuName = "October/Project Settings", order = 1)] + public class ProjectSettings : ScriptableObject + { + [SerializeField] protected string mainMenuSceneName = "Main Menu"; + public string MainMenuSceneName => mainMenuSceneName; + + [SerializeField] protected string gameSceneName = "Game"; + public string GameSceneName => gameSceneName; + + [SerializeField] protected string loadingSceneName = "Loading Screen"; + public string LoadingSceneName => loadingSceneName; + + protected void OnValidate() + { +#if UNITY_EDITOR + UnityEditor.EditorUtility.SetDirty(this); // Mark asset dirty for saving + + // Dynamically call editor-only method + var editorType = System.Type.GetType("OctoberStudio.DefaultSceneLoader, Assembly-CSharp-Editor"); + if (editorType != null) + { + var method = editorType.GetMethod("OnProjectSettingsChanged", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic); + method?.Invoke(null, new object[] {}); + } +#endif + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/ProjectSettings.cs.meta b/Assets/Common/Scripts/ProjectSettings.cs.meta new file mode 100644 index 0000000..413ff4c --- /dev/null +++ b/Assets/Common/Scripts/ProjectSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eba65de5fd9069241aafb2d7d75b5f44 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Rendering.meta b/Assets/Common/Scripts/Rendering.meta new file mode 100644 index 0000000..65a213b --- /dev/null +++ b/Assets/Common/Scripts/Rendering.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: febff280048dd1f42a87fb623e2b4b20 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Rendering/RendererAdapter.cs b/Assets/Common/Scripts/Rendering/RendererAdapter.cs new file mode 100644 index 0000000..38bb28e --- /dev/null +++ b/Assets/Common/Scripts/Rendering/RendererAdapter.cs @@ -0,0 +1,253 @@ +using UnityEngine; + +namespace OctoberStudio.Rendering +{ + /// + /// 渲染器模式:Sprite (2D) 或 Mesh (3D) + /// + public enum RendererMode + { + Sprite = 0, + Mesh = 1, + } + + /// + /// 统一渲染适配器。 + /// 让 OctoberStudio 的业务逻辑无需关心使用 还是 。 + /// 在 Prefab 上挂载此组件,选择 Mode,勾选 Auto Fetch 即可让组件自动绑定子级 Renderer。 + /// + /// 典型用法: + /// 2D Prefab → Mode=Sprite,自动找 SpriteRenderer,行为与原版完全一致 + /// 3D Prefab → Mode=Mesh,自动找 MeshRenderer,所有 Color/Flip/Sorting 操作映射到 Mesh 上 + /// + /// 业务代码统一通过适配器属性 (Color/FlipX/SortingOrder/...) 操作, + /// 切换 2D/3D 时无需重写逻辑层。 + /// + [DisallowMultipleComponent] + [ExecuteAlways] + [AddComponentMenu("OctoberStudio/Rendering/Renderer Adapter")] + public class RendererAdapter : MonoBehaviour + { + [Tooltip("渲染模式:Sprite=2D 模式 (默认), Mesh=3D 模式")] + [SerializeField] private RendererMode mode = RendererMode.Sprite; + + [Tooltip("启用后会在 OnValidate / Reset 自动查找并绑定子级 Renderer 组件")] + [SerializeField] private bool autoFetch = true; + + [Tooltip("自动查找时的搜索根 (留空 = 自己)")] + [SerializeField] private Transform fetchRoot; + + [Tooltip("是否在 mode 切换时自动启用/禁用对应的 Renderer (推荐勾选避免两个同时显示)")] + [SerializeField] private bool applyEnabledOnModeChange = true; + + [Header("Bound Renderers (可手动指定,否则自动 fetch)")] + [SerializeField] private SpriteRenderer spriteRenderer; + [SerializeField] private MeshRenderer meshRenderer; + + #region Public Read-only + + public RendererMode Mode => mode; + public bool IsSpriteMode => mode == RendererMode.Sprite; + public bool IsMeshMode => mode == RendererMode.Mesh; + public SpriteRenderer Sprite => spriteRenderer; + public MeshRenderer Mesh => meshRenderer; + + /// + /// 当前激活的 Renderer (Sprite 模式返回 SpriteRenderer,Mesh 模式返回 MeshRenderer) + /// + public Renderer Active => mode == RendererMode.Sprite ? (Renderer)spriteRenderer : meshRenderer; + + #endregion + + #region Unified API + + public bool IsVisible => Active != null && Active.isVisible; + + public Bounds Bounds => Active != null + ? Active.bounds + : new Bounds(transform.position, Vector3.zero); + + public bool Enabled + { + get => Active != null && Active.enabled; + set { if (Active != null) Active.enabled = value; } + } + + public Color Color + { + get + { + if (mode == RendererMode.Sprite) return spriteRenderer != null ? spriteRenderer.color : Color.white; + return meshRenderer != null && meshRenderer.sharedMaterial != null && meshRenderer.sharedMaterial.HasProperty(MainColorPropID) + ? meshRenderer.material.GetColor(MainColorPropID) + : Color.white; + } + set + { + if (mode == RendererMode.Sprite) + { + if (spriteRenderer != null) spriteRenderer.color = value; + } + else + { + if (meshRenderer != null && meshRenderer.material != null && meshRenderer.material.HasProperty(MainColorPropID)) + meshRenderer.material.SetColor(MainColorPropID, value); + } + } + } + + public float Alpha + { + get => Color.a; + set { var c = Color; c.a = value; Color = c; } + } + + /// + /// 水平翻转。 + /// Sprite 模式:spriteRenderer.flipX + /// Mesh 模式:transform.localScale.x 符号 + /// + public bool FlipX + { + get + { + if (mode == RendererMode.Sprite) return spriteRenderer != null && spriteRenderer.flipX; + return transform.localScale.x < 0; + } + set + { + if (mode == RendererMode.Sprite) + { + if (spriteRenderer != null) spriteRenderer.flipX = value; + } + else + { + var s = transform.localScale; + s.x = Mathf.Abs(s.x) * (value ? -1f : 1f); + transform.localScale = s; + } + } + } + + public bool FlipY + { + get + { + if (mode == RendererMode.Sprite) return spriteRenderer != null && spriteRenderer.flipY; + return transform.localScale.y < 0; + } + set + { + if (mode == RendererMode.Sprite) + { + if (spriteRenderer != null) spriteRenderer.flipY = value; + } + else + { + var s = transform.localScale; + s.y = Mathf.Abs(s.y) * (value ? -1f : 1f); + transform.localScale = s; + } + } + } + + public int SortingOrder + { + get => Active != null ? Active.sortingOrder : 0; + set { if (Active != null) Active.sortingOrder = value; } + } + + public string SortingLayerName + { + get => Active != null ? Active.sortingLayerName : "Default"; + set { if (Active != null) Active.sortingLayerName = value; } + } + + public int SortingLayerID + { + get => Active != null ? Active.sortingLayerID : 0; + set { if (Active != null) Active.sortingLayerID = value; } + } + + public Material Material + { + get => Active != null ? Active.material : null; + set { if (Active != null) Active.material = value; } + } + + public Material SharedMaterial + { + get => Active != null ? Active.sharedMaterial : null; + set { if (Active != null) Active.sharedMaterial = value; } + } + + #endregion + + #region Lifecycle + + private static readonly int MainColorPropID = Shader.PropertyToID("_Color"); + + private void Reset() + { + FetchComponents(); + ApplyMode(); + } + + private void OnValidate() + { + if (autoFetch) FetchComponents(); + if (applyEnabledOnModeChange) ApplyMode(); + } + + private void Awake() + { + if (autoFetch) FetchComponents(); + if (applyEnabledOnModeChange) ApplyMode(); + } + + #endregion + + #region Public Operations + + /// + /// 在子级中查找并绑定对应类型的 Renderer (优先用根节点上的,再退到子级)。 + /// + [ContextMenu("Fetch Renderer Components")] + public void FetchComponents() + { + var root = fetchRoot != null ? fetchRoot : transform; + if (spriteRenderer == null) + { + spriteRenderer = root.GetComponent(); + if (spriteRenderer == null) spriteRenderer = root.GetComponentInChildren(true); + } + if (meshRenderer == null) + { + meshRenderer = root.GetComponent(); + if (meshRenderer == null) meshRenderer = root.GetComponentInChildren(true); + } + } + + /// + /// 根据当前 mode 启用/禁用对应 Renderer (避免两个同时显示)。 + /// + [ContextMenu("Apply Mode")] + public void ApplyMode() + { + if (spriteRenderer != null) spriteRenderer.enabled = (mode == RendererMode.Sprite); + if (meshRenderer != null) meshRenderer.enabled = (mode == RendererMode.Mesh); + } + + /// + /// 运行时切换 mode (推荐通过这个方法切换,避免直接改 Inspector 字段不生效)。 + /// + public void SetMode(RendererMode newMode) + { + if (mode == newMode) return; + mode = newMode; + if (applyEnabledOnModeChange) ApplyMode(); + } + + #endregion + } +} diff --git a/Assets/Common/Scripts/Rendering/RendererAdapter.cs.meta b/Assets/Common/Scripts/Rendering/RendererAdapter.cs.meta new file mode 100644 index 0000000..433fc45 --- /dev/null +++ b/Assets/Common/Scripts/Rendering/RendererAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0f1f789d167f51c4faff9630afc68d4c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Rendering/RendererAdapterExtensions.cs b/Assets/Common/Scripts/Rendering/RendererAdapterExtensions.cs new file mode 100644 index 0000000..daa77ff --- /dev/null +++ b/Assets/Common/Scripts/Rendering/RendererAdapterExtensions.cs @@ -0,0 +1,34 @@ +using OctoberStudio.Easing; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace OctoberStudio.Rendering +{ + /// + /// RendererAdapter 的便捷扩展方法。 + /// 与 对齐,方便逻辑层平滑迁移。 + /// + public static class RendererAdapterExtensions + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RendererAdapter SetAlpha(this RendererAdapter adapter, float alpha) + { + if (adapter != null) adapter.Alpha = alpha; + return adapter; + } + + public static IEasingCoroutine DoAlpha(this RendererAdapter adapter, float targetAlpha, float duration, float delay = 0) + { + if (adapter == null) return null; + var initial = adapter.Alpha; + return new FloatEasingCoroutine(initial, targetAlpha, duration, delay, a => adapter.Alpha = a); + } + + public static IEasingCoroutine DoColor(this RendererAdapter adapter, Color targetColor, float duration, float delay = 0) + { + if (adapter == null) return null; + var initial = adapter.Color; + return new ColorEasingCoroutine(initial, targetColor, duration, delay, c => adapter.Color = c); + } + } +} diff --git a/Assets/Common/Scripts/Rendering/RendererAdapterExtensions.cs.meta b/Assets/Common/Scripts/Rendering/RendererAdapterExtensions.cs.meta new file mode 100644 index 0000000..ad09c54 --- /dev/null +++ b/Assets/Common/Scripts/Rendering/RendererAdapterExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a178dde5f3e93c44d8888efc2df0b9bd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Stage.meta b/Assets/Common/Scripts/Stage.meta new file mode 100644 index 0000000..b81f3d4 --- /dev/null +++ b/Assets/Common/Scripts/Stage.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 89b99d134d74c124ea226a18f88095c0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Stage/CameraManager.cs b/Assets/Common/Scripts/Stage/CameraManager.cs new file mode 100644 index 0000000..4c035bb --- /dev/null +++ b/Assets/Common/Scripts/Stage/CameraManager.cs @@ -0,0 +1,104 @@ +using UnityEngine; + +namespace OctoberStudio +{ + public class CameraManager : MonoBehaviour + { + private static CameraManager instance; + + [SerializeField] Transform target; + [SerializeField] SpriteRenderer spotlightRenderer; + [SerializeField] SpriteRenderer spotlightShadowRenderer; + + private Vector3 offset; + private Camera mainCamera; + + public static float HalfHeight => instance.mainCamera.orthographicSize; + public static float HalfWidth => instance.mainCamera.orthographicSize * instance.mainCamera.aspect; + + public static Vector2 Position => instance.transform.position; + + public static float LeftBound => Position.x - HalfWidth; + public static float RightBound => Position.x + HalfWidth; + public static float TopBound => Position.y + HalfHeight; + public static float BottomBound => Position.y - HalfHeight; + + private void Awake() + { + instance = this; + + mainCamera = GetComponent(); + + offset = transform.position - target.position; + spotlightShadowRenderer.size = new Vector2(HalfWidth, HalfHeight) * 2; + } + + public void Init(StageData stageData) + { + spotlightRenderer.color = stageData.SpotlightColor; + spotlightShadowRenderer.color = stageData.SpotlightShadowColor; + } + + private void LateUpdate() + { + transform.position = target.position + offset; + } + + public void SetSize(float size) + { + mainCamera.orthographicSize = size; + spotlightShadowRenderer.size = new Vector2(HalfWidth, HalfHeight) * 2; + } + + public static bool IsPointOutsideCameraRight(Vector2 point) + { + return point.x > RightBound; + } + + public static bool IsPointOutsideCameraRight(Vector2 point, out float distance) + { + bool result = point.x > RightBound; + distance = result ? point.x - RightBound : 0; + return result; + } + + public static bool IsPointOutsideCameraLeft(Vector2 point, out float distance) + { + bool result = point.x < LeftBound; + distance = result ? LeftBound - point.x : 0; + return result; + } + + public static bool IsPointOutsideCameraBottom(Vector2 point, out float distance) + { + bool result = point.y < BottomBound; + distance = result ? BottomBound - point.y : 0; + return result; + } + + public static bool IsPointOutsideCameraTop(Vector2 point, out float distance) + { + bool result = point.y > TopBound; + distance = result ? point.y - TopBound : 0; + return result; + } + + public static Vector2 GetPointInsideCamera(float padding = 0) + { + return new Vector2(Random.Range(LeftBound + padding, RightBound - padding), Random.Range(BottomBound + padding, TopBound - padding)); + } + + public static Vector2 GetRandomPointOutsideCamera(float padding = 0) + { + if(Random.value > instance.mainCamera.aspect / (instance.mainCamera.aspect + 1)) + { + float x = Random.value > 0.5f ? LeftBound - padding : RightBound + padding; + return new Vector2(x, Random.Range(BottomBound - padding, TopBound + padding)); + } else + { + float y = Random.value > 0.5f ? TopBound + padding : BottomBound - padding; + return new Vector2(Random.Range(LeftBound - padding, RightBound + padding), y); + } + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Stage/CameraManager.cs.meta b/Assets/Common/Scripts/Stage/CameraManager.cs.meta new file mode 100644 index 0000000..ce487b0 --- /dev/null +++ b/Assets/Common/Scripts/Stage/CameraManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 473cf2ab43c5a6049a3a9ce5642330d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Stage/PresetData.cs b/Assets/Common/Scripts/Stage/PresetData.cs new file mode 100644 index 0000000..b809605 --- /dev/null +++ b/Assets/Common/Scripts/Stage/PresetData.cs @@ -0,0 +1,19 @@ +using OctoberStudio.Abilities; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio +{ + [CreateAssetMenu(menuName = "October/Testing/Preset", fileName = "Testing Preset")] + public class PresetData : ScriptableObject + { + [SerializeField] float startTime; + public float StartTime => startTime; + + [SerializeField] int xpLevel; + public int XPLevel => xpLevel; + + [SerializeField] List abilities; + public List Abilities => abilities; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Stage/PresetData.cs.meta b/Assets/Common/Scripts/Stage/PresetData.cs.meta new file mode 100644 index 0000000..4e3ff82 --- /dev/null +++ b/Assets/Common/Scripts/Stage/PresetData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ef6ba5f06fb1f254485408470b14b310 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Stage/PropBehavior.cs b/Assets/Common/Scripts/Stage/PropBehavior.cs new file mode 100644 index 0000000..e41c5bd --- /dev/null +++ b/Assets/Common/Scripts/Stage/PropBehavior.cs @@ -0,0 +1,39 @@ +using OctoberStudio.Easing; +using OctoberStudio.Enemy; +using UnityEngine; + +namespace OctoberStudio +{ + public class PropBehavior : MonoBehaviour + { + protected static readonly int _Overlay = Shader.PropertyToID("_Overlay"); + protected static readonly int _Disolve = Shader.PropertyToID("_Disolve"); + + [SerializeField] SpriteRenderer spriteRenderer; + [SerializeField] DissolveSettings dissolveSettings; + + private Material sharedMaterial; + private Material effectsMaterial; + + protected virtual void Awake() + { + sharedMaterial = spriteRenderer.sharedMaterial; + effectsMaterial = Instantiate(sharedMaterial); + } + + public void Dissolve() + { + spriteRenderer.material = effectsMaterial; + + effectsMaterial.SetFloat(_Disolve, 0); + effectsMaterial.DoFloat(_Disolve, 1, dissolveSettings.Duration + 0.02f).SetEasingCurve(dissolveSettings.DissolveCurve).SetOnFinish(() => + { + effectsMaterial.SetColor(_Overlay, Color.clear); + effectsMaterial.SetFloat(_Disolve, 0); + + gameObject.SetActive(false); + spriteRenderer.material = sharedMaterial; + }); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Stage/PropBehavior.cs.meta b/Assets/Common/Scripts/Stage/PropBehavior.cs.meta new file mode 100644 index 0000000..90624ea --- /dev/null +++ b/Assets/Common/Scripts/Stage/PropBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 309d08e58721e8242b20702aaf5c6808 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Stage/Stage Field.meta b/Assets/Common/Scripts/Stage/Stage Field.meta new file mode 100644 index 0000000..6dc0027 --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ed99587137a846941aa427096484236e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Stage/Stage Field/AbstractFieldBehavior.cs b/Assets/Common/Scripts/Stage/Stage Field/AbstractFieldBehavior.cs new file mode 100644 index 0000000..742a030 --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field/AbstractFieldBehavior.cs @@ -0,0 +1,68 @@ +using OctoberStudio.Pool; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio +{ + public abstract class AbstractFieldBehavior : IFieldBehavior + { + public StageFieldData Data { get; private set; } + + private bool spawnProp; + + public abstract void Clear(); + public abstract Vector2 GetBossSpawnPosition(BossFenceBehavior fence, Vector2 offset); + public abstract Vector2 GetRandomPositionOnBorder(); + public abstract bool IsPointOutsideBottom(Vector2 point, out float distance); + public abstract bool IsPointOutsideLeft(Vector2 point, out float distance); + public abstract bool IsPointOutsideRight(Vector2 point, out float distance); + public abstract bool IsPointOutsideTop(Vector2 point, out float distance); + public abstract void Update(); + public abstract bool ValidatePosition(Vector2 position); + public abstract void RemovePropFromBossFence(BossFenceBehavior fence); + public abstract Vector2 GetIntersectionPoint(Vector2 start, Vector2 end, float offset); + + private List> propPools = new List>(); + + public virtual void Init(StageFieldData stageFieldData, bool spawnProp) + { + Data = stageFieldData; + + this.spawnProp = spawnProp; + + if (!spawnProp) return; + + for (int i = 0; i < stageFieldData.PropChances.Count; i++) + { + var propData = stageFieldData.PropChances[i]; + var pool = new PoolComponent(propData.Prefab, propData.MaxAmount * 9); + + propPools.Add(pool); + } + } + + protected void SpawnProp(StageChunkBehavior chunk) + { + if (!spawnProp) return; + + for (int i = 0; i < Data.PropChances.Count; i++) + { + var propData = Data.PropChances[i]; + + if(Random.value * 100 < propData.Chance) + { + int amount = Mathf.RoundToInt(Mathf.Lerp(1, propData.MaxAmount, Random.value)); + + var pool = propPools[i]; + for (int j = 0; j < amount; j++) + { + var prop = pool.GetEntity(); + + chunk.AddProp(prop); + } + } + } + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Stage/Stage Field/AbstractFieldBehavior.cs.meta b/Assets/Common/Scripts/Stage/Stage Field/AbstractFieldBehavior.cs.meta new file mode 100644 index 0000000..6751608 --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field/AbstractFieldBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 13373ccf544ebd34f99a15f28c2010a7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Stage/Stage Field/EndlessFieldBehavior.cs b/Assets/Common/Scripts/Stage/Stage Field/EndlessFieldBehavior.cs new file mode 100644 index 0000000..0abfd1f --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field/EndlessFieldBehavior.cs @@ -0,0 +1,353 @@ +using OctoberStudio.Easing; +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio +{ + public class EndlessFieldBehavior : AbstractFieldBehavior + { + protected List> pools; + + protected List> chunks = new List>(); + + protected bool wait = false; + + public override void Init(StageFieldData stageFieldData, bool spawnProp) + { + base.Init(stageFieldData, spawnProp); + + pools = new List>(); + foreach (var background in stageFieldData.GetBackgroundPrefabs()) + { + var pool = new PoolComponent(background, 6); + pools.Add(pool); + } + + var row = new List(); + var chunk = pools.Random().GetEntity(); + + chunk.transform.position = Vector3.zero; + chunk.transform.rotation = Quaternion.identity; + chunk.transform.localScale = Vector3.one; + + row.Add(chunk); + chunks.Add(row); + + wait = false; + EasingManager.DoNextFrame().SetOnFinish(() => wait = true); + } + + public override void Update() + { + if (!wait) return; + + RemoveInvisibleChunks(); + CheckForNewChunks(); + } + + #region Add New Chunks + + protected virtual void CheckForNewChunks() + { + CheckForEmptyField(); + TryAddTopRow(); + TryAddBottomRow(); + TryAddLeftColumn(); + TryAddRightColumn(); + } + + protected virtual void TryAddTopRow() + { + if (chunks[0][0].HasEmptyTop) + { + var newTopRow = new List(); + + var columnCounts = chunks[0].Count; + + for (int i = 0; i < columnCounts; i++) + { + var chunk = pools.Random().GetEntity(); + var chunkBellow = chunks[0][i]; + + chunk.transform.position = chunkBellow.transform.position + Vector3.up * chunk.Size.y; + chunk.transform.rotation = Quaternion.identity; + chunk.transform.localScale = Vector3.one; + + SpawnProp(chunk); + + newTopRow.Add(chunk); + } + + chunks.Insert(0, newTopRow); + } + } + + protected virtual void TryAddBottomRow() + { + if (chunks[^1][^1].HasEmptyBottom) + { + var newBottomRow = new List(); + + var columnCounts = chunks[0].Count; + + for (int i = 0; i < columnCounts; i++) + { + var chunk = pools.Random().GetEntity(); + var chunkOnTop = chunks[^1][i]; + + chunk.transform.position = chunkOnTop.transform.position + Vector3.down * chunk.Size.y; + chunk.transform.rotation = Quaternion.identity; + chunk.transform.localScale = Vector3.one; + + SpawnProp(chunk); + + newBottomRow.Add(chunk); + } + + chunks.Add(newBottomRow); + } + } + + protected virtual void TryAddLeftColumn() + { + if (chunks[0][0].HasEmptyLeft) + { + for(int i = 0; i < chunks.Count; i++) + { + var row = chunks[i]; + + var chunk = pools.Random().GetEntity(); + var chunkOnRight = chunks[i][0]; + + chunk.transform.position = chunkOnRight.transform.position + Vector3.left * chunk.Size.x; + chunk.transform.rotation = Quaternion.identity; + chunk.transform.localScale = Vector3.one; + + SpawnProp(chunk); + + row.Insert(0, chunk); + } + } + } + + protected virtual void TryAddRightColumn() + { + if (chunks[^1][^1].HasEmptyRight) + { + for (int i = 0; i < chunks.Count; i++) + { + var row = chunks[i]; + + var chunk = pools.Random().GetEntity(); + var chunkOnLeft = chunks[i][^1]; + + chunk.transform.position = chunkOnLeft.transform.position + Vector3.right * chunk.Size.x; + chunk.transform.rotation = Quaternion.identity; + chunk.transform.localScale = Vector3.one; + + SpawnProp(chunk); + + row.Add(chunk); + } + } + } + + #endregion + + #region Remove Invisible Chunks + + protected virtual void RemoveInvisibleChunks() + { + if (chunks.Count == 0) return; + + CheckTopRow(); + CheckForEmptyField(); + CheckLeftColumn(); + CheckForEmptyField(); + CheckRightColumn(); + CheckForEmptyField(); + CheckBottomRow(); + CheckForEmptyField(); + } + + protected virtual void CheckForEmptyField() + { + if(chunks.Count > 0) + { + if (chunks[0].Count > 0) return; + } + + chunks.Clear(); + + var row = new List(); + var chunk = pools.Random().GetEntity(); + + chunk.transform.position = PlayerBehavior.Player.transform.position.SetZ(0); + chunk.transform.rotation = Quaternion.identity; + chunk.transform.localScale = Vector3.one; + + row.Add(chunk); + chunks.Add(row); + } + + protected virtual void CheckTopRow() + { + if (!chunks[0][0].IsVisible) + { + if (!chunks[0][^1].IsVisible) + { + RemoveTopRow(); + } + } + } + + protected virtual void CheckLeftColumn() + { + if (!chunks[0][0].IsVisible) + { + if (!chunks[^1][0].IsVisible) + { + RemoveLeftColumn(); + } + } + } + + protected virtual void CheckRightColumn() + { + if (!chunks[^1][^1].IsVisible) + { + if (!chunks[0][^1].IsVisible) + { + RemoveRightColumn(); + } + } + } + + protected virtual void CheckBottomRow() + { + if (!chunks[^1][^1].IsVisible) + { + if (!chunks[^1][0].IsVisible) + { + RemoveBottomRow(); + } + } + } + + protected virtual void RemoveTopRow() + { + var topRow = chunks[0]; + + for (int i = 0; i < topRow.Count; i++) + { + var chunk = topRow[i]; + + chunk.Clear(); + } + + topRow.Clear(); + chunks.RemoveAt(0); + } + + protected virtual void RemoveLeftColumn() + { + for (int i = 0; i < chunks.Count; i++) + { + var row = chunks[i]; + + row[0].Clear(); + row.RemoveAt(0); + } + } + + protected virtual void RemoveRightColumn() + { + for (int i = 0; i < chunks.Count; i++) + { + var row = chunks[i]; + + row[^1].Clear(); + row.RemoveAt(row.Count - 1); + } + } + + protected virtual void RemoveBottomRow() + { + var bottomRow = chunks[^1]; + + for (int i = 0; i < bottomRow.Count; i++) + { + var chunk = bottomRow[i]; + + chunk.Clear(); + } + + bottomRow.Clear(); + chunks.RemoveAt(chunks.Count - 1); + } + + #endregion + + public override bool ValidatePosition(Vector2 position) => true; + + public override Vector2 GetRandomPositionOnBorder() => Vector2.zero; + + public override Vector2 GetBossSpawnPosition(BossFenceBehavior fence, Vector2 offset) + { + var playerPosition = PlayerBehavior.Player.transform.position.XY(); + return playerPosition + offset; + } + + public override bool IsPointOutsideRight(Vector2 point, out float distance) + { + distance = 0; + return false; + } + + public override bool IsPointOutsideLeft(Vector2 point, out float distance) + { + distance = 0; + return false; + } + + public override bool IsPointOutsideTop(Vector2 point, out float distance) + { + distance = 0; + return false; + } + + public override bool IsPointOutsideBottom(Vector2 point, out float distance) + { + distance = 0; + return false; + } + + public override Vector2 GetIntersectionPoint(Vector2 start, Vector2 end, float offset) + { + return end; + } + + public override void RemovePropFromBossFence(BossFenceBehavior fence) + { + for (int i = 0; i < chunks.Count; i++) + { + for(int j = 0; j < chunks[i].Count; j++) + { + chunks[i][j].RemovePropFromBossFence(fence); + } + } + } + + public override void Clear() + { + for(int i = 0; i < pools.Count; i++) + { + pools[i].Destroy(); + } + + pools.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Stage/Stage Field/EndlessFieldBehavior.cs.meta b/Assets/Common/Scripts/Stage/Stage Field/EndlessFieldBehavior.cs.meta new file mode 100644 index 0000000..a762387 --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field/EndlessFieldBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3123f67e1cbf86944a2e70d658281afa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Stage/Stage Field/HorizontalFieldBehavior.cs b/Assets/Common/Scripts/Stage/Stage Field/HorizontalFieldBehavior.cs new file mode 100644 index 0000000..cb0cbc7 --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field/HorizontalFieldBehavior.cs @@ -0,0 +1,304 @@ +using OctoberStudio.Easing; +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio +{ + public class HorizontalFieldBehavior : AbstractFieldBehavior + { + protected List> backgroundPools; + protected PoolComponent topPool; + protected PoolComponent bottomPool; + + protected List chunks = new List(); + + protected bool wait = false; + + public override void Init(StageFieldData stageFieldData, bool spawnProp) + { + base.Init(stageFieldData, spawnProp); + + backgroundPools = new List>(); + foreach (var background in stageFieldData.GetBackgroundPrefabs()) + { + var pool = new PoolComponent(background, 3); + backgroundPools.Add(pool); + } + + if (stageFieldData.LeftPrefab != null) + { + topPool = new PoolComponent("Field Top Border", stageFieldData.TopPrefab, 4); + } + + if (stageFieldData.RightPrefab != null) + { + bottomPool = new PoolComponent("Field Bottom Border", stageFieldData.BottomPrefab, 4); + } + + var chunk = backgroundPools.Random().GetEntity(); + + chunk.transform.position = Vector3.zero; + chunk.transform.rotation = Quaternion.identity; + chunk.transform.localScale = Vector3.one; + + AddBordersToChunk(chunk); + + chunks.Add(chunk); + + wait = false; + EasingManager.DoNextFrame().SetOnFinish(() => wait = true); + } + + public override void Update() + { + if (!wait) return; + + RemoveInvisibleChunks(); + CheckForNewChunks(); + } + + #region Add New Chunks + + protected virtual void CheckForNewChunks() + { + TryAddRightRow(); + TryAddLeftRow(); + } + + protected virtual void TryAddRightRow() + { + if (chunks[0].HasEmptyRight) + { + var chunk = backgroundPools.Random().GetEntity(); + var chunkBellow = chunks[0]; + + chunk.transform.position = chunkBellow.transform.position + Vector3.right * chunk.Size.y; + chunk.transform.rotation = Quaternion.identity; + chunk.transform.localScale = Vector3.one; + + AddBordersToChunk(chunk); + SpawnProp(chunk); + + chunks.Insert(0, chunk); + } + } + + protected virtual void TryAddLeftRow() + { + if (chunks[^1].HasEmptyLeft) + { + var chunk = backgroundPools.Random().GetEntity(); + var chunkOnTop = chunks[^1]; + + chunk.transform.position = chunkOnTop.transform.position + Vector3.left * chunk.Size.y; + chunk.transform.rotation = Quaternion.identity; + chunk.transform.localScale = Vector3.one; + + AddBordersToChunk(chunk); + SpawnProp(chunk); + + chunks.Add(chunk); + } + } + + protected virtual void AddBordersToChunk(StageChunkBehavior chunk) + { + if (topPool != null) + { + var topBorder = topPool.GetEntity(); + topBorder.transform.position = chunk.transform.position + Vector3.up * chunk.Size.y; + + chunk.AddBorder(topBorder); + } + + if (bottomPool != null) + { + var bottomBorder = bottomPool.GetEntity(); + bottomBorder.transform.position = chunk.transform.position + Vector3.down * chunk.Size.y; + + chunk.AddBorder(bottomBorder); + } + } + + #endregion + + #region Remove Invisible Chunks + + protected virtual void RemoveInvisibleChunks() + { + if (chunks.Count == 0) return; + + CheckRightRow(); + CheckLeftRow(); + } + + protected virtual void CheckRightRow() + { + if (!chunks[0].IsVisible) + { + RemoveRightRow(); + } + } + + protected virtual void CheckLeftRow() + { + if (!chunks[^1].IsVisible) + { + RemoveLeftRow(); + } + } + + protected virtual void RemoveRightRow() + { + chunks[0].Clear(); + chunks.RemoveAt(0); + } + + protected virtual void RemoveLeftRow() + { + chunks[^1].Clear(); + chunks.RemoveAt(chunks.Count - 1); + } + + #endregion + + + public override bool ValidatePosition(Vector2 position) + { + if (position.y > chunks[0].transform.position.y + chunks[0].Size.y / 2) return false; + if (position.y < chunks[0].transform.position.y - chunks[0].Size.y / 2) return false; + + return true; + } + + public override Vector2 GetIntersectionPoint(Vector2 start, Vector2 end, float offset) + { + var path = end - start; + var distance = path.magnitude; + + // start == end + if (distance < Mathf.Epsilon) return start; + + var direction = path.normalized; + + float ty1, ty2; + + // Create rectangle with offset + var rect = new Rect(chunks[0].LeftBound + offset, chunks[0].BottomBound + offset, (chunks[0].Size.x - offset) * 2, (chunks[0].Size.y - offset) * 2); + + // Y axis + if (Mathf.Abs(path.y) > Mathf.Epsilon) + { + // Calculate intersection points + ty1 = (rect.yMin - start.y) / path.y; + ty2 = (rect.yMax - start.y) / path.y; + + // Swapping if needed + if (ty1 > ty2) (ty1, ty2) = (ty2, ty1); + } + else + { + // No intersection + ty1 = float.NegativeInfinity; + ty2 = float.PositiveInfinity; + } + + var tEnter = ty1; + var tExit = ty2; + + // No intersection + if (tExit < 0f || tEnter > tExit) return start; + + return start + path * tExit; + } + + public override Vector2 GetBossSpawnPosition(BossFenceBehavior fence, Vector2 offset) + { + var playerPosition = PlayerBehavior.Player.transform.position.XY(); + + if (fence is CircleFenceBehavior circleFence) + { + if(circleFence.Radius < chunks[0].Size.y / 2f) + { + circleFence.SetRadiusOverride(chunks[0].Size.y / 2f * 1.1f); + } + + var positionWithOffset = new Vector2(playerPosition.x, offset.y); + if(Vector3.Distance(positionWithOffset, playerPosition) < circleFence.Radius) + { + return positionWithOffset; + } else + { + return new Vector2(playerPosition.x, 0); + } + } + else if(fence is RectFenceBehavior rectFence) + { + if(rectFence.Height < chunks[0].Size.y) + { + rectFence.SetSizeOverride(rectFence.Width, chunks[0].Size.x * 1.1f); + } + + return new Vector2(playerPosition.x, 0); + } + + return playerPosition + offset; + } + + public override Vector2 GetRandomPositionOnBorder() + { + float y = Random.Range(-chunks[0].Size.y / 2, chunks[0].Size.y / 2) + chunks[0].transform.position.y; + + float sign = Random.Range(0, 2) * 2 - 1; + float x = PlayerBehavior.Player.transform.position.x + CameraManager.HalfWidth * 1.05f * sign; + + return new Vector2(x, y); + } + + public override bool IsPointOutsideRight(Vector2 point, out float distance) + { + distance = 0; + return false; + } + + public override bool IsPointOutsideLeft(Vector2 point, out float distance) + { + distance = 0; + return false; + } + + public override bool IsPointOutsideTop(Vector2 point, out float distance) + { + bool result = point.y > chunks[0].TopBound; + distance = result ? point.y - chunks[0].TopBound : 0; + return result; + } + + public override bool IsPointOutsideBottom(Vector2 point, out float distance) + { + bool result = point.y < chunks[0].BottomBound; + distance = result ? chunks[0].BottomBound - point.y : 0; + return result; + } + + public override void RemovePropFromBossFence(BossFenceBehavior fence) + { + for(int i = 0; i < chunks.Count; i++) + { + chunks[i].RemovePropFromBossFence(fence); + } + } + + public override void Clear() + { + for (int i = 0; i < backgroundPools.Count; i++) + { + backgroundPools[i].Destroy(); + } + + backgroundPools.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Stage/Stage Field/HorizontalFieldBehavior.cs.meta b/Assets/Common/Scripts/Stage/Stage Field/HorizontalFieldBehavior.cs.meta new file mode 100644 index 0000000..a75e981 --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field/HorizontalFieldBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 82f325a2b53b2c84cb2a7e48f4f05f59 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Stage/Stage Field/IFieldBehavior.cs b/Assets/Common/Scripts/Stage/Stage Field/IFieldBehavior.cs new file mode 100644 index 0000000..717c24b --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field/IFieldBehavior.cs @@ -0,0 +1,25 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio +{ + public interface IFieldBehavior + { + void Init(StageFieldData stageFieldData, bool spawnProp); + void Update(); + void Clear(); + + bool ValidatePosition(Vector2 position); + Vector2 GetBossSpawnPosition(BossFenceBehavior fence, Vector2 offset); + Vector2 GetRandomPositionOnBorder(); + Vector2 GetIntersectionPoint(Vector2 start, Vector2 end, float offset); + + bool IsPointOutsideRight(Vector2 point, out float distance); + bool IsPointOutsideLeft(Vector2 point, out float distance); + bool IsPointOutsideTop(Vector2 point, out float distance); + bool IsPointOutsideBottom(Vector2 point, out float distance); + + void RemovePropFromBossFence(BossFenceBehavior fence); + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Stage/Stage Field/IFieldBehavior.cs.meta b/Assets/Common/Scripts/Stage/Stage Field/IFieldBehavior.cs.meta new file mode 100644 index 0000000..4bd19d3 --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field/IFieldBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 98e4cfaa5c232e449b999b5641f0aadd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Stage/Stage Field/RectFieldBehavior.cs b/Assets/Common/Scripts/Stage/Stage Field/RectFieldBehavior.cs new file mode 100644 index 0000000..ca0a4f3 --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field/RectFieldBehavior.cs @@ -0,0 +1,289 @@ +using OctoberStudio.Extensions; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio +{ + public class RectFieldBehavior : AbstractFieldBehavior + { + StageChunkBehavior chunk; + + List borders = new List(); + + public override void Init(StageFieldData stageFieldData, bool spawnProp) + { + base.Init(stageFieldData, spawnProp); + + chunk = Object.Instantiate(stageFieldData.GetBackgroundPrefabs().Random()).GetComponent(); + + chunk.transform.position = Vector3.zero; + chunk.transform.rotation = Quaternion.identity; + chunk.transform.localScale = Vector3.one; + + if (stageFieldData.TopPrefab != null) + { + var topBorder = Object.Instantiate(stageFieldData.TopPrefab).GetComponent(); + topBorder.transform.position = Vector3.up * chunk.Size.y; + borders.Add(topBorder); + } + + if (stageFieldData.BottomPrefab != null) + { + var bottomBorder = Object.Instantiate(stageFieldData.BottomPrefab).GetComponent(); + bottomBorder.transform.position = Vector3.down * chunk.Size.y; + borders.Add(bottomBorder); + } + + if (stageFieldData.LeftPrefab != null) + { + var leftBorder = Object.Instantiate(stageFieldData.LeftPrefab).GetComponent(); + leftBorder.transform.position = Vector3.left * chunk.Size.x; + borders.Add(leftBorder); + } + + if (stageFieldData.RightPrefab != null) + { + var rightBorder = Object.Instantiate(stageFieldData.RightPrefab).GetComponent(); + rightBorder.transform.position = Vector3.right * chunk.Size.x; + borders.Add(rightBorder); + } + + if (stageFieldData.TopLeftPrefab != null) + { + var topLeftCorner = Object.Instantiate(stageFieldData.TopLeftPrefab).GetComponent(); + topLeftCorner.transform.position = new Vector2(-chunk.Size.x, chunk.Size.y); + borders.Add(topLeftCorner); + } + + if (stageFieldData.TopRightPrefab != null) + { + var topRightCorner = Object.Instantiate(stageFieldData.TopRightPrefab).GetComponent(); + topRightCorner.transform.position = new Vector2(chunk.Size.x, chunk.Size.y); + borders.Add(topRightCorner); + } + + if (stageFieldData.BottomLeftPrefab != null) + { + var bottomLeftCorner = Object.Instantiate(stageFieldData.BottomLeftPrefab).GetComponent(); + bottomLeftCorner.transform.position = new Vector2(-chunk.Size.x, -chunk.Size.y); + borders.Add(bottomLeftCorner); + } + + if (stageFieldData.BottomRightPrefab != null) + { + var bottomRightCorner = Object.Instantiate(stageFieldData.BottomRightPrefab).GetComponent(); + bottomRightCorner.transform.position = new Vector2(chunk.Size.x, -chunk.Size.y); + borders.Add(bottomRightCorner); + } + + SpawnProp(chunk); + } + + public override void Update() + { + + } + + public override bool ValidatePosition(Vector2 position) + { + if (position.x > chunk.transform.position.x + chunk.Size.x / 2) return false; + if (position.x < chunk.transform.position.x - chunk.Size.x / 2) return false; + + if (position.y > chunk.transform.position.y + chunk.Size.y / 2) return false; + if (position.y < chunk.transform.position.y - chunk.Size.y / 2) return false; + + return true; + } + + public override Vector2 GetRandomPositionOnBorder() + { + Vector2 randomPoint = Random.insideUnitCircle.normalized * Mathf.Max(chunk.Size.x, chunk.Size.y); + + if (randomPoint.x > chunk.Size.x / 2) randomPoint.x = chunk.Size.x / 2; + if (randomPoint.x < -chunk.Size.x / 2) randomPoint.x = -chunk.Size.x / 2; + + if (randomPoint.y > chunk.Size.y / 2) randomPoint.y = chunk.Size.y / 2; + if (randomPoint.y < -chunk.Size.y / 2) randomPoint.y = -chunk.Size.y / 2; + + return randomPoint + chunk.transform.position.XY(); + } + + public override Vector2 GetBossSpawnPosition(BossFenceBehavior fence, Vector2 offset) + { + var playerPosition = PlayerBehavior.Player.transform.position.XY(); + var desiredPosition = playerPosition + offset; + + if (fence is CircleFenceBehavior circleFence) + { + bool tooCloseToLeftBorder = desiredPosition.x - circleFence.Radius < -chunk.Size.x / 2; + bool tooCloseToRightBorder = desiredPosition.x + circleFence.Radius > chunk.Size.x / 2; + + if (tooCloseToLeftBorder && tooCloseToRightBorder) + { + desiredPosition.x = 0; + } else if (tooCloseToLeftBorder) + { + desiredPosition.x = -chunk.Size.x / 2 + circleFence.Radius; + } else if (tooCloseToRightBorder) + { + desiredPosition.x = chunk.Size.x / 2 - circleFence.Radius; + } + + bool tooCloseToTopBorder = desiredPosition.y + circleFence.Radius > chunk.Size.y / 2; + bool tooCloseToBottomBorder = desiredPosition.y - circleFence.Radius < -chunk.Size.y / 2; + + if (tooCloseToTopBorder && tooCloseToBottomBorder) + { + desiredPosition.y = 0; + } + else if (tooCloseToTopBorder) + { + desiredPosition.y = chunk.Size.y / 2 - circleFence.Radius; + } + else if (tooCloseToBottomBorder) + { + desiredPosition.y = -chunk.Size.y / 2 + circleFence.Radius; + } + } + else if (fence is RectFenceBehavior rectFence) + { + bool tooCloseToLeftBorder = desiredPosition.x - rectFence.Width / 2 < -chunk.Size.x / 2; + bool tooCloseToRightBorder = desiredPosition.x + rectFence.Width / 2 > chunk.Size.x / 2; + + if (tooCloseToLeftBorder && tooCloseToRightBorder) + { + desiredPosition.x = 0; + } + else if (tooCloseToLeftBorder) + { + desiredPosition.x = -chunk.Size.x / 2 + rectFence.Width / 2; + } + else if (tooCloseToRightBorder) + { + desiredPosition.x = chunk.Size.x / 2 - rectFence.Width / 2; + } + + bool tooCloseToTopBorder = desiredPosition.y + rectFence.Height / 2 > chunk.Size.y / 2; + bool tooCloseToBottomBorder = desiredPosition.y - rectFence.Height / 2 < -chunk.Size.y / 2; + + if (tooCloseToTopBorder && tooCloseToBottomBorder) + { + desiredPosition.y = 0; + } + else if (tooCloseToTopBorder) + { + desiredPosition.y = chunk.Size.y / 2 - rectFence.Height / 2; + } + else if (tooCloseToBottomBorder) + { + desiredPosition.y = -chunk.Size.y / 2 + rectFence.Height / 2; + } + } + + return desiredPosition; + } + + public override bool IsPointOutsideRight(Vector2 point, out float distance) + { + bool result = point.x > chunk.RightBound; + distance = result ? point.x - chunk.RightBound : 0; + return result; + } + + public override bool IsPointOutsideLeft(Vector2 point, out float distance) + { + bool result = point.x < chunk.LeftBound; + distance = result ? chunk.LeftBound - point.x : 0; + return result; + } + + public override bool IsPointOutsideTop(Vector2 point, out float distance) + { + bool result = point.y > chunk.TopBound; + distance = result ? point.y - chunk.TopBound : 0; + return result; + } + + public override bool IsPointOutsideBottom(Vector2 point, out float distance) + { + bool result = point.y < chunk.BottomBound; + distance = result ? chunk.BottomBound - point.y : 0; + return result; + } + + public override Vector2 GetIntersectionPoint(Vector2 start, Vector2 end, float offset) + { + var path = end - start; + var distance = path.magnitude; + + // start == end + if (distance < Mathf.Epsilon) return start; + + var direction = path.normalized; + + float tx1, tx2, ty1, ty2; + + // Create rectangle with offset + var rect = new Rect(chunk.LeftBound + offset, chunk.BottomBound + offset, (chunk.Size.x - offset) * 2, (chunk.Size.y - offset) * 2); + + // X axis + if (Mathf.Abs(path.x) > Mathf.Epsilon) + { + // Calculate intersection points + tx1 = (rect.xMin - start.x) / path.x; + tx2 = (rect.xMax - start.x) / path.x; + + // Swapping if needed + if (tx1 > tx2) (tx1, tx2) = (tx2, tx1); + } + else + { + // No intersection + tx1 = float.NegativeInfinity; + tx2 = float.PositiveInfinity; + } + + // Y axis + if (Mathf.Abs(path.y) > Mathf.Epsilon) + { + // Calculate intersection points + ty1 = (rect.yMin - start.y) / path.y; + ty2 = (rect.yMax - start.y) / path.y; + + // Swapping if needed + if (ty1 > ty2) (ty1, ty2) = (ty2, ty1); + } + else + { + // No intersection + ty1 = float.NegativeInfinity; + ty2 = float.PositiveInfinity; + } + + var tEnter = Mathf.Max(tx1, ty1); + var tExit = Mathf.Min(tx2, ty2); + + // No intersection + if (tExit < 0f || tEnter > tExit) return start; + + return start + path * tExit; + } + + public override void RemovePropFromBossFence(BossFenceBehavior fence) + { + chunk.RemovePropFromBossFence(fence); + } + + public override void Clear() + { + Object.Destroy(chunk.gameObject); + + for(int i = 0; i < borders.Count; i++) + { + Object.Destroy(borders[i].gameObject); + } + + borders.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Stage/Stage Field/RectFieldBehavior.cs.meta b/Assets/Common/Scripts/Stage/Stage Field/RectFieldBehavior.cs.meta new file mode 100644 index 0000000..2153e16 --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field/RectFieldBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4ba588b206fc1b54f8fec7516c7745fc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Stage/Stage Field/StageChunkBehavior.cs b/Assets/Common/Scripts/Stage/Stage Field/StageChunkBehavior.cs new file mode 100644 index 0000000..91be70a --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field/StageChunkBehavior.cs @@ -0,0 +1,69 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio +{ + public class StageChunkBehavior : MonoBehaviour + { + [SerializeField] SpriteRenderer sprite; + public Vector2 Size => sprite.size; + public bool IsVisible => sprite.isVisible; + + public float LeftBound => transform.position.x - Size.x / 2; + public float RightBound => transform.position.x + Size.x / 2; + public float TopBound => transform.position.y + Size.y / 2; + public float BottomBound => transform.position.y - Size.y / 2; + + public bool HasEmptyLeft => LeftBound > CameraManager.LeftBound; + public bool HasEmptyRight => RightBound < CameraManager.RightBound; + public bool HasEmptyTop => TopBound < CameraManager.TopBound; + public bool HasEmptyBottom => BottomBound > CameraManager.BottomBound; + + private List borders = new List(); + private List prop = new List(); + + public void AddBorder(Transform border) + { + borders.Add(border); + } + + public void AddProp(PropBehavior propObject) + { + prop.Add(propObject); + + propObject.transform.position = new Vector3(Random.Range(LeftBound, RightBound), Random.Range(BottomBound, TopBound), 0); + } + + public void RemovePropFromBossFence(BossFenceBehavior fence) + { + for(int i = 0; i < prop.Count; i++) + { + if (fence.ValidatePosition(prop[i].transform.position, Vector2.zero)) + { + prop[i].Dissolve(); + prop.RemoveAt(i); + i--; + } + } + } + + public void Clear() + { + for(int i = 0; i < borders.Count; i++) + { + borders[i].gameObject.SetActive(false); + } + + for(int i = 0; i < prop.Count; i++) + { + prop[i].gameObject.SetActive(false); + } + + borders.Clear(); + prop.Clear(); + + gameObject.SetActive(false); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Stage/Stage Field/StageChunkBehavior.cs.meta b/Assets/Common/Scripts/Stage/Stage Field/StageChunkBehavior.cs.meta new file mode 100644 index 0000000..da870a8 --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field/StageChunkBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bac1cfaf43b31eb4eaad629ac0acdf1b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Stage/Stage Field/StageFieldData.cs b/Assets/Common/Scripts/Stage/Stage Field/StageFieldData.cs new file mode 100644 index 0000000..8b1284e --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field/StageFieldData.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Serialization; + +namespace OctoberStudio +{ + [CreateAssetMenu(fileName = "Stage Field Data", menuName = "October/Stage Field Data")] + public class StageFieldData : ScriptableObject + { + [Obsolete("Use backgroundPrefabs field instead")] + [Tooltip("Obsolete, Use backgroundPrefabs field instead")] + [FormerlySerializedAs("backgroundPrefab")] + [SerializeField] GameObject obsoleteBackgroundPrefab; + +#pragma warning disable 0618 + public GameObject BackgroundPrefab => obsoleteBackgroundPrefab; +#pragma warning restore 0618 + + [SerializeField] protected List backgroundPrefabs; + public List BackgroundPrefabs => backgroundPrefabs; + + [Header("Sides")] + [SerializeField] GameObject topPrefab; + [SerializeField] GameObject bottomPrefab; + [SerializeField] GameObject leftPrefab; + [SerializeField] GameObject rightPrefab; + + public GameObject TopPrefab => topPrefab; + public GameObject BottomPrefab => bottomPrefab; + public GameObject LeftPrefab => leftPrefab; + public GameObject RightPrefab => rightPrefab; + + [Header("Corners")] + [SerializeField] GameObject topRightPrefab; + [SerializeField] GameObject topLeftPrefab; + [SerializeField] GameObject bottomRightPrefab; + [SerializeField] GameObject bottomLeftPrefab; + + public GameObject TopRightPrefab => topRightPrefab; + public GameObject TopLeftPrefab => topLeftPrefab; + public GameObject BottomRightPrefab => bottomRightPrefab; + public GameObject BottomLeftPrefab => bottomLeftPrefab; + + [Header("Prop")] + [SerializeField] List propChances; + public List PropChances => propChances; + + public List GetBackgroundPrefabs() + { + if (backgroundPrefabs.Count > 0) return backgroundPrefabs; +#pragma warning disable 0618 + return new List { obsoleteBackgroundPrefab }; +#pragma warning restore 0618 + } + } + + [System.Serializable] + public class StagePropData + { + [SerializeField] GameObject prefab; + [SerializeField, Min(1)] int maxAmount; + [SerializeField, Range(0, 100)] float chance; + + public GameObject Prefab => prefab; + public int MaxAmount => maxAmount; + public float Chance => chance; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Stage/Stage Field/StageFieldData.cs.meta b/Assets/Common/Scripts/Stage/Stage Field/StageFieldData.cs.meta new file mode 100644 index 0000000..946d5d1 --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field/StageFieldData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 108aeb0c3fe1ce34588d447d300c8020 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Stage/Stage Field/StageFieldManager.cs b/Assets/Common/Scripts/Stage/Stage Field/StageFieldManager.cs new file mode 100644 index 0000000..721d9c8 --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field/StageFieldManager.cs @@ -0,0 +1,135 @@ +using OctoberStudio.Bossfight; +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using OctoberStudio.Timeline.Bossfight; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Playables; + +namespace OctoberStudio +{ + public class StageFieldManager : MonoBehaviour + { + private static StageFieldManager instance; + + [SerializeField] BossfightDatabase bossfightDatabase; + + public StageType StageType { get; private set; } + public GameObject BackgroundPrefab { get; private set; } + + public BossFenceBehavior Fence { get; private set; } + + private IFieldBehavior field; + private Dictionary fences; + + private void Awake() + { + instance = this; + } + + public void Init(StageData stageData, PlayableDirector director) + { + switch (stageData.StageType) + { + case StageType.Endless: field = new EndlessFieldBehavior(); break; + case StageType.VerticalEndless: field = new VerticalFieldBehavior(); break; + case StageType.HorizontalEndless: field = new HorizontalFieldBehavior(); break; + case StageType.Rect: field = new RectFieldBehavior(); break; + } + + field.Init(stageData.StageFieldData, stageData.SpawnProp); + + fences = new Dictionary(); + + var bossAssets = director.GetAssets(); + + for(int i = 0; i < bossAssets.Count; i++) + { + var bossAsset = bossAssets[i]; + var bossData = bossfightDatabase.GetBossfight(bossAsset.BossType); + + if (!fences.ContainsKey(bossData.BossType)) + { + var fence = Instantiate(bossData.FencePrefab).GetComponent(); + fence.gameObject.SetActive(false); + fence.Init(); + + fences.Add(bossData.BossType, fence); + } + } + } + + public Vector2 SpawnFence(BossType bossType, Vector2 offset) + { + Fence = fences[bossType]; + + var center = field.GetBossSpawnPosition(Fence, offset); + + Fence.SpawnFence(center); + + return center; + } + + public void RemoveFence() + { + Fence.RemoveFence(); + Fence = null; + } + + public void RemovePropFromFence() + { + field.RemovePropFromBossFence(Fence); + } + + private void Update() + { + if (field == null) return; // StageController.Start 还没调到 Init 时,跳过 + field.Update(); + } + + public bool ValidatePosition(Vector2 position, Vector2 offset, bool withFence = true) + { + var isFenceValid = true; + if(Fence != null && withFence) + { + isFenceValid = Fence.ValidatePosition(position, offset); + } + return instance.field.ValidatePosition(position) && isFenceValid; + } + + public virtual Vector2 GetIntersectionPoint(Vector2 start, Vector2 end, float offset, bool withFence) + { + if(Fence != null && withFence) + { + return Fence.GetIntersectionPoint(start, end, offset); + } + return instance.field.GetIntersectionPoint(start, end, offset); + } + + public Vector2 GetRandomPositionOnBorder() + { + return instance.field.GetRandomPositionOnBorder(); + } + + public bool IsPointOutsideFieldRight(Vector2 point, out float distance) + { + return field.IsPointOutsideRight(point, out distance); + } + + public bool IsPointOutsideFieldLeft(Vector2 point, out float distance) + { + return field.IsPointOutsideLeft(point, out distance); + } + + public bool IsPointOutsideFieldTop(Vector2 point, out float distance) + { + return field.IsPointOutsideTop(point, out distance); + } + + public bool IsPointOutsideFieldBottom(Vector2 point, out float distance) + { + return field.IsPointOutsideBottom(point, out distance); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Stage/Stage Field/StageFieldManager.cs.meta b/Assets/Common/Scripts/Stage/Stage Field/StageFieldManager.cs.meta new file mode 100644 index 0000000..549dbb5 --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field/StageFieldManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a0e10dffca34eaf41973c3a0d9118492 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Stage/Stage Field/VerticalFieldBehavior.cs b/Assets/Common/Scripts/Stage/Stage Field/VerticalFieldBehavior.cs new file mode 100644 index 0000000..2dea472 --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field/VerticalFieldBehavior.cs @@ -0,0 +1,310 @@ +using OctoberStudio.Easing; +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio +{ + public class VerticalFieldBehavior : AbstractFieldBehavior + { + protected List> backgroundPools; + protected PoolComponent leftPool; + protected PoolComponent rightPool; + + protected List chunks = new List(); + + protected bool wait = false; + + public override void Init(StageFieldData stageFieldData, bool spawnProp) + { + base.Init(stageFieldData, spawnProp); + + foreach (var background in stageFieldData.GetBackgroundPrefabs()) + { + var pool = new PoolComponent(background, 6); + } + + backgroundPools = new List>(); + foreach (var background in stageFieldData.GetBackgroundPrefabs()) + { + var pool = new PoolComponent(background, 3); + backgroundPools.Add(pool); + } + + if(stageFieldData.LeftPrefab != null ) + { + leftPool = new PoolComponent("Field Left Border", stageFieldData.LeftPrefab, 4); + } + + if (stageFieldData.RightPrefab != null) + { + rightPool = new PoolComponent("Field Right Border", stageFieldData.RightPrefab, 4); + } + + var chunk = backgroundPools.Random().GetEntity(); + + chunk.transform.position = Vector3.zero; + chunk.transform.rotation = Quaternion.identity; + chunk.transform.localScale = Vector3.one; + + AddBordersToChunk(chunk); + + chunks.Add(chunk); + + wait = false; + EasingManager.DoNextFrame().SetOnFinish(() => wait = true); + } + + public override void Update() + { + if (!wait) return; + + RemoveInvisibleChunks(); + CheckForNewChunks(); + } + + #region Add New Chunks + + protected virtual void CheckForNewChunks() + { + TryAddTopRow(); + TryAddBottomRow(); + } + + protected virtual void TryAddTopRow() + { + if (chunks[0].HasEmptyTop) + { + var chunk = backgroundPools.Random().GetEntity(); + var chunkBellow = chunks[0]; + + chunk.transform.position = chunkBellow.transform.position + Vector3.up * chunk.Size.y; + chunk.transform.rotation = Quaternion.identity; + chunk.transform.localScale = Vector3.one; + + AddBordersToChunk(chunk); + SpawnProp(chunk); + + chunks.Insert(0, chunk); + } + } + + protected virtual void TryAddBottomRow() + { + if (chunks[^1].HasEmptyBottom) + { + var chunk = backgroundPools.Random().GetEntity(); + var chunkOnTop = chunks[^1]; + + chunk.transform.position = chunkOnTop.transform.position + Vector3.down * chunk.Size.y; + chunk.transform.rotation = Quaternion.identity; + chunk.transform.localScale = Vector3.one; + + AddBordersToChunk(chunk); + SpawnProp(chunk); + + chunks.Add(chunk); + } + } + + protected virtual void AddBordersToChunk(StageChunkBehavior chunk) + { + if (leftPool != null) + { + var leftBorder = leftPool.GetEntity(); + leftBorder.transform.position = chunk.transform.position + Vector3.left * chunk.Size.x; + + chunk.AddBorder(leftBorder); + } + + if (rightPool != null) + { + var rightBorder = rightPool.GetEntity(); + rightBorder.transform.position = chunk.transform.position + Vector3.right * chunk.Size.x; + + chunk.AddBorder(rightBorder); + } + } + + #endregion + + #region Remove Invisible Chunks + + protected virtual void RemoveInvisibleChunks() + { + if (chunks.Count == 0) return; + + CheckTopRow(); + CheckBottomRow(); + } + + protected virtual void CheckTopRow() + { + if (!chunks[0].IsVisible) + { + RemoveTopRow(); + } + } + + protected virtual void CheckBottomRow() + { + if (!chunks[^1].IsVisible) + { + RemoveBottomRow(); + } + } + + protected virtual void RemoveTopRow() + { + chunks[0].Clear(); + chunks.RemoveAt(0); + } + + protected virtual void RemoveBottomRow() + { + chunks[^1].Clear(); + chunks.RemoveAt(chunks.Count - 1); + } + + #endregion + + + public override bool ValidatePosition(Vector2 position) + { + if (position.x > chunks[0].transform.position.x + chunks[0].Size.x / 2) return false; + if (position.x < chunks[0].transform.position.x - chunks[0].Size.x / 2) return false; + + return true; + } + + public override Vector2 GetIntersectionPoint(Vector2 start, Vector2 end, float offset) + { + var path = end - start; + var distance = path.magnitude; + + // start == end + if (distance < Mathf.Epsilon) return start; + + var direction = path.normalized; + + float tx1, tx2; + + // Create rectangle with offset + var rect = new Rect(chunks[0].LeftBound + offset, chunks[0].BottomBound + offset, (chunks[0].Size.x - offset) * 2, (chunks[0].Size.y - offset) * 2); + + // X axis + if (Mathf.Abs(path.x) > Mathf.Epsilon) + { + // Calculate intersection points + tx1 = (rect.xMin - start.x) / path.x; + tx2 = (rect.xMax - start.x) / path.x; + + // Swapping if needed + if (tx1 > tx2) (tx1, tx2) = (tx2, tx1); + } + else + { + // No intersection + tx1 = float.NegativeInfinity; + tx2 = float.PositiveInfinity; + } + + var tEnter = tx1; + var tExit = tx2; + + // No intersection + if (tExit < 0f || tEnter > tExit) return start; + + return start + path * tExit; + } + + public override Vector2 GetBossSpawnPosition(BossFenceBehavior fence, Vector2 offset) + { + var playerPosition = PlayerBehavior.Player.transform.position.XY(); + + if (fence is CircleFenceBehavior circleFence) + { + if (circleFence.Radius < chunks[0].Size.x / 2f) + { + circleFence.SetRadiusOverride(chunks[0].Size.x / 2f * 1.1f); + } + + var positionWithOffset = new Vector2(0, playerPosition.y + offset.y); + if (Vector3.Distance(positionWithOffset, playerPosition) < circleFence.Radius) + { + return positionWithOffset; + } + else + { + return new Vector2(0, playerPosition.y); + } + } + else if (fence is RectFenceBehavior rectFence) + { + if (rectFence.Width < chunks[0].Size.x) + { + rectFence.SetSizeOverride(chunks[0].Size.x * 1.1f, rectFence.Height); + } + + return new Vector2(0, playerPosition.y + offset.y); + } + + return playerPosition + offset; + } + + public override Vector2 GetRandomPositionOnBorder() + { + float x = Random.Range(-chunks[0].Size.x / 2, chunks[0].Size.x / 2) + chunks[0].transform.position.x; + + float sign = Random.Range(0, 2) * 2 - 1; + float y = PlayerBehavior.Player.transform.position.y + CameraManager.HalfHeight * 1.05f * sign; + + return new Vector2(x, y); + } + + public override bool IsPointOutsideRight(Vector2 point, out float distance) + { + bool result = point.x > chunks[0].RightBound; + distance = result ? point.x - chunks[0].RightBound : 0; + return result; + } + + public override bool IsPointOutsideLeft(Vector2 point, out float distance) + { + bool result = point.x < chunks[0].LeftBound; + distance = result ? chunks[0].LeftBound - point.x : 0; + return result; + } + + public override bool IsPointOutsideTop(Vector2 point, out float distance) + { + distance = 0; + return false; + } + + public override bool IsPointOutsideBottom(Vector2 point, out float distance) + { + distance = 0; + return false; + } + + public override void RemovePropFromBossFence(BossFenceBehavior fence) + { + for (int i = 0; i < chunks.Count; i++) + { + chunks[i].RemovePropFromBossFence(fence); + } + } + + public override void Clear() + { + for(int i = 0; i < backgroundPools.Count; i++) + { + backgroundPools[i].Destroy(); + } + + backgroundPools.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Stage/Stage Field/VerticalFieldBehavior.cs.meta b/Assets/Common/Scripts/Stage/Stage Field/VerticalFieldBehavior.cs.meta new file mode 100644 index 0000000..cbbcd86 --- /dev/null +++ b/Assets/Common/Scripts/Stage/Stage Field/VerticalFieldBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 42aff85b4ce70f344b268bd394f9dcb0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Stage/StageController.cs b/Assets/Common/Scripts/Stage/StageController.cs new file mode 100644 index 0000000..0bac64f --- /dev/null +++ b/Assets/Common/Scripts/Stage/StageController.cs @@ -0,0 +1,151 @@ +using OctoberStudio.Abilities; +using OctoberStudio.Extensions; +using OctoberStudio.Pool; +using OctoberStudio.Timeline.Bossfight; +using OctoberStudio.UI; +using UnityEngine; +using UnityEngine.Playables; + +namespace OctoberStudio +{ + public class StageController : MonoBehaviour + { + private static StageController instance; + + [SerializeField] StagesDatabase database; + [SerializeField] PlayableDirector director; + [SerializeField] EnemiesSpawner spawner; + [SerializeField] StageFieldManager fieldManager; + [SerializeField] ExperienceManager experienceManager; + [SerializeField] DropManager dropManager; + [SerializeField] AbilityManager abilityManager; + [SerializeField] PoolsManager poolsManager; + [SerializeField] WorldSpaceTextManager worldSpaceTextManager; + [SerializeField] CameraManager cameraManager; + + public static EnemiesSpawner EnemiesSpawner => instance.spawner; + public static ExperienceManager ExperienceManager => instance.experienceManager; + public static AbilityManager AbilityManager => instance.abilityManager; + public static StageFieldManager FieldManager => instance.fieldManager; + public static PlayableDirector Director => instance.director; + public static PoolsManager PoolsManager => instance.poolsManager; + public static WorldSpaceTextManager WorldSpaceTextManager => instance.worldSpaceTextManager; + public static CameraManager CameraController => instance.cameraManager; + public static DropManager DropManager => instance.dropManager; + + [Header("UI")] + [SerializeField] GameScreenBehavior gameScreen; + [SerializeField] StageFailedScreen stageFailedScreen; + [SerializeField] StageCompleteScreen stageCompletedScreen; + + [Header("Testing")] + [SerializeField] PresetData testingPreset; + + public static GameScreenBehavior GameScreen => instance.gameScreen; + + public static StageData Stage { get; private set; } + + private StageSave stageSave; + + private void Awake() + { + instance = this; + + stageSave = GameController.SaveManager.GetSave("Stage"); + } + + private void Start() + { + Stage = database.GetStage(stageSave.SelectedStageId); + + director.playableAsset = Stage.Timeline; + + spawner.Init(director); + experienceManager.Init(testingPreset); + dropManager.Init(); + fieldManager.Init(Stage, director); + abilityManager.Init(testingPreset, PlayerBehavior.Player.Data); + cameraManager.Init(Stage); + + PlayerBehavior.Player.onPlayerDied += OnGameFailed; + + director.stopped += TimelineStopped; + if (testingPreset != null) { + director.time = testingPreset.StartTime; + } else + { + var time = stageSave.Time; + + var bossClips = director.GetClips(); + + for(int i = 0; i < bossClips.Count; i++) + { + var bossClip = bossClips[i]; + + if(time >= bossClip.start && time <= bossClip.end) + { + time = (float) bossClip.start; + break; + } + } + + director.time = time; + } + + director.Play(); + + if (Stage.UseCustomMusic) + { + GameController.ChangeMusic(Stage.MusicName); + } + } + + private void TimelineStopped(PlayableDirector director) + { + if (gameObject.activeSelf) + { + if (stageSave.MaxReachedStageId < stageSave.SelectedStageId + 1 && stageSave.SelectedStageId + 1 < database.StagesCount) + { + stageSave.SetMaxReachedStageId(stageSave.SelectedStageId + 1); + } + + stageSave.IsPlaying = false; + GameController.SaveManager.Save(true); + + gameScreen.Hide(); + stageCompletedScreen.Show(); + Time.timeScale = 0; + } + } + + private void OnGameFailed() + { + Time.timeScale = 0; + + stageSave.IsPlaying = false; + GameController.SaveManager.Save(true); + + gameScreen.Hide(); + stageFailedScreen.Show(); + } + + public static void ResurrectPlayer() + { + EnemiesSpawner.DealDamageToAllEnemies(PlayerBehavior.Player.Damage * 1000); + + GameScreen.Show(); + PlayerBehavior.Player.Revive(); + Time.timeScale = 1; + } + + public static void ReturnToMainMenu() + { + GameController.LoadMainMenu(); + } + + private void OnDisable() + { + director.stopped -= TimelineStopped; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Stage/StageController.cs.meta b/Assets/Common/Scripts/Stage/StageController.cs.meta new file mode 100644 index 0000000..1f796ac --- /dev/null +++ b/Assets/Common/Scripts/Stage/StageController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 91c85fa9f72344c4eb031e5c30d5213b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Stage/StageData.cs b/Assets/Common/Scripts/Stage/StageData.cs new file mode 100644 index 0000000..349b6e6 --- /dev/null +++ b/Assets/Common/Scripts/Stage/StageData.cs @@ -0,0 +1,62 @@ +using UnityEngine; +using UnityEngine.Timeline; + +namespace OctoberStudio +{ + [CreateAssetMenu(fileName = "Stage Data", menuName = "October/Stage Data")] + public class StageData : ScriptableObject + { + [Header("Display Data")] + [SerializeField] Sprite icon; + public Sprite Icon => icon; + + [SerializeField] string displayName; + public string DisplayName => displayName; + + [Header("Timeline Data")] + [SerializeField] TimelineAsset timeline; + public TimelineAsset Timeline => timeline; + + [Header("Stage Settings")] + [SerializeField] StageType stageType; + public StageType StageType => stageType; + + [SerializeField] StageFieldData stageFieldData; + public StageFieldData StageFieldData => stageFieldData; + + [SerializeField] bool spawnProp; + public bool SpawnProp => spawnProp; + + [SerializeField] bool removePropFromBossfight; + public bool RemovePropFromBossfight => removePropFromBossfight; + + [Space] + [SerializeField] Color spotlightColor; + public Color SpotlightColor => spotlightColor; + + [SerializeField] Color spotlightShadowColor; + public Color SpotlightShadowColor => spotlightShadowColor; + + [Space] + [SerializeField] float enemyDamage; + public float EnemyDamage => enemyDamage; + + [SerializeField] float enemyHP; + public float EnemyHP => enemyHP; + + [Space] + [SerializeField] bool useCustomMusic; + public bool UseCustomMusic => useCustomMusic; + + [SerializeField] string musicName; + public string MusicName => musicName; + } + + public enum StageType + { + Endless, + VerticalEndless, + HorizontalEndless, + Rect + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Stage/StageData.cs.meta b/Assets/Common/Scripts/Stage/StageData.cs.meta new file mode 100644 index 0000000..d612850 --- /dev/null +++ b/Assets/Common/Scripts/Stage/StageData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e675658e5d57a9046b3324c0c946a620 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Stage/StageSave.cs b/Assets/Common/Scripts/Stage/StageSave.cs new file mode 100644 index 0000000..f8bae90 --- /dev/null +++ b/Assets/Common/Scripts/Stage/StageSave.cs @@ -0,0 +1,54 @@ +using OctoberStudio.Save; +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio +{ + public class StageSave : ISave + { + [SerializeField] int maxReachedStageId; + [SerializeField] int selectedStageId; + + [SerializeField] bool isPlaying; + [SerializeField] float time; + [SerializeField] bool resetAbilities; + [SerializeField] int xpLevel; + [SerializeField] float xp; + [SerializeField] int enemiesKilled; + + public bool loadedBefore = false; + + public event UnityAction onSelectedStageChanged; + + public int SelectedStageId => selectedStageId; + public int MaxReachedStageId => maxReachedStageId; + + public bool IsFirstStageSelected => selectedStageId == 0; + public bool IsMaxReachedStageSelected => selectedStageId == maxReachedStageId; + + public bool IsPlaying { get => isPlaying; set => isPlaying = value; } + + public float Time { get => time; set => time = value; } + public bool ResetStageData { get => resetAbilities; set => resetAbilities = value; } + public int XPLEVEL { get => xpLevel; set => xpLevel = value; } + public float XP { get => xp; set => xp = value; } + public int EnemiesKilled { get => enemiesKilled; set => enemiesKilled = value; } + + public void SetSelectedStageId(int selectedStageId) + { + this.selectedStageId = selectedStageId; + + onSelectedStageChanged?.Invoke(selectedStageId); + } + + public void SetMaxReachedStageId(int maxReachedStageId) + { + this.maxReachedStageId = maxReachedStageId; + } + + public void Flush() + { + + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Stage/StageSave.cs.meta b/Assets/Common/Scripts/Stage/StageSave.cs.meta new file mode 100644 index 0000000..73f93bb --- /dev/null +++ b/Assets/Common/Scripts/Stage/StageSave.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0bdd1c3c8fd873f4d98c6f9f36c246bf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Stage/StagesDatabase.cs b/Assets/Common/Scripts/Stage/StagesDatabase.cs new file mode 100644 index 0000000..207eacb --- /dev/null +++ b/Assets/Common/Scripts/Stage/StagesDatabase.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio +{ + [CreateAssetMenu(fileName = "Stage Database", menuName = "October/Stages Database")] + public class StagesDatabase : ScriptableObject + { + [SerializeField] List stages; + + public int StagesCount => stages.Count; + + public StageData GetStage(int stageId) + { + return stages[stageId]; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Stage/StagesDatabase.cs.meta b/Assets/Common/Scripts/Stage/StagesDatabase.cs.meta new file mode 100644 index 0000000..ad8a41e --- /dev/null +++ b/Assets/Common/Scripts/Stage/StagesDatabase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 925c0123597e16c489f7e2219144907d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit.meta b/Assets/Common/Scripts/Toolkit.meta new file mode 100644 index 0000000..1f2546b --- /dev/null +++ b/Assets/Common/Scripts/Toolkit.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5901da31a08659648b5fc1d9b5569ed7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit/Audio.meta b/Assets/Common/Scripts/Toolkit/Audio.meta new file mode 100644 index 0000000..3fc8471 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Audio.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3e7a4aa03ac9bcd4a8c83e1569775904 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit/Audio/AudioDatabase.cs b/Assets/Common/Scripts/Toolkit/Audio/AudioDatabase.cs new file mode 100644 index 0000000..3758fe3 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Audio/AudioDatabase.cs @@ -0,0 +1,111 @@ +using OctoberStudio.Extensions; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Serialization; + +namespace OctoberStudio.Audio +{ + [CreateAssetMenu(fileName = "Audio Database", menuName = "October/Audio Database")] + public class AudioDatabase : ScriptableObject + { + [SerializeField] List sounds; + public List Sounds => sounds; + + [Header("Music (Obsolete. Use Sounds instead)")] + [Tooltip("This value is obsolete and will be deprecated. Use sounds instead")] + [SerializeField] SoundContainer music; + + [System.Obsolete("This Property is obsolete and will be deprecated. Use sounds instead")] + public SoundContainer Music => music; + + public void Init() + { + if(music != null) music.Init(); + } + } + + [System.Serializable] + public class SoundContainer + { + [SerializeField] string name; + public string Name => name; + + [Tooltip("The minimum interval between sounds")] + [FormerlySerializedAs("coodlown")] + [SerializeField, Range(0, 1f)] float cooldown; + + [SerializeField] AudioClipData audioClip; + + private float lastTimePlayed; + + public void Init() + { + lastTimePlayed = -1; + } + + public AudioSource Play(bool music = false, float volume = 1, float pitch = 1) + { + if(cooldown == 0 || Time.unscaledTime > lastTimePlayed + cooldown) + { + lastTimePlayed = Time.unscaledTime; + + if (music) + { + return GameController.AudioManager.PlayMusic(audioClip); + } + else + { + return GameController.AudioManager.PlaySound(audioClip, volume, pitch); + } + } + + return null; + } + } + + [System.Serializable] + public class SoundsContainer + { + [Tooltip("The minimum interval between sounds")] + [FormerlySerializedAs("coodlown")] + [SerializeField, Range(0, 1f)] float cooldown; + + [SerializeField] List audioClips; + + private float lastTimePlayed; + + public void Init() + { + lastTimePlayed = -1; + } + + public void Play(bool music = false) + { + if (lastTimePlayed == 0 || Time.unscaledTime > lastTimePlayed + cooldown) + { + var audioClip = audioClips.Random(); + if(music) + { + GameController.AudioManager.PlayMusic(audioClip); + } else + { + GameController.AudioManager.PlaySound(audioClip); + } + lastTimePlayed = Time.unscaledTime; + } + } + } + + [System.Serializable] + public class AudioClipData + { + [SerializeField] AudioClip audioClip; + public AudioClip AudioClip => audioClip; + + [SerializeField] Vector2 volume = Vector2.one; + public float Volume => Random.Range(volume.x, volume.y); + + [SerializeField] Vector2 pitch = Vector2.one; + public float Pitch => Random.Range(pitch.x, pitch.y); + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Audio/AudioDatabase.cs.meta b/Assets/Common/Scripts/Toolkit/Audio/AudioDatabase.cs.meta new file mode 100644 index 0000000..f315967 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Audio/AudioDatabase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 95531853c36d2984a9a689e5bba6f689 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit/Audio/AudioManager.cs b/Assets/Common/Scripts/Toolkit/Audio/AudioManager.cs new file mode 100644 index 0000000..3946156 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Audio/AudioManager.cs @@ -0,0 +1,201 @@ +using OctoberStudio.Pool; +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Audio +{ + public class AudioManager : MonoBehaviour, IAudioManager + { + public static readonly int BUTTON_CLICK_HASH = "Button Click".GetHashCode(); + + private static AudioManager instance; + + [SerializeField] AudioDatabase database; + [SerializeField] GameObject audioSource; + + public AudioDatabase AudioDatabase => database; + + private PoolComponent audioSourcePool; + private List aliveSources = new List(); + + private Dictionary sounds; + + private AudioSave save; + + public float SoundVolume { + get => save.SoundVolume; + set + { + save.SoundVolume = value; + OnSoundVolumeChanged(); + } + } + + public float MusicVolume + { + get => save.MusicVolume; + set + { + save.MusicVolume = value; + OnMusicVolumeChanged(); + } + } + + private void Awake() + { + if (instance != null) + { + Destroy(gameObject); + return; + } + + instance = this; + DontDestroyOnLoad(gameObject); + + audioSourcePool = new PoolComponent("audio source", audioSource, 2, null, true); + + gameObject.AddComponent(); + + sounds = new Dictionary(); + + for(int i = 0; i < database.Sounds.Count; i++) + { + var sound = database.Sounds[i]; + var hash = sound.Name.GetHashCode(); + + if (sounds.ContainsKey(hash)) + { + Debug.LogError($"Audio clip with the name {sound.Name} has already been added. You should rename one of the entries with this name."); + } else + { + sound.Init(); + sounds.Add(hash, sound); + } + } + + GameController.RegisterAudioManager(this); + } + + private void Start() + { + save = GameController.SaveManager.GetSave("Audio"); + } + + public AudioSource PlaySound(AudioClip clip, float volume = 1, float pitch = 1) + { + var source = audioSourcePool.GetEntity(); + source.clip = clip; + + source.loop = false; + + source.pitch = pitch; + source.volume = volume * save.SoundVolume; + + var data = new AudioData() { source = source, volume = volume }; + aliveSources.Add(data); + + source.Play(); + + return source; + } + + public AudioSource PlaySound(int hash, float volume = 1, float pitch = 1) + { + if (sounds.ContainsKey(hash)) + { + return sounds[hash].Play(false, volume, pitch); + } + + Debug.LogWarning($"There are no sound with hash {hash} in the AudioDatabase"); + return null; + } + + public AudioSource PlaySound(AudioClipData clipData, float volume = 1, float pitch = 1) + { + var source = audioSourcePool.GetEntity(); + source.clip = clipData.AudioClip; + + source.loop = false; + + source.pitch = clipData.Pitch * pitch; + source.volume = clipData.Volume * save.SoundVolume * volume; + + var data = new AudioData() { source = source, volume = clipData.Volume }; + aliveSources.Add(data); + + source.Play(); + + return source; + } + + public AudioSource PlayMusic(AudioClipData clipData) + { + var source = audioSourcePool.GetEntity(); + source.clip = clipData.AudioClip; + + source.loop = true; + + source.pitch = clipData.Pitch; + source.volume = clipData.Volume * save.MusicVolume; + + var data = new AudioData() { source = source, volume = clipData.Volume }; + aliveSources.Add(data); + + source.Play(); + + return source; + } + + public AudioSource PlayMusic(int hash) + { + if (sounds.ContainsKey(hash)) + { + return sounds[hash].Play(true); + } + + Debug.LogWarning($"There are no sound with hash {hash} in the AudioDatabase"); + return null; + } + + private void OnSoundVolumeChanged() + { + foreach(var source in aliveSources) + { + if (!source.source.loop) + { + source.source.volume = source.volume * save.SoundVolume; + } + } + } + + private void OnMusicVolumeChanged() + { + foreach (var source in aliveSources) + { + if (source.source.loop) + { + source.source.volume = source.volume * save.MusicVolume; + } + } + } + + private void Update() + { + for(int i = 0; i < aliveSources.Count; i++) + { + if (!aliveSources[i].source.isPlaying && !aliveSources[i].source.loop) + { + aliveSources[i].source.gameObject.SetActive(false); + aliveSources.RemoveAt(i); + i--; + } + } + } + + public class AudioData + { + public AudioSource source; + public float volume; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Audio/AudioManager.cs.meta b/Assets/Common/Scripts/Toolkit/Audio/AudioManager.cs.meta new file mode 100644 index 0000000..5e6cf6e --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Audio/AudioManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b9eafbfc5f86cde438061e141667e490 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit/Audio/AudioSave.cs b/Assets/Common/Scripts/Toolkit/Audio/AudioSave.cs new file mode 100644 index 0000000..fb3360d --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Audio/AudioSave.cs @@ -0,0 +1,19 @@ +using OctoberStudio.Save; +using UnityEngine; + +namespace OctoberStudio.Audio +{ + public class AudioSave : ISave + { + [SerializeField] float soundVolume = 1f; + [SerializeField] float musicVolume = 1f; + + public float SoundVolume { get => soundVolume; set => soundVolume = value; } + public float MusicVolume { get => musicVolume; set => musicVolume = value; } + + public void Flush() + { + + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Audio/AudioSave.cs.meta b/Assets/Common/Scripts/Toolkit/Audio/AudioSave.cs.meta new file mode 100644 index 0000000..65cb138 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Audio/AudioSave.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0679799a402d0ba42a7f876f53315d01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit/Audio/IAudioManager.cs b/Assets/Common/Scripts/Toolkit/Audio/IAudioManager.cs new file mode 100644 index 0000000..1c95811 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Audio/IAudioManager.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +namespace OctoberStudio.Audio +{ + public interface IAudioManager + { + AudioDatabase AudioDatabase { get; } + + float SoundVolume { get; set; } + float MusicVolume { get; set; } + + AudioSource PlaySound(AudioClip clip, float volume = 1, float pitch = 1); + AudioSource PlaySound(int hash, float volume = 1, float pitch = 1); + AudioSource PlaySound(AudioClipData clipData, float volume = 1, float pitch = 1); + + AudioSource PlayMusic(AudioClipData clipData); + AudioSource PlayMusic(int hash); + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Audio/IAudioManager.cs.meta b/Assets/Common/Scripts/Toolkit/Audio/IAudioManager.cs.meta new file mode 100644 index 0000000..4762889 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Audio/IAudioManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9837b3b10b9ab2747b2f251bee85f5f1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit/Currency.meta b/Assets/Common/Scripts/Toolkit/Currency.meta new file mode 100644 index 0000000..a2ce628 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Currency.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5c193e3f40ee88e499ac7bdd0ddc3d0c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit/Currency/CurrenciesDatabase.cs b/Assets/Common/Scripts/Toolkit/Currency/CurrenciesDatabase.cs new file mode 100644 index 0000000..e8ea903 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Currency/CurrenciesDatabase.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace OctoberStudio.Currency +{ + [CreateAssetMenu(fileName = "Currencies Database", menuName = "October/Currencies Database")] + public class CurrenciesDatabase : ScriptableObject + { + [SerializeField] List currencies; + + public CurrencyData GetCurrency(string id) + { + for(int i = 0; i < currencies.Count; i++) + { + if (currencies[i].ID == id) return currencies[i]; + } + + return null; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Currency/CurrenciesDatabase.cs.meta b/Assets/Common/Scripts/Toolkit/Currency/CurrenciesDatabase.cs.meta new file mode 100644 index 0000000..ae74d2a --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Currency/CurrenciesDatabase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a23ba7731b9c73c4ca43dcb5842230ab +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit/Currency/CurrenciesManager.cs b/Assets/Common/Scripts/Toolkit/Currency/CurrenciesManager.cs new file mode 100644 index 0000000..a250fa1 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Currency/CurrenciesManager.cs @@ -0,0 +1,43 @@ +using UnityEngine; + +namespace OctoberStudio.Currency +{ + public class CurrenciesManager : MonoBehaviour + { + private static CurrenciesManager instance; + + [SerializeField] CurrenciesDatabase database; + + public void Init() + { + if(instance != null) + { + Destroy(this); + + return; + } + + instance = this; + + DontDestroyOnLoad(gameObject); + } + + public Sprite GetIcon(string currencyId) + { + var data = database.GetCurrency(currencyId); + + if(data == null) return null; + + return data.Icon; + } + + public string GetName(string currencyId) + { + var data = database.GetCurrency(currencyId); + + if (data == null) return null; + + return data.Name; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Currency/CurrenciesManager.cs.meta b/Assets/Common/Scripts/Toolkit/Currency/CurrenciesManager.cs.meta new file mode 100644 index 0000000..31b1937 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Currency/CurrenciesManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 40afd16adc25e1241a0df40c6ea65656 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit/Currency/CurrencyData.cs b/Assets/Common/Scripts/Toolkit/Currency/CurrencyData.cs new file mode 100644 index 0000000..db7b510 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Currency/CurrencyData.cs @@ -0,0 +1,17 @@ +using UnityEngine; + +namespace OctoberStudio.Currency +{ + [System.Serializable] + public class CurrencyData + { + [SerializeField] string id; + public string ID => id; + + [SerializeField] string name; + public string Name => name; + + [SerializeField] Sprite icon; + public Sprite Icon => icon; + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Currency/CurrencyData.cs.meta b/Assets/Common/Scripts/Toolkit/Currency/CurrencyData.cs.meta new file mode 100644 index 0000000..7ec8dc4 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Currency/CurrencyData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2c48b20e412d744468ab31ff8bd6a794 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit/Currency/CurrencySave.cs b/Assets/Common/Scripts/Toolkit/Currency/CurrencySave.cs new file mode 100644 index 0000000..ed6e513 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Currency/CurrencySave.cs @@ -0,0 +1,53 @@ +using OctoberStudio.Save; +using System; +using UnityEngine; + +namespace OctoberStudio +{ + public class CurrencySave: ISave + { + [SerializeField] int amount; + public int Amount => amount; + + public event Action onGoldAmountChanged; + + public void Deposit(int depositedAmount) + { + amount += depositedAmount; + + onGoldAmountChanged?.Invoke(amount); + } + + public void Withdraw(int withdrawnAmount) + { + amount -= withdrawnAmount; + if (amount < 0) amount = 0; + + onGoldAmountChanged?.Invoke(amount); + } + + public bool TryWithdraw(int withdrawnAmount) + { + var canAfford = CanAfford(withdrawnAmount); + + if(canAfford) + { + amount -= withdrawnAmount; + + onGoldAmountChanged?.Invoke(amount); + } + + return canAfford; + } + + public bool CanAfford(int requiredAmount) + { + return amount >= requiredAmount; + } + + public void Flush() + { + + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Currency/CurrencySave.cs.meta b/Assets/Common/Scripts/Toolkit/Currency/CurrencySave.cs.meta new file mode 100644 index 0000000..ec23c23 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Currency/CurrencySave.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b16b5ea92b742ee4d8dea8bcf7ada199 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit/Easing.meta b/Assets/Common/Scripts/Toolkit/Easing.meta new file mode 100644 index 0000000..c28aefa --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Easing.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2673a67e79ff45679955dab2d4a4748a +timeCreated: 1726371403 \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Easing/EasingExtensions.cs b/Assets/Common/Scripts/Toolkit/Easing/EasingExtensions.cs new file mode 100644 index 0000000..840eb37 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Easing/EasingExtensions.cs @@ -0,0 +1,131 @@ +using OctoberStudio.Extensions; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +namespace OctoberStudio.Easing +{ + public static class EasingExtensions + { + public static EasingJobAnimation DoPositionJob(this Transform transform, Transform targetTransform, float duration, float delay = 0, bool useUnscaledTime = false, EasingType easingType = EasingType.Linear) + { + return new PositionEasingJobAnimation(transform, targetTransform, duration, delay, useUnscaledTime, easingType); + } + + public static IEasingCoroutine DoAnchorPosition(this RectTransform rect, Vector2 targetPosition, float duration, float delay = 0) + { + return new VectorEasingCoroutine3(rect.anchoredPosition3D, new Vector3(targetPosition.x, targetPosition.y, rect.anchoredPosition3D.z), duration, delay, (position) => rect.anchoredPosition3D = position); + } + + public static IEasingCoroutine DoSizeDelta(this RectTransform rect, Vector2 targetSizeDelta, float duration, float delay = 0) + { + Vector2 startSizeDelta = rect.sizeDelta; + + return new VectorEasingCoroutine2(startSizeDelta, targetSizeDelta, duration, delay, (position) => rect.sizeDelta = position); + } + + public static IEasingCoroutine DoPosition(this Transform transform, Vector3 targetPosition, float duration, float delay = 0) + { + Vector3 startPosition = transform.position; + + return new VectorEasingCoroutine3(startPosition, targetPosition, duration, delay, (position) => transform.position = position); + } + + public static IEasingCoroutine DoPosition(this Transform transform, Transform targetTransform, float duration, float delay = 0) + { + Vector3 startPosition = transform.position; + + IEasingCoroutine coroutine = EasingManager.DoFloat(0, 1, duration, (value) => + { + transform.position = Vector3.LerpUnclamped(startPosition, targetTransform.position, value); + }, delay); + + return coroutine; + } + + public static IEasingCoroutine DoLocalScale(this Transform transform, Vector3 targetScale, float duration, float delay = 0) + { + Vector3 startScale = transform.localScale; + + return new VectorEasingCoroutine3(startScale, targetScale, duration, delay, (scale) => transform.localScale = scale); + } + + public static void StopIfExists(this IEasingCoroutine coroutine) + { + if(coroutine != null && coroutine.IsActive) coroutine.Stop(); + } + + public static bool ExistsAndActive(this IEasingCoroutine coroutine) + { + return coroutine != null && coroutine.IsActive; + } + + public static IEasingCoroutine DoColor(this MaterialPropertyBlock block, string property, Color color, float duration, float delay = 0) + { + var id = Shader.PropertyToID(property); + + var startColor = block.GetColor(id); + + return new ColorEasingCoroutine(startColor, color, duration, delay, (color) => block.SetColor(id, color)); + } + + public static IEasingCoroutine DoColor(this Material material, string property, Color color, float duration, float delay = 0) + { + var id = Shader.PropertyToID(property); + + var startColor = material.GetColor(id); + + return new ColorEasingCoroutine(startColor, color, duration, delay, (color) => material.SetColor(id, color)); + } + + public static IEasingCoroutine DoColor(this Material material, int propertyId, Color color, float duration, float delay = 0) + { + var startColor = material.GetColor(propertyId); + + return new ColorEasingCoroutine(startColor, color, duration, delay, (color) => material.SetColor(propertyId, color)); + } + + public static IEasingCoroutine DoFloat(this Material material, string property, float value, float duration, float delay = 0) + { + var id = Shader.PropertyToID(property); + + var startValue = material.GetFloat(id); + + return new FloatEasingCoroutine(startValue, value, duration, delay, (value) => material.SetFloat(id, value)); + } + + public static IEasingCoroutine DoFloat(this Material material, int propertyId, float value, float duration, float delay = 0) + { + var startValue = material.GetFloat(propertyId); + + return new FloatEasingCoroutine(startValue, value, duration, delay, (value) => material.SetFloat(propertyId, value)); + } + + public static IEasingCoroutine DoAlpha(this Graphic graphic, float targetAlpha, float duration, float delay = 0) + { + var initialAplha = graphic.color.a; + + return new FloatEasingCoroutine(initialAplha, targetAlpha, duration, delay, (alpha) => graphic.SetAlpha(alpha)); + } + + public static IEasingCoroutine DoAlpha(this CanvasGroup canvasGroup, float targetAlpha, float duration, float delay = 0) + { + var initialAplha = canvasGroup.alpha; + + return new FloatEasingCoroutine(initialAplha, targetAlpha, duration, delay, (alpha) => canvasGroup.alpha = alpha); + } + + public static IEasingCoroutine DoAlpha(this SpriteRenderer spriteRederer, float targetAlpha, float duration, float delay = 0) + { + var initialAplha = spriteRederer.color.a; + + return new FloatEasingCoroutine(initialAplha, targetAlpha, duration, delay, (alpha) => spriteRederer.SetAlpha(alpha)); + } + + public static IEasingCoroutine DoVolume(this AudioSource audioSource, float targetVolume, float duration, float delay = 0) + { + return new FloatEasingCoroutine(audioSource.volume, targetVolume, duration, delay, (volume) => audioSource.volume = volume); + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Easing/EasingExtensions.cs.meta b/Assets/Common/Scripts/Toolkit/Easing/EasingExtensions.cs.meta new file mode 100644 index 0000000..2e42a94 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Easing/EasingExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4ed79232000048948bd9fa77abd8d4b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit/Easing/EasingFunctions.cs b/Assets/Common/Scripts/Toolkit/Easing/EasingFunctions.cs new file mode 100644 index 0000000..da22d02 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Easing/EasingFunctions.cs @@ -0,0 +1,241 @@ +using System.Runtime.CompilerServices; +using Unity.Burst; +using Unity.Mathematics; + +namespace OctoberStudio.Easing +{ + [BurstCompile] + public static class EasingFunctions + { + public static readonly FunctionPointer[] Functions; + + public delegate float EasingFunction(float t); + + static EasingFunctions() + { + Functions = new FunctionPointer[] + { + BurstCompiler.CompileFunctionPointer(Linear), + + BurstCompiler.CompileFunctionPointer(QuadIn), + BurstCompiler.CompileFunctionPointer(QuadOut), + BurstCompiler.CompileFunctionPointer(QuadOutIn), + + BurstCompiler.CompileFunctionPointer(CubicIn), + BurstCompiler.CompileFunctionPointer(CubicOut), + BurstCompiler.CompileFunctionPointer(CubicInOut), + + BurstCompiler.CompileFunctionPointer(QuartIn), + BurstCompiler.CompileFunctionPointer(QuartOut), + BurstCompiler.CompileFunctionPointer(QuartInOut), + + BurstCompiler.CompileFunctionPointer(QuintIn), + BurstCompiler.CompileFunctionPointer(QuintOut), + BurstCompiler.CompileFunctionPointer(QuintInOut), + + BurstCompiler.CompileFunctionPointer(SineIn), + BurstCompiler.CompileFunctionPointer(SineOut), + BurstCompiler.CompileFunctionPointer(SineInOut), + + BurstCompiler.CompileFunctionPointer(CircIn), + BurstCompiler.CompileFunctionPointer(CircOut), + BurstCompiler.CompileFunctionPointer(CircInOut), + + BurstCompiler.CompileFunctionPointer(ExpoIn), + BurstCompiler.CompileFunctionPointer(ExpoOut), + BurstCompiler.CompileFunctionPointer(ExpoInOut), + + BurstCompiler.CompileFunctionPointer(ElasticIn), + BurstCompiler.CompileFunctionPointer(ElasticOut), + BurstCompiler.CompileFunctionPointer(ElasticInOut), + + BurstCompiler.CompileFunctionPointer(BackIn), + BurstCompiler.CompileFunctionPointer(BackOut), + BurstCompiler.CompileFunctionPointer(BackInOut), + + BurstCompiler.CompileFunctionPointer(BounceIn), + BurstCompiler.CompileFunctionPointer(BounceOut), + BurstCompiler.CompileFunctionPointer(BounceInOut), + }; + } + + public static float ApplyEasing(float t, EasingType easingType) + { + switch (easingType) + { + case EasingType.Linear: return Linear(t); + + case EasingType.QuadIn: return QuadIn(t); + case EasingType.QuadOut: return QuadOut(t); + case EasingType.QuadOutIn: return QuadOutIn(t); + + case EasingType.CubicIn: return CubicIn(t); + case EasingType.CubicOut: return CubicOut(t); + case EasingType.CubicInOut: return CubicInOut(t); + + case EasingType.QuartIn: return QuartIn(t); + case EasingType.QuartOut: return QuartOut(t); + case EasingType.QuartInOut: return QuartInOut(t); + + case EasingType.QuintIn: return QuintIn(t); + case EasingType.QuintOut: return QuintOut(t); + case EasingType.QuintInOut: return QuintInOut(t); + + case EasingType.SineIn: return SineIn(t); + case EasingType.SineOut: return SineOut(t); + case EasingType.SineInOut: return SineInOut(t); + + case EasingType.CircIn: return CircIn(t); + case EasingType.CircOut: return CircOut(t); + case EasingType.CircInOut: return CircInOut(t); + + case EasingType.ExpoIn: return ExpoIn(t); + case EasingType.ExpoOut: return ExpoOut(t); + case EasingType.ExpoInOut: return ExpoInOut(t); + + case EasingType.ElasticIn: return ElasticIn(t); + case EasingType.ElasticOut: return ElasticOut(t); + case EasingType.ElasticInOut: return ElasticInOut(t); + + case EasingType.BackIn: return BackIn(t); + case EasingType.BackOut: return BackOut(t); + case EasingType.BackInOut: return BackInOut(t); + + case EasingType.BounceIn: return BounceIn(t); + case EasingType.BounceOut: return BounceOut(t); + case EasingType.BounceInOut: return BounceInOut(t); + } + + return t; + } + + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Linear(float t) => t; + + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float QuadIn(float t) => t * t; + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float QuadOut(float t) => -(t * (t - 2)); + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float QuadOutIn(float t) => t < 0.5f ? 2 * t * t : (-2 * t * t) + (4 * t) - 1; + + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float CubicIn(float t) => t * t * t; + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float CubicOut(float t) => (t - 1) * (t - 1) * (t - 1) + 1; + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float CubicInOut(float t) => t < 0.5f ? 4 * t * t * t : 0.5f * ((2 * t) - 2) * ((2 * t) - 2) * ((2 * t) - 2) + 1; + + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float QuartIn(float t) => t * t * t * t; + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float QuartOut(float t) => (t - 1) * (t - 1) * (t - 1) * (1 - t) + 1; + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float QuartInOut(float t) => t < 0.5f ? 8 * t * t * t * t : -8 * (t - 1) * (t - 1) * (t - 1) * (t - 1) + 1; + + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float QuintIn(float t) => t * t * t * t * t; + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float QuintOut(float t) => (t - 1) * (t - 1) * (t - 1) * (t - 1) * (t - 1) + 1; + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float QuintInOut(float t) => t < 0.5f ? 16 * t * t * t * t * t : 0.5f * ((2 * t) - 2) * ((2 * t) - 2) * ((2 * t) - 2) * ((2 * t) - 2) * ((2 * t) - 2) + 1; + + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float SineIn(float t) => math.sin((t - 1) * math.PI / 2f) + 1; + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float SineOut(float t) => math.sin(t * math.PI / 2f); + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float SineInOut(float t) => 0.5f * (1 - math.cos(t * math.PI)); + + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float CircIn(float t) => 1 - math.sqrt(1 - (t * t)); + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float CircOut(float t) => math.sqrt((2 - t) * t); + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float CircInOut(float t) => t < 0.5f ? 0.5f * (1 - math.sqrt(1 - 4 * (t * t))) : 0.5f * (math.sqrt(-((2 * t) - 3) * ((2 * t) - 1)) + 1); + + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float ExpoIn(float t) => Approximately(t, 0.0f) ? t : math.pow(2, 10 * (t - 1)); + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float ExpoOut(float t) => Approximately(t, 1.0f) ? t : 1 - math.pow(2, -10 * t); + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float ExpoInOut(float t) => (Approximately(t, 0.0f) || Approximately(t, 1.0f)) ? t : t < 0.5f ? 0.5f * math.pow(2, (20 * t) - 10) : -0.5f * math.pow(2, (-20 * t) + 10) + 1; + + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float ElasticIn(float t) => math.sin(13 * math.PI / 2 * t) * math.pow(2, 10 * (t - 1)); + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float ElasticOut(float t) => math.sin(-13 * math.PI / 2 * (t + 1)) * math.pow(2, -10 * t) + 1; + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float ElasticInOut(float t) => t < 0.5f ? 0.5f * math.sin(13 * math.PI / 2 * (2 * t)) * math.pow(2, 10 * ((2 * t) - 1)) : 0.5f * (math.sin(-13 * math.PI / 2 * ((2 * t - 1) + 1)) * math.pow(2, -10 * (2 * t - 1)) + 2); + + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float BackIn(float t) => t * t * t - t * math.sin(t * math.PI); + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float BackOut(float t) => 1 - ((1 - t) * (1 - t) * (1 - t) - (1 - t) * math.sin((1 - t) * math.PI)); + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float BackInOut(float t) => t < 0.5f ? 0.5f * (2 * t * 2 * t * 2 * t - 2 * t * math.sin(2 * t * math.PI)) : 0.5f * (1 - ((1 - (2 * t - 1)) * (1 - (2 * t - 1)) * (1 - (2 * t - 1)) - (1 - (2 * t - 1)) * math.sin((1 - (2 * t - 1)) * math.PI))) + 0.5f; + + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float BounceIn(float t) => 1 - BounceOut(1 - t); + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float BounceInOut(float t) => t < 0.5f ? 0.5f * BounceIn(t * 2) : 0.5f * BounceOut(t * 2 - 1) + 0.5f; + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float BounceOut(float t) + { + if (t < 4 / 11.0f) + { + return (121 * t * t) / 16.0f; + } + else if (t < 8 / 11.0f) + { + return (363 / 40.0f * t * t) - (99 / 10.0f * t) + 17 / 5.0f; + } + else if (t < 9 / 10.0f) + { + return (4356 / 361.0f * t * t) - (35442 / 1805.0f * t) + 16061 / 1805.0f; + } + else + { + return (54 / 5.0f * t * t) - (513 / 25.0f * t) + 268 / 25.0f; + } + } + + [BurstCompile] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool Approximately(float a, float b) + { + return math.abs(a - b) < 1e-5f; // same default epsilon as Mathf.Approximately + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Easing/EasingFunctions.cs.meta b/Assets/Common/Scripts/Toolkit/Easing/EasingFunctions.cs.meta new file mode 100644 index 0000000..e48b2fb --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Easing/EasingFunctions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ab53d1741571d1b48aedffe5d0ebb9d8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit/Easing/EasingManager.cs b/Assets/Common/Scripts/Toolkit/Easing/EasingManager.cs new file mode 100644 index 0000000..db01d33 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Easing/EasingManager.cs @@ -0,0 +1,660 @@ +using OctoberStudio.Extensions; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Unity.Burst; +using Unity.Collections; +using Unity.Jobs; +using Unity.Mathematics; +using UnityEngine; +using UnityEngine.Events; + +namespace OctoberStudio.Easing +{ + public class EasingManager : MonoBehaviour + { + private static EasingManager instance; + + protected EasingPositionJobRunner positionJobRunner; + public static EasingPositionJobRunner PositionJobRunner => instance.positionJobRunner; + + public virtual void Awake() + { + instance = this; + + positionJobRunner = new EasingPositionJobRunner(); + } + + protected virtual void OnDestroy() + { + positionJobRunner.Clear(); + } + + protected virtual void Update() + { + positionJobRunner.Update(); + } + + protected virtual void LateUpdate() + { + positionJobRunner.LateUpdate(); + } + + public static IEasingCoroutine DoFloat(float from, float to, float duration, UnityAction action, float delay = 0) + { + return new FloatEasingCoroutine(from, to, duration, delay, action); + } + + public static IEasingCoroutine DoAfter(float seconds, UnityAction action, bool unscaledTime = false) + { + return new WaitCoroutine(seconds, unscaledTime).SetOnFinish(action); + } + + public static IEasingCoroutine DoAfter(Func condition) + { + return new WaitForConditionCoroutine(condition); + } + + public static IEasingCoroutine DoNextFrame() + { + return new NextFrameCoroutine(); + } + public static IEasingCoroutine DoNextFrame(UnityAction action) + { + return new NextFrameCoroutine().SetOnFinish(action); + } + + public static IEasingCoroutine DoNextFixedFrame() + { + return new NextFixedFrameCoroutine(); + } + + public static Coroutine StartCustomCoroutine(IEnumerator coroutine) + { + return instance.StartCoroutine(coroutine); + } + + public static void StopCustomCoroutine(Coroutine coroutine) + { + if (instance != null) instance.StopCoroutine(coroutine); + } + } + + public interface IEasingCoroutine + { + bool IsActive { get; } + IEasingCoroutine SetEasing(EasingType easingType); + IEasingCoroutine SetEasingCurve(AnimationCurve easingCurve); + IEasingCoroutine SetOnFinish(UnityAction callback); + IEasingCoroutine SetUnscaledTime(bool unscaledTime); + IEasingCoroutine SetDelay(float delay); + void Stop(); + } + + public abstract class EmptyCoroutine : IEasingCoroutine + { + protected Coroutine coroutine; + + public bool IsActive { get; protected set; } + + protected UnityAction finishCallback; + + protected EasingType easingType = EasingType.Linear; + + protected float delay = -1; + + protected bool unscaledTime; + + protected bool useCurve; + + protected AnimationCurve easingCurve; + + public IEasingCoroutine SetEasing(EasingType easingType) + { + this.easingType = easingType; + useCurve = false; + return this; + } + + public IEasingCoroutine SetOnFinish(UnityAction callback) + { + finishCallback = callback; + return this; + } + + public IEasingCoroutine SetUnscaledTime(bool unscaledTime) + { + this.unscaledTime = unscaledTime; + return this; + } + + public IEasingCoroutine SetEasingCurve(AnimationCurve curve) + { + easingCurve = curve; + useCurve = true; + + return this; + } + + public IEasingCoroutine SetDelay(float delay) + { + this.delay = delay; + + return this; + } + + public void Stop() + { + EasingManager.StopCustomCoroutine(coroutine); + + IsActive = false; + } + } + + public class NextFrameCoroutine : EmptyCoroutine + { + public NextFrameCoroutine() + { + coroutine = EasingManager.StartCustomCoroutine(Coroutine()); + } + + private IEnumerator Coroutine() + { + IsActive = true; + + yield return null; + + finishCallback?.Invoke(); + + IsActive = false; + } + } + + public class NextFixedFrameCoroutine : EmptyCoroutine + { + public NextFixedFrameCoroutine() + { + coroutine = EasingManager.StartCustomCoroutine(Coroutine()); + } + + private IEnumerator Coroutine() + { + IsActive = true; + + yield return new WaitForFixedUpdate(); + + finishCallback?.Invoke(); + + IsActive = false; + } + } + + public class WaitCoroutine : EmptyCoroutine + { + protected float duration; + + public WaitCoroutine(float duration, bool unscaledTime = false) + { + this.duration = duration; + this.unscaledTime = unscaledTime; + + coroutine = EasingManager.StartCustomCoroutine(Coroutine()); + } + + private IEnumerator Coroutine() + { + IsActive = true; + + while (delay > 0) + { + yield return null; + + delay -= unscaledTime ? Time.unscaledDeltaTime : Time.deltaTime; + } + + if (unscaledTime) + { + yield return new WaitForSecondsRealtime(duration); + } + else + { + yield return new WaitForSeconds(duration); + } + + finishCallback?.Invoke(); + + IsActive = false; + } + } + + public class WaitForConditionCoroutine : EmptyCoroutine + { + private Func condition; + + public WaitForConditionCoroutine(Func condition) + { + this.condition = condition; + coroutine = EasingManager.StartCustomCoroutine(Coroutine()); + } + + private IEnumerator Coroutine() + { + IsActive = true; + + while (delay > 0) + { + yield return null; + + delay -= unscaledTime ? Time.unscaledDeltaTime : Time.deltaTime; + } + + do + { + yield return null; + } while (!condition()); + + finishCallback?.Invoke(); + + IsActive = false; + } + } + + public abstract class EasingCoroutine : EmptyCoroutine + { + protected T from; + protected T to; + protected float duration; + + protected UnityAction callback; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public abstract T Lerp(T a, T b, float t); + + public EasingCoroutine(T from, T to, float duration, float delay, UnityAction callback) + { + this.from = from; + this.to = to; + this.duration = duration; + this.callback = callback; + this.delay = delay; + + coroutine = EasingManager.StartCustomCoroutine(Coroutine()); + } + + private IEnumerator Coroutine() + { + IsActive = true; + + float time = 0; + + while (time < duration) + { + yield return null; + + if (delay > 0) + { + delay -= unscaledTime ? Time.unscaledDeltaTime : Time.deltaTime; + + if (delay > 0) continue; + } + + time += unscaledTime ? Time.unscaledDeltaTime : Time.deltaTime; + float t; + if (useCurve) + { + t = easingCurve.Evaluate(time / duration); + } + else + { + t = EasingFunctions.ApplyEasing(time / duration, easingType); + } + + T value = Lerp(from, to, t); + callback?.Invoke(value); + } + + callback.Invoke(to); + finishCallback?.Invoke(); + + IsActive = false; + } + } + + public class FloatEasingCoroutine : EasingCoroutine + { + public FloatEasingCoroutine(float from, float to, float duration, float delay, UnityAction callback) : base(from, to, duration, delay, callback) + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override float Lerp(float a, float b, float t) + { + return Mathf.LerpUnclamped(a, b, t); + } + } + + public class VectorEasingCoroutine3 : EasingCoroutine + { + public VectorEasingCoroutine3(Vector3 from, Vector3 to, float duration, float delay, UnityAction callback) : base(from, to, duration, delay, callback) + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override Vector3 Lerp(Vector3 a, Vector3 b, float t) + { + return Vector3.LerpUnclamped(a, b, t); + } + } + + public class VectorEasingCoroutine2 : EasingCoroutine + { + public VectorEasingCoroutine2(Vector2 from, Vector2 to, float duration, float delay, UnityAction callback) : base(from, to, duration, delay, callback) + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override Vector2 Lerp(Vector2 a, Vector2 b, float t) + { + return Vector2.LerpUnclamped(a, b, t); + } + } + + public class ColorEasingCoroutine : EasingCoroutine + { + public ColorEasingCoroutine(Color from, Color to, float duration, float delay, UnityAction callback) : base(from, to, duration, delay, callback) + { + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override Color Lerp(Color a, Color b, float t) + { + return Color.LerpUnclamped(a, b, t); + } + } + + public abstract class EasingJobAnimation + { + protected float startTime; + public float StartTime => startTime; + + protected float endTime; + public float EndTime => endTime; + + protected bool useUnscaledTime; + public bool UseUnscaledTime => useUnscaledTime; + + protected EasingType easingType; + public EasingType EasingType => easingType; + + protected UnityAction finishCallback; + + protected EasingJobAnimation(float duration, float delay, bool useUnscaledTime, EasingType easingType) + { + this.useUnscaledTime = useUnscaledTime; + + var time = useUnscaledTime ? Time.unscaledTime : Time.time; + startTime = time + delay; + endTime = startTime + duration; + + this.easingType = easingType; + } + + public bool IsActive => useUnscaledTime ? Time.unscaledTime < endTime : Time.time < endTime; + public bool IsStarted => useUnscaledTime ? startTime <= Time.unscaledTime : startTime <= Time.time; + + public virtual void SetOnFinish(UnityAction finishCallback) + { + this.finishCallback = finishCallback; + } + + public virtual void Finish() + { + finishCallback?.Invoke(); + } + } + + public class PositionEasingJobAnimation : EasingJobAnimation + { + protected Transform transform; + protected Transform targetTransform; + + public float2 Position { get => transform.position.XY(); set => transform.position = (Vector2)value; } + public float2 Target => targetTransform.position.XY(); + + public PositionEasingJobAnimation(Transform transform, Transform targetTransform, float duration, float delay, bool useUnscaledTime, EasingType easingType) : base(duration, delay, useUnscaledTime, easingType) + { + this.transform = transform; + this.targetTransform = targetTransform; + + IsValid = true; + + EasingManager.PositionJobRunner.AddJobAnimaiton(this); + } + + public bool IsValid { get; protected set; } + } + + public class EasingPositionJobRunner + { + protected List waitingAnimations; + protected List activeAnimations; + + [ReadOnly] public NativeList timeData; + [ReadOnly] public NativeList useUnscaledTime; + + [ReadOnly] public NativeList> easingFunctions; + + [ReadOnly] public NativeList startPositions; + [ReadOnly] public NativeList targets; + + [WriteOnly] public NativeList positions; + + public bool isJobRunning = false; + + protected DoPosition2DJob doPosition2DJob; + protected JobHandle doPosition2DJobHandle; + protected int capacityCache; + + public EasingPositionJobRunner() + { + waitingAnimations = new List(10); + activeAnimations = new List(50); + + timeData = new NativeList(50, Allocator.Persistent); + useUnscaledTime = new NativeList(50, Allocator.Persistent); + + easingFunctions = new NativeList>(50, Allocator.Persistent); + + startPositions = new NativeList(50, Allocator.Persistent); + targets = new NativeList(50, Allocator.Persistent); + + positions = new NativeList(50, Allocator.Persistent); + + doPosition2DJob = new DoPosition2DJob(); + + capacityCache = timeData.Capacity; + + ReinitializeJob(); + } + + public virtual void AddJobAnimaiton(PositionEasingJobAnimation jobAnimation) + { + if (jobAnimation.IsStarted && !isJobRunning) + { + AddActiveAnimation(jobAnimation); + } else + { + waitingAnimations.Add(jobAnimation); + } + } + + public virtual void Update() + { + if (waitingAnimations.Count > 0) + { + for (int i = 0; i < waitingAnimations.Count; i++) + { + if (waitingAnimations[i].IsStarted) + { + AddActiveAnimation(waitingAnimations[i]); + waitingAnimations.RemoveAt(i); + + i--; + } + } + } + + if (activeAnimations.Count == 0) return; + + for (int i = 0; i < activeAnimations.Count; i++) + { + var animation = activeAnimations[i]; + + if (animation.IsValid) + { + targets[i] = activeAnimations[i].Target; + } + else + { + RemoveActiveAnimation(i); + i--; + } + } + + doPosition2DJob.scaledTime = Time.time; + doPosition2DJob.unscaledTime = Time.unscaledTime; + + doPosition2DJobHandle = doPosition2DJob.Schedule(activeAnimations.Count, 16); + JobHandle.ScheduleBatchedJobs(); + + isJobRunning = true; + } + + protected virtual void ReinitializeJob() + { + doPosition2DJob.timeData = timeData.AsDeferredJobArray(); + doPosition2DJob.useUnscaledTime = useUnscaledTime.AsDeferredJobArray(); + + doPosition2DJob.easingFunctions = easingFunctions.AsDeferredJobArray(); + + doPosition2DJob.startPositions = startPositions.AsDeferredJobArray(); + doPosition2DJob.targets = targets.AsDeferredJobArray(); + + doPosition2DJob.positions = positions.AsDeferredJobArray(); + } + + protected virtual void AddActiveAnimation(PositionEasingJobAnimation jobAnimation) + { + activeAnimations.Add(jobAnimation); + + timeData.Add(new float2(jobAnimation.StartTime, jobAnimation.EndTime)); + useUnscaledTime.Add(jobAnimation.UseUnscaledTime ? 1f : 0f); + + easingFunctions.Add(EasingFunctions.Functions[(int)jobAnimation.EasingType]); + + startPositions.Add(jobAnimation.Position); + targets.Add(jobAnimation.Target); + + positions.Add(float2.zero); + + if(timeData.Capacity != capacityCache) + { + capacityCache = timeData.Capacity; + ReinitializeJob(); + } + } + + public virtual void LateUpdate() + { + if (!isJobRunning) return; + isJobRunning = false; + + doPosition2DJobHandle.Complete(); + + for (int i = 0; i < activeAnimations.Count; i++) + { + var animation = activeAnimations[i]; + + var remove = false; + if (animation.IsValid) + { + activeAnimations[i].Position = positions[i]; + + if (!animation.IsActive) + { + animation.Finish(); + remove = true; + } + } else + { + remove = true; + } + + if (remove) + { + RemoveActiveAnimation(i); + i--; + } + } + } + + protected virtual void RemoveActiveAnimation(int index) + { + activeAnimations.RemoveAt(index); + + timeData.RemoveAt(index); + useUnscaledTime.RemoveAt(index); + easingFunctions.RemoveAt(index); + startPositions.RemoveAt(index); + targets.RemoveAt(index); + positions.RemoveAt(index); + } + + public virtual void Clear() + { + if(isJobRunning) doPosition2DJobHandle.Complete(); + + timeData.Dispose(); + useUnscaledTime.Dispose(); + + easingFunctions.Dispose(); + startPositions.Dispose(); + + targets.Dispose(); + positions.Dispose(); + } + + [BurstCompile(OptimizeFor = OptimizeFor.Performance)] + public struct DoPosition2DJob : IJobParallelFor + { + // x - startTime, y = endTime + [ReadOnly] public NativeArray timeData; + [ReadOnly] public NativeArray useUnscaledTime; + + [ReadOnly] public NativeArray> easingFunctions; + + [ReadOnly] public NativeArray startPositions; + [ReadOnly] public NativeArray targets; + + [WriteOnly] public NativeArray positions; + + [ReadOnly] public float scaledTime; + [ReadOnly] public float unscaledTime; + + public void Execute(int i) + { + var time = math.select(unscaledTime, scaledTime, useUnscaledTime[i] == 0f); + var t = math.unlerp(timeData[i].x, timeData[i].y, time); + + t = easingFunctions[i].Invoke(math.saturate(t)); + + positions[i] = startPositions[i] + (targets[i] - startPositions[i]) * t; + } + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Easing/EasingManager.cs.meta b/Assets/Common/Scripts/Toolkit/Easing/EasingManager.cs.meta new file mode 100644 index 0000000..0c97d2e --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Easing/EasingManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5d03811da5f05704a947e8cb019e6422 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit/Easing/EasingType.cs b/Assets/Common/Scripts/Toolkit/Easing/EasingType.cs new file mode 100644 index 0000000..f73386b --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Easing/EasingType.cs @@ -0,0 +1,37 @@ +namespace OctoberStudio.Easing +{ + public enum EasingType + { + Linear = 0, + QuadIn = 1, + QuadOut = 2, + QuadOutIn = 3, + CubicIn = 4, + CubicOut = 5, + CubicInOut = 6, + QuartIn = 7, + QuartOut = 8, + QuartInOut = 9, + QuintIn = 10, + QuintOut = 11, + QuintInOut = 12, + SineIn = 13, + SineOut = 14, + SineInOut = 15, + CircIn = 16, + CircOut = 17, + CircInOut = 18, + ExpoIn = 19, + ExpoOut = 20, + ExpoInOut = 21, + ElasticIn = 22, + ElasticOut = 23, + ElasticInOut = 24, + BackIn = 25, + BackOut = 26, + BackInOut = 27, + BounceIn = 28, + BounceOut = 29, + BounceInOut = 30 + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Easing/EasingType.cs.meta b/Assets/Common/Scripts/Toolkit/Easing/EasingType.cs.meta new file mode 100644 index 0000000..ea45801 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Easing/EasingType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cd65cd1dd628aeb44bca3a0ff8431b71 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit/Editor.meta b/Assets/Common/Scripts/Toolkit/Editor.meta new file mode 100644 index 0000000..d235930 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5388d699cfd8b1445a0b7888d5745372 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit/Extensions.meta b/Assets/Common/Scripts/Toolkit/Extensions.meta new file mode 100644 index 0000000..603b7cc --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Extensions.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c517916457074615a5923d188acd305d +timeCreated: 1726266740 \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Extensions/ColorExtensions.cs b/Assets/Common/Scripts/Toolkit/Extensions/ColorExtensions.cs new file mode 100644 index 0000000..ed79218 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Extensions/ColorExtensions.cs @@ -0,0 +1,31 @@ +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.UIElements; + +namespace OctoberStudio.Extensions +{ + public static class ColorExtensions + { + public static Color SetAlpha(this Color color, float aValue) + { + color.a = aValue; + + return color; + } + + public static Graphic SetAlpha(this Graphic graphic, float a) + { + graphic.color = graphic.color.SetAlpha(a); + + return graphic; + } + + public static void SetBorderColor(this IStyle style, Color color) + { + style.borderBottomColor = color; + style.borderLeftColor = color; + style.borderRightColor = color; + style.borderTopColor = color; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Extensions/ColorExtensions.cs.meta b/Assets/Common/Scripts/Toolkit/Extensions/ColorExtensions.cs.meta new file mode 100644 index 0000000..6e5b9a4 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Extensions/ColorExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9f61e5ebbbbb4509bc1ec256f0464d19 +timeCreated: 1726370083 \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Extensions/EnumerableExtensions.cs b/Assets/Common/Scripts/Toolkit/Extensions/EnumerableExtensions.cs new file mode 100644 index 0000000..4b069b8 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Extensions/EnumerableExtensions.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.Linq; + +namespace OctoberStudio.Extensions +{ + public static class EnumerableExtensions + { + public static T Random(this IList list) + { + return list[UnityEngine.Random.Range(0, list.Count)]; + } + + public static T Random(this IEnumerable enumerable) + { + var count = enumerable.Count(); + var rand = UnityEngine.Random.Range(0, count); + var i = 0; + foreach (var element in enumerable) + { + if (rand == i) + return element; + i++; + } + + return default; + } + + public static T PopRandom(this IList list) + { + var random = UnityEngine.Random.Range(0, list.Count); + var result = list[random]; + list.RemoveAt(random); + return result; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Extensions/EnumerableExtensions.cs.meta b/Assets/Common/Scripts/Toolkit/Extensions/EnumerableExtensions.cs.meta new file mode 100644 index 0000000..730710b --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Extensions/EnumerableExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9361332e187e45f5a6a914432472d272 +timeCreated: 1726267459 \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Extensions/RectTransformExtensions.cs b/Assets/Common/Scripts/Toolkit/Extensions/RectTransformExtensions.cs new file mode 100644 index 0000000..0a28562 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Extensions/RectTransformExtensions.cs @@ -0,0 +1,63 @@ +using System.Runtime.CompilerServices; +using UnityEngine; +using UnityEngine.UI; + +namespace OctoberStudio.Extensions +{ + public static class RectTransformExtensions + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RectTransform SetAnchoredPositionX(this Graphic graphic, float x) + { + return graphic.rectTransform.SetAnchoredPositionX(x); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RectTransform SetAnchoredPositionY(this Graphic graphic, float y) + { + return graphic.rectTransform.SetAnchoredPositionY(y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RectTransform SetAnchoredPositionX(this RectTransform rectTransform, float x) + { + rectTransform.anchoredPosition = rectTransform.anchoredPosition.SetX(x); + return rectTransform; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RectTransform SetAnchoredPositionY(this RectTransform rectTransform, float y) + { + rectTransform.anchoredPosition = rectTransform.anchoredPosition.SetY(y); + return rectTransform; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RectTransform SetSizeDeltaX(this RectTransform rectTransform, float x) + { + rectTransform.sizeDelta = rectTransform.sizeDelta.SetX(x); + return rectTransform; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Graphic SetSizeDeltaX(this Graphic graphic, float x) + { + graphic.rectTransform.sizeDelta = graphic.rectTransform.sizeDelta.SetX(x); + return graphic; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RectTransform SetSizeDeltaY(this RectTransform rectTransform, float y) + { + rectTransform.sizeDelta = rectTransform.sizeDelta.SetY(y); + return rectTransform; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Graphic SetSizeDeltaY(this Graphic graphic, float y) + { + graphic.rectTransform.sizeDelta = graphic.rectTransform.sizeDelta.SetY(y); + return graphic; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Extensions/RectTransformExtensions.cs.meta b/Assets/Common/Scripts/Toolkit/Extensions/RectTransformExtensions.cs.meta new file mode 100644 index 0000000..dd286ec --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Extensions/RectTransformExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 713fde6385ac45ee9a1b65caceec8e9e +timeCreated: 1726369401 \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Extensions/SpriteRendererExtensions.cs b/Assets/Common/Scripts/Toolkit/Extensions/SpriteRendererExtensions.cs new file mode 100644 index 0000000..ea93ccf --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Extensions/SpriteRendererExtensions.cs @@ -0,0 +1,15 @@ +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace OctoberStudio.Extensions +{ + public static class SpriteRendererExtensions + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static SpriteRenderer SetAlpha(this SpriteRenderer renderer, float alpha) + { + renderer.color = renderer.color.SetAlpha(alpha); + return renderer; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Extensions/SpriteRendererExtensions.cs.meta b/Assets/Common/Scripts/Toolkit/Extensions/SpriteRendererExtensions.cs.meta new file mode 100644 index 0000000..aa2459b --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Extensions/SpriteRendererExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0e22da8a1a1c01843a1180839a781528 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit/Extensions/ToolkitExtensions.cs b/Assets/Common/Scripts/Toolkit/Extensions/ToolkitExtensions.cs new file mode 100644 index 0000000..0dcb7ca --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Extensions/ToolkitExtensions.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using UnityEngine.Playables; +using UnityEngine.Timeline; + +namespace OctoberStudio.Extensions +{ + public static class ToolkitExtensions + { + public static List GetAssets(this PlayableDirector director) where T : TrackAsset where K : PlayableAsset + { + var result = new List(); + + foreach (var output in director.playableAsset.outputs) + { + if (output.sourceObject is T track) + { + foreach (var clip in track.GetClips()) + { + if (clip.asset is K asset) + { + result.Add(asset); + } + } + } + } + + return result; + } + + public static List GetClips(this PlayableDirector director) where T : TrackAsset where K : PlayableAsset + { + var result = new List(); + + foreach (var output in director.playableAsset.outputs) + { + if (output.sourceObject is T track) + { + foreach (var clip in track.GetClips()) + { + if (clip.asset is K) + { + result.Add(clip); + } + } + } + } + + return result; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Extensions/ToolkitExtensions.cs.meta b/Assets/Common/Scripts/Toolkit/Extensions/ToolkitExtensions.cs.meta new file mode 100644 index 0000000..c425428 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Extensions/ToolkitExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: aa9490abb8704c20a19c3071ac3973aa +timeCreated: 1726365457 \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Extensions/TransformExtensions.cs b/Assets/Common/Scripts/Toolkit/Extensions/TransformExtensions.cs new file mode 100644 index 0000000..0a3e42c --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Extensions/TransformExtensions.cs @@ -0,0 +1,25 @@ +using UnityEngine; + +namespace OctoberStudio.Extensions +{ + public static class TransformExtensions + { + public static Transform ResetLocal(this Transform transform) + { + transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); + + transform.localScale = Vector3.one; + + return transform; + } + + public static Transform ResetGlobal(this Transform transform) + { + transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity); + + transform.localScale = Vector3.one; + + return transform; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Extensions/TransformExtensions.cs.meta b/Assets/Common/Scripts/Toolkit/Extensions/TransformExtensions.cs.meta new file mode 100644 index 0000000..8e71a8f --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Extensions/TransformExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 70baeb55ac48491a9301777797203bc3 +timeCreated: 1726267352 \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Extensions/VectorExtensions.cs b/Assets/Common/Scripts/Toolkit/Extensions/VectorExtensions.cs new file mode 100644 index 0000000..8b10410 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Extensions/VectorExtensions.cs @@ -0,0 +1,71 @@ +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace OctoberStudio.Extensions +{ + public static class VectorExtensions + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 XZ(this Vector3 vector) => new Vector2(vector.x, vector.z); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 XY(this Vector3 vector) => new Vector2(vector.x, vector.y); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 YZ(this Vector3 vector) => new Vector2(vector.y, vector.z); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 XYZ(this Vector4 value) => new Vector3(value.x, value.y, value.z); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 XY(this Vector4 value) => new Vector2(value.x, value.y); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 SetZ(this Vector4 vector, float value) + { + vector.z = value; + + return vector; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 SetX(this Vector3 vector, float value) + { + vector.x = value; + + return vector; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 SetY(this Vector3 vector, float value) + { + vector.y = value; + + return vector; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 SetZ(this Vector3 vector, float value) + { + vector.z = value; + + return vector; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 SetX(this Vector2 vector, float value) + { + vector.x = value; + + return vector; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 SetY(this Vector2 vector, float value) + { + vector.y = value; + + return vector; + } + } +} \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Extensions/VectorExtensions.cs.meta b/Assets/Common/Scripts/Toolkit/Extensions/VectorExtensions.cs.meta new file mode 100644 index 0000000..f0df7e1 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Extensions/VectorExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0fc0b8446fe34467a55b19f4e7140560 +timeCreated: 1726267352 \ No newline at end of file diff --git a/Assets/Common/Scripts/Toolkit/Input.meta b/Assets/Common/Scripts/Toolkit/Input.meta new file mode 100644 index 0000000..74da7d5 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Input.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e3e6f2753bb63f245b0b63ab9297f391 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Common/Scripts/Toolkit/Input/HighlightableButtonUI.cs b/Assets/Common/Scripts/Toolkit/Input/HighlightableButtonUI.cs new file mode 100644 index 0000000..5fb2a78 --- /dev/null +++ b/Assets/Common/Scripts/Toolkit/Input/HighlightableButtonUI.cs @@ -0,0 +1,66 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace OctoberStudio.UI +{ + [RequireComponent(typeof(Button))] + public class HighlightableButtonUI : MonoBehaviour, ISelectHandler, IDeselectHandler + { + public bool IsHighlighted { get; set; } + + protected Button button; + + private Vector3 savedPosition = Vector3.zero; + + protected virtual void Awake() + { + button = GetComponent