diff options
author | chai <215380520@qq.com> | 2024-03-21 10:28:46 +0800 |
---|---|---|
committer | chai <215380520@qq.com> | 2024-03-21 10:28:46 +0800 |
commit | 3fb2121cc0d00cbd42b2ca10b5dfb399a4df1a04 (patch) | |
tree | c1f4683fb021522b459408ab1ad61c40be77ee47 | |
parent | 9ee2cfa385ed77c39003f524f5f03079124fc476 (diff) |
*misc
109 files changed, 11019 insertions, 11 deletions
diff --git a/Assembly_CSharp/.vs/ProjectEvaluation/roguetower.metadata.v5.2 b/Assembly_CSharp/.vs/ProjectEvaluation/roguetower.metadata.v5.2 Binary files differindex f9a914b..b0cfd99 100644 --- a/Assembly_CSharp/.vs/ProjectEvaluation/roguetower.metadata.v5.2 +++ b/Assembly_CSharp/.vs/ProjectEvaluation/roguetower.metadata.v5.2 diff --git a/Assembly_CSharp/.vs/ProjectEvaluation/roguetower.projects.v5.2 b/Assembly_CSharp/.vs/ProjectEvaluation/roguetower.projects.v5.2 Binary files differindex bc7c288..5fb5798 100644 --- a/Assembly_CSharp/.vs/ProjectEvaluation/roguetower.projects.v5.2 +++ b/Assembly_CSharp/.vs/ProjectEvaluation/roguetower.projects.v5.2 diff --git a/Assembly_CSharp/.vs/RogueTower/DesignTimeBuild/.dtbcache.v2 b/Assembly_CSharp/.vs/RogueTower/DesignTimeBuild/.dtbcache.v2 Binary files differindex 185c6d1..a9ca918 100644 --- a/Assembly_CSharp/.vs/RogueTower/DesignTimeBuild/.dtbcache.v2 +++ b/Assembly_CSharp/.vs/RogueTower/DesignTimeBuild/.dtbcache.v2 diff --git a/Assembly_CSharp/.vs/RogueTower/FileContentIndex/53548182-5dd3-46a3-8253-f9dcdfb12a9f.vsidx b/Assembly_CSharp/.vs/RogueTower/FileContentIndex/53548182-5dd3-46a3-8253-f9dcdfb12a9f.vsidx Binary files differdeleted file mode 100644 index 1b7038b..0000000 --- a/Assembly_CSharp/.vs/RogueTower/FileContentIndex/53548182-5dd3-46a3-8253-f9dcdfb12a9f.vsidx +++ /dev/null diff --git a/Assembly_CSharp/.vs/RogueTower/FileContentIndex/543ecb80-83ee-4e8b-a04a-2776c4c9ef4f.vsidx b/Assembly_CSharp/.vs/RogueTower/FileContentIndex/543ecb80-83ee-4e8b-a04a-2776c4c9ef4f.vsidx Binary files differdeleted file mode 100644 index 2f00599..0000000 --- a/Assembly_CSharp/.vs/RogueTower/FileContentIndex/543ecb80-83ee-4e8b-a04a-2776c4c9ef4f.vsidx +++ /dev/null diff --git a/Assembly_CSharp/.vs/RogueTower/v17/.suo b/Assembly_CSharp/.vs/RogueTower/v17/.suo Binary files differindex 69249e8..7693ec6 100644 --- a/Assembly_CSharp/.vs/RogueTower/v17/.suo +++ b/Assembly_CSharp/.vs/RogueTower/v17/.suo diff --git a/Assembly_CSharp/obj/Debug/netstandard2.0/RogueTower.GeneratedMSBuildEditorConfig.editorconfig b/Assembly_CSharp/obj/Debug/netstandard2.0/RogueTower.GeneratedMSBuildEditorConfig.editorconfig index a8e9be8..8aa5c36 100644 --- a/Assembly_CSharp/obj/Debug/netstandard2.0/RogueTower.GeneratedMSBuildEditorConfig.editorconfig +++ b/Assembly_CSharp/obj/Debug/netstandard2.0/RogueTower.GeneratedMSBuildEditorConfig.editorconfig @@ -1,3 +1,3 @@ is_global = true build_property.RootNamespace = RogueTower -build_property.ProjectDir = D:\Games\_PC\_Mono\Rogue Tower\Decompile\Assembly_CSharp\ +build_property.ProjectDir = D:\Games\PC\_Mono\Rogue Tower\Decompile\Assembly_CSharp\ diff --git a/Assembly_CSharp/obj/Debug/netstandard2.0/RogueTower.assets.cache b/Assembly_CSharp/obj/Debug/netstandard2.0/RogueTower.assets.cache Binary files differindex b8ef08a..af085e0 100644 --- a/Assembly_CSharp/obj/Debug/netstandard2.0/RogueTower.assets.cache +++ b/Assembly_CSharp/obj/Debug/netstandard2.0/RogueTower.assets.cache diff --git a/Assembly_CSharp/obj/Debug/netstandard2.0/RogueTower.csproj.AssemblyReference.cache b/Assembly_CSharp/obj/Debug/netstandard2.0/RogueTower.csproj.AssemblyReference.cache Binary files differindex 4ac6ac6..2a05939 100644 --- a/Assembly_CSharp/obj/Debug/netstandard2.0/RogueTower.csproj.AssemblyReference.cache +++ b/Assembly_CSharp/obj/Debug/netstandard2.0/RogueTower.csproj.AssemblyReference.cache diff --git a/Assembly_CSharp/obj/RogueTower.csproj.nuget.dgspec.json b/Assembly_CSharp/obj/RogueTower.csproj.nuget.dgspec.json index 5f2465c..31878da 100644 --- a/Assembly_CSharp/obj/RogueTower.csproj.nuget.dgspec.json +++ b/Assembly_CSharp/obj/RogueTower.csproj.nuget.dgspec.json @@ -1,17 +1,17 @@ { "format": 1, "restore": { - "D:\\Games\\_PC\\_Mono\\Rogue Tower\\Decompile\\Assembly_CSharp\\RogueTower.csproj": {} + "D:\\Games\\PC\\_Mono\\Rogue Tower\\Decompile\\Assembly_CSharp\\RogueTower.csproj": {} }, "projects": { - "D:\\Games\\_PC\\_Mono\\Rogue Tower\\Decompile\\Assembly_CSharp\\RogueTower.csproj": { + "D:\\Games\\PC\\_Mono\\Rogue Tower\\Decompile\\Assembly_CSharp\\RogueTower.csproj": { "version": "1.0.0", "restore": { - "projectUniqueName": "D:\\Games\\_PC\\_Mono\\Rogue Tower\\Decompile\\Assembly_CSharp\\RogueTower.csproj", + "projectUniqueName": "D:\\Games\\PC\\_Mono\\Rogue Tower\\Decompile\\Assembly_CSharp\\RogueTower.csproj", "projectName": "Assembly-CSharp", - "projectPath": "D:\\Games\\_PC\\_Mono\\Rogue Tower\\Decompile\\Assembly_CSharp\\RogueTower.csproj", + "projectPath": "D:\\Games\\PC\\_Mono\\Rogue Tower\\Decompile\\Assembly_CSharp\\RogueTower.csproj", "packagesPath": "C:\\Users\\Administrator\\.nuget\\packages\\", - "outputPath": "D:\\Games\\_PC\\_Mono\\Rogue Tower\\Decompile\\Assembly_CSharp\\obj\\", + "outputPath": "D:\\Games\\PC\\_Mono\\Rogue Tower\\Decompile\\Assembly_CSharp\\obj\\", "projectStyle": "PackageReference", "fallbackFolders": [ "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" diff --git a/Assembly_CSharp/obj/project.assets.json b/Assembly_CSharp/obj/project.assets.json index 38d8907..926b7af 100644 --- a/Assembly_CSharp/obj/project.assets.json +++ b/Assembly_CSharp/obj/project.assets.json @@ -186,11 +186,11 @@ "project": { "version": "1.0.0", "restore": { - "projectUniqueName": "D:\\Games\\_PC\\_Mono\\Rogue Tower\\Decompile\\Assembly_CSharp\\RogueTower.csproj", + "projectUniqueName": "D:\\Games\\PC\\_Mono\\Rogue Tower\\Decompile\\Assembly_CSharp\\RogueTower.csproj", "projectName": "Assembly-CSharp", - "projectPath": "D:\\Games\\_PC\\_Mono\\Rogue Tower\\Decompile\\Assembly_CSharp\\RogueTower.csproj", + "projectPath": "D:\\Games\\PC\\_Mono\\Rogue Tower\\Decompile\\Assembly_CSharp\\RogueTower.csproj", "packagesPath": "C:\\Users\\Administrator\\.nuget\\packages\\", - "outputPath": "D:\\Games\\_PC\\_Mono\\Rogue Tower\\Decompile\\Assembly_CSharp\\obj\\", + "outputPath": "D:\\Games\\PC\\_Mono\\Rogue Tower\\Decompile\\Assembly_CSharp\\obj\\", "projectStyle": "PackageReference", "fallbackFolders": [ "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" diff --git a/Assembly_CSharp/obj/project.nuget.cache b/Assembly_CSharp/obj/project.nuget.cache index 3d5d096..c9729cd 100644 --- a/Assembly_CSharp/obj/project.nuget.cache +++ b/Assembly_CSharp/obj/project.nuget.cache @@ -1,8 +1,8 @@ { "version": 2, - "dgSpecHash": "TXdjMDGnAcXpY8OX7QNyMyANBH85Ib9TBuPLsvYCe4Y195KcyQG5bt2WeTPgYc/ukbn2xXIEKovN3smCGtxa1w==", + "dgSpecHash": "+X9xFnoe2YNyXySc25Xl3dPzed7x+O7/vrAZMkSQSivo71Bz95RqS6JTrVV8bJpnKDKLegjGlRbuCMi+oCMOog==", "success": true, - "projectFilePath": "D:\\Games\\_PC\\_Mono\\Rogue Tower\\Decompile\\Assembly_CSharp\\RogueTower.csproj", + "projectFilePath": "D:\\Games\\PC\\_Mono\\Rogue Tower\\Decompile\\Assembly_CSharp\\RogueTower.csproj", "expectedPackageFiles": [ "C:\\Users\\Administrator\\.nuget\\packages\\microsoft.netcore.platforms\\1.1.0\\microsoft.netcore.platforms.1.1.0.nupkg.sha512", "C:\\Users\\Administrator\\.nuget\\packages\\netstandard.library\\2.0.3\\netstandard.library.2.0.3.nupkg.sha512" diff --git a/GameCode/.NETStandard,Version=v2.0.AssemblyAttributes.cs b/GameCode/.NETStandard,Version=v2.0.AssemblyAttributes.cs new file mode 100644 index 0000000..8bf3a42 --- /dev/null +++ b/GameCode/.NETStandard,Version=v2.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// <autogenerated /> +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] diff --git a/GameCode/AchievementManager.cs b/GameCode/AchievementManager.cs new file mode 100644 index 0000000..a189341 --- /dev/null +++ b/GameCode/AchievementManager.cs @@ -0,0 +1,424 @@ +using Steamworks; +using UnityEngine; + +public class AchievementManager : MonoBehaviour +{ + public static AchievementManager instance; + + private int goldSpentOnResearch; + + private int discoveriesMade; + + private int enemiesKilled; + + [SerializeField] + private string[] towerUnlockStrings; + + public bool shrineSpawned; + + private void Awake() + { + instance = this; + } + + private void Start() + { + if (SteamManager.Initialized) + { + SteamUserStats.GetStat("EnemiesKilled", out enemiesKilled); + SteamUserStats.GetStat("DiscoveriesMade", out discoveriesMade); + SteamUserStats.GetStat("GoldOnResearch", out goldSpentOnResearch); + } + } + + public void OnSceneClose() + { + if (SteamManager.Initialized) + { + SteamUserStats.SetStat("EnemiesKilled", enemiesKilled); + SteamUserStats.SetStat("DiscoveriesMade", discoveriesMade); + SteamUserStats.SetStat("GoldOnResearch", goldSpentOnResearch); + SteamUserStats.StoreStats(); + } + } + + public void ResetSteamStats() + { + SteamUserStats.ResetAllStats(bAchievementsToo: true); + } + + public void FundResearchAchievement(int amt) + { + if (goldSpentOnResearch < 100000 && goldSpentOnResearch + amt >= 100000) + { + UnlockAchievement("Funding100000"); + } + else if (goldSpentOnResearch < 10000 && goldSpentOnResearch + amt >= 10000) + { + UnlockAchievement("Funding10000"); + } + else if (goldSpentOnResearch < 1000 && goldSpentOnResearch + amt >= 1000) + { + UnlockAchievement("Funding1000"); + } + goldSpentOnResearch += amt; + } + + public void NewDiscoveriesAchievement() + { + discoveriesMade++; + if (discoveriesMade == 100) + { + UnlockAchievement("Discover100"); + } + else if (discoveriesMade == 10) + { + UnlockAchievement("Discover10"); + } + else if (discoveriesMade == 1) + { + UnlockAchievement("Discover1"); + } + } + + public void EnemyKilled() + { + enemiesKilled++; + if (enemiesKilled == 1000000) + { + UnlockAchievement("Kill1000000Enemies"); + } + else if (enemiesKilled == 100000) + { + UnlockAchievement("Kill100000Enemies"); + } + else if (enemiesKilled == 10000) + { + UnlockAchievement("Kill10000Enemies"); + } + else if (enemiesKilled == 1000) + { + UnlockAchievement("Kill1000Enemies"); + } + else if (enemiesKilled == 100) + { + UnlockAchievement("Kill100Enemies"); + } + } + + public void UnlockAchievement(string s) + { + if (SteamManager.Initialized) + { + Debug.Log("Unlocked Achievement: " + s); + SteamUserStats.SetAchievement(s); + SteamUserStats.StoreStats(); + } + } + + public void CheckTowerUnlocks() + { + int num = 0; + string[] array = towerUnlockStrings; + foreach (string key in array) + { + num += PlayerPrefs.GetInt(key, 0); + } + if (num == towerUnlockStrings.Length) + { + UnlockAchievement("UnlockAllTowers"); + } + } + + public void BeatLevel(int level) + { + int gameMode = GameManager.instance.gameMode; + if (level == 15) + { + switch (gameMode) + { + case 1: + UnlockAchievement("BeatLevel15Mode1"); + break; + case 2: + UnlockAchievement("BeatLevel15Mode2"); + break; + case 3: + UnlockAchievement("BeatLevel15Mode3"); + break; + } + } + if (level == 25) + { + switch (gameMode) + { + case 1: + UnlockAchievement("BeatLevel25Mode1"); + break; + case 2: + UnlockAchievement("BeatLevel25Mode2"); + break; + case 3: + UnlockAchievement("BeatLevel25Mode3"); + break; + } + } + if (level == 35) + { + switch (gameMode) + { + case 1: + UnlockAchievement("BeatLevel35Mode1"); + break; + case 2: + UnlockAchievement("BeatLevel35Mode2"); + break; + case 3: + UnlockAchievement("BeatLevel35Mode3"); + break; + } + if (!shrineSpawned) + { + UnlockAchievement("NoShrines"); + } + } + if (level == 45) + { + switch (gameMode) + { + case 1: + UnlockAchievement("BeatLevel45Mode1"); + break; + case 2: + UnlockAchievement("BeatLevel45Mode2"); + break; + case 3: + UnlockAchievement("BeatLevel45Mode3"); + break; + } + } + } + + public void TowerLevel(int level) + { + switch (level) + { + case 10: + UnlockAchievement("TowerLevel10"); + break; + case 20: + UnlockAchievement("TowerLevel20"); + break; + case 50: + UnlockAchievement("TowerLevel50"); + break; + } + } + + public void CheckTowerTypesVictory() + { + int gameMode = GameManager.instance.gameMode; + if (TowerManager.instance.towersUsed.Contains(TowerType.Crossbow) && TowerManager.instance.towersUsed.Count <= 1) + { + UnlockAchievement("OnlyBallista"); + if (gameMode >= 2) + { + UnlockAchievement("OnlyBallista2"); + } + if (gameMode >= 3) + { + UnlockAchievement("OnlyBallista3"); + } + } + if (!TowerManager.instance.towersUsed.Contains(TowerType.Crossbow)) + { + UnlockAchievement("NoBallista"); + } + if ((TowerManager.instance.towersUsed.Contains(TowerType.Crossbow) && TowerManager.instance.towersUsed.Contains(TowerType.Morter) && TowerManager.instance.towersUsed.Count <= 2) || (TowerManager.instance.towersUsed.Contains(TowerType.Morter) && TowerManager.instance.towersUsed.Count <= 1)) + { + UnlockAchievement("OnlyBallistaMortar"); + if (gameMode >= 2) + { + UnlockAchievement("OnlyBallistaMortar2"); + } + if (gameMode >= 3) + { + UnlockAchievement("OnlyBallistaMortar3"); + } + } + if ((TowerManager.instance.towersUsed.Contains(TowerType.Crossbow) && TowerManager.instance.towersUsed.Contains(TowerType.TeslaCoil) && TowerManager.instance.towersUsed.Count <= 2) || (TowerManager.instance.towersUsed.Contains(TowerType.TeslaCoil) && TowerManager.instance.towersUsed.Count <= 1)) + { + UnlockAchievement("OnlyBallistaTesla"); + if (gameMode >= 2) + { + UnlockAchievement("OnlyBallistaTesla2"); + } + if (gameMode >= 3) + { + UnlockAchievement("OnlyBallistaTesla3"); + } + } + if ((TowerManager.instance.towersUsed.Contains(TowerType.Crossbow) && TowerManager.instance.towersUsed.Contains(TowerType.Frost) && TowerManager.instance.towersUsed.Count <= 2) || (TowerManager.instance.towersUsed.Contains(TowerType.Frost) && TowerManager.instance.towersUsed.Count <= 1)) + { + UnlockAchievement("OnlyBallistaFrost"); + if (gameMode >= 2) + { + UnlockAchievement("OnlyBallistaFrost2"); + } + if (gameMode >= 3) + { + UnlockAchievement("OnlyBallistaFrost3"); + } + } + if ((TowerManager.instance.towersUsed.Contains(TowerType.Crossbow) && TowerManager.instance.towersUsed.Contains(TowerType.FlameThrower) && TowerManager.instance.towersUsed.Count <= 2) || (TowerManager.instance.towersUsed.Contains(TowerType.FlameThrower) && TowerManager.instance.towersUsed.Count <= 1)) + { + UnlockAchievement("OnlyBallistaFlameThrower"); + if (gameMode >= 2) + { + UnlockAchievement("OnlyBallistaFlameThrower2"); + } + if (gameMode >= 3) + { + UnlockAchievement("OnlyBallistaFlameThrower3"); + } + } + if ((TowerManager.instance.towersUsed.Contains(TowerType.Crossbow) && TowerManager.instance.towersUsed.Contains(TowerType.PoisonSprayer) && TowerManager.instance.towersUsed.Count <= 2) || (TowerManager.instance.towersUsed.Contains(TowerType.PoisonSprayer) && TowerManager.instance.towersUsed.Count <= 1)) + { + UnlockAchievement("OnlyBallistaPoisonSprayer"); + if (gameMode >= 2) + { + UnlockAchievement("OnlyBallistaPoisonSprayer2"); + } + if (gameMode >= 3) + { + UnlockAchievement("OnlyBallistaPoisonSprayer3"); + } + } + if ((TowerManager.instance.towersUsed.Contains(TowerType.Crossbow) && TowerManager.instance.towersUsed.Contains(TowerType.Shredder) && TowerManager.instance.towersUsed.Count <= 2) || (TowerManager.instance.towersUsed.Contains(TowerType.Shredder) && TowerManager.instance.towersUsed.Count <= 1)) + { + UnlockAchievement("OnlyBallistaShredder"); + if (gameMode >= 2) + { + UnlockAchievement("OnlyBallistaShredder2"); + } + if (gameMode >= 3) + { + UnlockAchievement("OnlyBallistaShredder3"); + } + } + if ((TowerManager.instance.towersUsed.Contains(TowerType.Crossbow) && TowerManager.instance.towersUsed.Contains(TowerType.Encampment) && TowerManager.instance.towersUsed.Count <= 2) || (TowerManager.instance.towersUsed.Contains(TowerType.Encampment) && TowerManager.instance.towersUsed.Count <= 1)) + { + UnlockAchievement("OnlyBallistaEncampment"); + if (gameMode >= 2) + { + UnlockAchievement("OnlyBallistaEncampment2"); + } + if (gameMode >= 3) + { + UnlockAchievement("OnlyBallistaEncampment3"); + } + } + if ((TowerManager.instance.towersUsed.Contains(TowerType.Crossbow) && TowerManager.instance.towersUsed.Contains(TowerType.Lookout) && TowerManager.instance.towersUsed.Count <= 2) || (TowerManager.instance.towersUsed.Contains(TowerType.Lookout) && TowerManager.instance.towersUsed.Count <= 1)) + { + UnlockAchievement("OnlyBallistaLookout"); + if (gameMode >= 2) + { + UnlockAchievement("OnlyBallistaLookout2"); + } + if (gameMode >= 3) + { + UnlockAchievement("OnlyBallistaLookout3"); + } + } + if ((TowerManager.instance.towersUsed.Contains(TowerType.Crossbow) && TowerManager.instance.towersUsed.Contains(TowerType.Radar) && TowerManager.instance.towersUsed.Count <= 2) || (TowerManager.instance.towersUsed.Contains(TowerType.Radar) && TowerManager.instance.towersUsed.Count <= 1)) + { + UnlockAchievement("OnlyBallistaRadar"); + if (gameMode >= 2) + { + UnlockAchievement("OnlyBallistaRadar2"); + } + if (gameMode >= 3) + { + UnlockAchievement("OnlyBallistaRadar3"); + } + } + if ((TowerManager.instance.towersUsed.Contains(TowerType.Crossbow) && TowerManager.instance.towersUsed.Contains(TowerType.Obelisk) && TowerManager.instance.towersUsed.Count <= 2) || (TowerManager.instance.towersUsed.Contains(TowerType.Obelisk) && TowerManager.instance.towersUsed.Count <= 1)) + { + UnlockAchievement("OnlyBallistaObelisk"); + if (gameMode >= 2) + { + UnlockAchievement("OnlyBallistaObelisk2"); + } + if (gameMode >= 3) + { + UnlockAchievement("OnlyBallistaObelisk3"); + } + } + if ((TowerManager.instance.towersUsed.Contains(TowerType.Crossbow) && TowerManager.instance.towersUsed.Contains(TowerType.ParticleCannon) && TowerManager.instance.towersUsed.Count <= 2) || (TowerManager.instance.towersUsed.Contains(TowerType.ParticleCannon) && TowerManager.instance.towersUsed.Count <= 1)) + { + UnlockAchievement("OnlyBallistaParticleCannon"); + if (gameMode >= 2) + { + UnlockAchievement("OnlyBallistaParticleCannon2"); + } + if (gameMode >= 3) + { + UnlockAchievement("OnlyBallistaParticleCannon3"); + } + } + } + + public bool CheckAllTowers() + { + if (!TowerManager.instance.towersUsed.Contains(TowerType.Crossbow)) + { + return false; + } + if (!TowerManager.instance.towersUsed.Contains(TowerType.Morter)) + { + return false; + } + if (!TowerManager.instance.towersUsed.Contains(TowerType.TeslaCoil)) + { + return false; + } + if (!TowerManager.instance.towersUsed.Contains(TowerType.Frost)) + { + return false; + } + if (!TowerManager.instance.towersUsed.Contains(TowerType.FlameThrower)) + { + return false; + } + if (!TowerManager.instance.towersUsed.Contains(TowerType.PoisonSprayer)) + { + return false; + } + if (!TowerManager.instance.towersUsed.Contains(TowerType.Shredder)) + { + return false; + } + if (!TowerManager.instance.towersUsed.Contains(TowerType.Encampment)) + { + return false; + } + if (!TowerManager.instance.towersUsed.Contains(TowerType.Lookout)) + { + return false; + } + if (!TowerManager.instance.towersUsed.Contains(TowerType.Radar)) + { + return false; + } + if (!TowerManager.instance.towersUsed.Contains(TowerType.Obelisk)) + { + return false; + } + if (!TowerManager.instance.towersUsed.Contains(TowerType.ParticleCannon)) + { + return false; + } + UnlockAchievement("UsedAllTowers"); + return true; + } +} diff --git a/GameCode/AssemblyInfo.cs b/GameCode/AssemblyInfo.cs new file mode 100644 index 0000000..bbd7eef --- /dev/null +++ b/GameCode/AssemblyInfo.cs @@ -0,0 +1,5 @@ +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; + +[assembly: AssemblyVersion("0.0.0.0")] diff --git a/GameCode/AudioPoolSource.cs b/GameCode/AudioPoolSource.cs new file mode 100644 index 0000000..883151d --- /dev/null +++ b/GameCode/AudioPoolSource.cs @@ -0,0 +1,40 @@ +using UnityEngine; + +public class AudioPoolSource : MonoBehaviour +{ + [SerializeField] + private AudioSource audioS; + + private float timer = -1f; + + private bool active; + + public void PlayClip(AudioClip clip, float volume, float pitchVariance) + { + audioS.Stop(); + audioS.clip = clip; + audioS.pitch = 1f + Random.Range(0f - pitchVariance, pitchVariance); + audioS.volume = volume; + timer = clip.length + 0.1f; + active = true; + audioS.Play(); + } + + private void Update() + { + if (!active) + { + return; + } + timer -= Time.deltaTime; + if (timer <= 0f) + { + active = false; + if (base.transform.parent != null) + { + base.transform.parent = null; + } + SFXManager.instance.sources.Add(this); + } + } +} diff --git a/GameCode/BattleCry.cs b/GameCode/BattleCry.cs new file mode 100644 index 0000000..f76a756 --- /dev/null +++ b/GameCode/BattleCry.cs @@ -0,0 +1,84 @@ +using UnityEngine; + +public class BattleCry : MonoBehaviour +{ + public enum BattleCryTrigger + { + Death, + Spawn, + NearEnd, + ArmorBreak, + ShieldBreak + } + + [SerializeField] + private LayerMask enemyLayerMask; + + [SerializeField] + private string battleCryText = "Battle Cry!"; + + [SerializeField] + private float cryRadius; + + [SerializeField] + private BattleCryTrigger myTrigger; + + [SerializeField] + private float fortifyTime; + + [SerializeField] + private float hastePercentage; + + [SerializeField] + private GameObject[] enemiesToSpawn; + + private bool triggered; + + public void CheckBattleCry(BattleCryTrigger source) + { + if (source == myTrigger && !triggered) + { + Cry(); + } + } + + private void Cry() + { + if (enemiesToSpawn.Length != 0) + { + Waypoint currentWaypoint = GetComponent<Pathfinder>().currentWaypoint; + GameObject[] array = enemiesToSpawn; + for (int i = 0; i < array.Length; i++) + { + Enemy component = Object.Instantiate(array[i], base.transform.position + new Vector3(Random.Range(-0.5f, 0.5f), 0f, Random.Range(-0.5f, 0.5f)), Quaternion.identity).GetComponent<Enemy>(); + component.SetStats(); + component.SetFirstSpawnPoint(currentWaypoint); + SpawnManager.instance.currentEnemies.Add(component); + } + } + DamageNumber component2 = ObjectPool.instance.SpawnObject(ObjectPool.ObjectType.DamageNumber, base.transform.position, Quaternion.identity).GetComponent<DamageNumber>(); + component2.SetText(battleCryText, "Grey", 1f); + component2.SetHoldTime(2f); + if (myTrigger != 0) + { + component2.transform.parent = base.transform; + } + Collider[] array2 = Physics.OverlapSphere(base.transform.position, cryRadius, enemyLayerMask, QueryTriggerInteraction.Collide); + for (int i = 0; i < array2.Length; i++) + { + Enemy component3 = array2[i].GetComponent<Enemy>(); + if (component3 != null) + { + if (fortifyTime > 0f) + { + component3.Fortify(fortifyTime); + } + if (hastePercentage > 0f) + { + component3.AddHaste(hastePercentage); + } + } + } + triggered = true; + } +} diff --git a/GameCode/BiPlane.cs b/GameCode/BiPlane.cs new file mode 100644 index 0000000..bcf32e5 --- /dev/null +++ b/GameCode/BiPlane.cs @@ -0,0 +1,161 @@ +using UnityEngine; + +public class BiPlane : MonoBehaviour +{ + [SerializeField] + private TowerType towerType; + + [SerializeField] + private float speed; + + [SerializeField] + private float turnTime = 3f; + + [SerializeField] + private float minDistance = 3f; + + [SerializeField] + private float maxDistance = 12f; + + [SerializeField] + private float attackDistance = 6f; + + public GameObject target; + + private int directionMultiplier = 1; + + private Vector3 previousPos; + + private bool flyingTowards = true; + + private float desiredAltitude = 5f; + + private float desiredTilt; + + public int damage; + + public int healthDamage; + + public int armorDamage; + + public int shieldDamage; + + public float rps; + + public float slowPercent; + + public float bleedPercent; + + public float burnPercent; + + public float poisonPercent; + + public float critChance; + + public float stunChance; + + private int ammo; + + [SerializeField] + private int maxAmmo = 20; + + private float timeOfLastShot; + + [SerializeField] + private LayerMask bulletHitMask; + + [SerializeField] + private GameObject projectile; + + [SerializeField] + private float projectileSpeed; + + [SerializeField] + private Transform muzzle; + + [SerializeField] + private Transform artTransform; + + private void Start() + { + ammo = maxAmmo; + } + + private void Update() + { + FlightPath(); + } + + private void FixedUpdate() + { + } + + private void FlightPath() + { + Vector3 vector; + if (target != null) + { + vector = target.transform.position; + } + else + { + vector = Vector3.zero; + vector.y = 5f; + } + if (Vector3.SqrMagnitude(vector - base.transform.position) <= minDistance * minDistance) + { + flyingTowards = false; + Reload(); + } + else if (Vector3.SqrMagnitude(vector - base.transform.position) >= maxDistance * maxDistance) + { + flyingTowards = true; + } + float num = ((!flyingTowards) ? 0f : Vector2.SignedAngle(new Vector2(base.transform.forward.x, base.transform.forward.z), new Vector2(vector.x - base.transform.position.x, vector.z - base.transform.position.z))); + float num2; + if (target != null && flyingTowards && Vector3.SqrMagnitude(vector - base.transform.position) <= attackDistance * attackDistance) + { + desiredAltitude += (Mathf.Min(vector.y, 1f) - desiredAltitude) * Time.deltaTime * 1.5f; + num2 = base.transform.position.y - desiredAltitude; + if (Mathf.Abs(num) < 22.5f) + { + Fire(); + } + } + else + { + desiredAltitude += (5f - desiredAltitude) * Time.deltaTime * 3f; + num2 = base.transform.position.y - desiredAltitude; + } + num = Mathf.Clamp(num * 6f, -90f, 90f); + num2 = Mathf.Clamp(num2 * 6f, -45f, 45f); + base.transform.Rotate(new Vector3(0f, (0f - num) * Time.deltaTime / turnTime, 0f)); + base.transform.eulerAngles = new Vector3(num2, base.transform.eulerAngles.y, 0f); + base.transform.Translate(Vector3.forward * Time.deltaTime * speed); + desiredTilt += (num - desiredTilt) * Time.deltaTime; + artTransform.eulerAngles = new Vector3(base.transform.eulerAngles.x, base.transform.eulerAngles.y, desiredTilt); + } + + private void Reload() + { + ammo = maxAmmo; + } + + private void Fire() + { + if (ammo > 0 && timeOfLastShot + rps <= Time.time) + { + ammo--; + timeOfLastShot = Time.time; + LaunchProjectile(); + } + } + + private void LaunchProjectile() + { + Vector3 position = target.transform.position; + position += new Vector3(Random.Range(-0.33f, 0.33f) + Random.Range(-0.33f, 0.33f), Random.Range(-0.33f, 0.33f) + Random.Range(-0.33f, 0.33f), Random.Range(-0.33f, 0.33f) + Random.Range(-0.33f, 0.33f)); + muzzle.LookAt(position); + Object.Instantiate(projectile, muzzle.position, muzzle.rotation).GetComponent<Projectile>().SetStats(towerType, target, projectileSpeed, damage, healthDamage, armorDamage, shieldDamage, slowPercent, bleedPercent, burnPercent, poisonPercent, critChance, stunChance); + } +} diff --git a/GameCode/BuildButtonUI.cs b/GameCode/BuildButtonUI.cs new file mode 100644 index 0000000..86c7732 --- /dev/null +++ b/GameCode/BuildButtonUI.cs @@ -0,0 +1,107 @@ +using UnityEngine; +using UnityEngine.UI; + +public class BuildButtonUI : MonoBehaviour +{ + [SerializeField] + private GameObject tower; + + [SerializeField] + private TowerFlyweight towerFlyweight; + + [SerializeField] + private Text priceTag; + + [SerializeField] + private Text modifiersText; + + [SerializeField] + private TowerType myTowerType; + + private void Start() + { + priceTag.text = towerFlyweight.currentPrice + "g"; + UpdateModifiersText(); + } + + public void Build() + { + BuildingManager.instance.EnterBuildMode(tower, towerFlyweight.currentPrice, towerFlyweight.priceIncrease, myTowerType); + } + + public void UpdatePriceText() + { + priceTag.text = towerFlyweight.currentPrice + "g"; + } + + public void UpdateModifiersText() + { + if (!(modifiersText != null)) + { + return; + } + string text = ""; + if (TowerManager.instance.GetBonusBaseDamage(myTowerType) > 0) + { + text = text + "\n+" + TowerManager.instance.GetBonusBaseDamage(myTowerType) + " Base Damage"; + } + if (TowerManager.instance.GetBonusBaseDamage(myTowerType) < 0) + { + text = text + "\n" + TowerManager.instance.GetBonusBaseDamage(myTowerType) + " Base Damage"; + } + if (TowerManager.instance.GetBonusHealthDamage(myTowerType) > 0) + { + text = text + "\n+" + TowerManager.instance.GetBonusHealthDamage(myTowerType) + " Health Damage"; + } + if (TowerManager.instance.GetBonusArmorDamage(myTowerType) > 0) + { + text = text + "\n+" + TowerManager.instance.GetBonusArmorDamage(myTowerType) + " Armor Damage"; + } + if (TowerManager.instance.GetBonusShieldDamage(myTowerType) > 0) + { + text = text + "\n+" + TowerManager.instance.GetBonusShieldDamage(myTowerType) + " Shield Damage"; + } + if (TowerManager.instance.GetCritChance(myTowerType) + TowerManager.instance.GetCritChanceLevelMultiplier(myTowerType) > 0f) + { + text = text + "\n+(" + (int)(TowerManager.instance.GetCritChance(myTowerType) * 100f); + if (TowerManager.instance.GetCritChanceLevelMultiplier(myTowerType) > 1f) + { + text = text + " + " + (int)TowerManager.instance.GetCritChanceLevelMultiplier(myTowerType) + "xLvl"; + } + else if (TowerManager.instance.GetCritChanceLevelMultiplier(myTowerType) > 0f) + { + text += " + level"; + } + text += ")% Crit"; + } + if (TowerManager.instance.GetStunChance(myTowerType) > 0f) + { + text = text + "\n+" + Mathf.FloorToInt(TowerManager.instance.GetStunChance(myTowerType) * 101f) + "% Freeze Chance"; + } + if (TowerManager.instance.GetBonusRange(myTowerType) > 0f) + { + text = text + "\n+" + TowerManager.instance.GetBonusRange(myTowerType) + " Range"; + } + if (TowerManager.instance.GetBonusBlast(myTowerType) > 0f) + { + text = text + "\n+" + (int)(TowerManager.instance.GetBonusBlast(myTowerType) * 100f) + "% Blast Radius"; + } + if (TowerManager.instance.GetBonusSlow(myTowerType) > 0f) + { + text = text + "\n+" + (int)(TowerManager.instance.GetBonusSlow(myTowerType) * 100f) + "% Slow"; + } + if (TowerManager.instance.GetBonusBleed(myTowerType) > 0f) + { + text = text + "\n+" + (int)(TowerManager.instance.GetBonusBleed(myTowerType) * 100f) + "% Bleed"; + } + if (TowerManager.instance.GetBonusBurn(myTowerType) > 0f) + { + text = text + "\n+" + (int)(TowerManager.instance.GetBonusBurn(myTowerType) * 100f) + "% Burn"; + } + if (TowerManager.instance.GetBonusPoison(myTowerType) > 0f) + { + text = text + "\n+" + (int)(TowerManager.instance.GetBonusPoison(myTowerType) * 100f) + "% Poison"; + } + modifiersText.text = text; + } +} diff --git a/GameCode/BuildingGhost.cs b/GameCode/BuildingGhost.cs new file mode 100644 index 0000000..ea1db9f --- /dev/null +++ b/GameCode/BuildingGhost.cs @@ -0,0 +1,13 @@ +using UnityEngine; +using UnityEngine.UI; + +public class BuildingGhost : MonoBehaviour +{ + [SerializeField] + private Text text; + + public void SetText(string newText) + { + text.text = newText; + } +} diff --git a/GameCode/BuildingManager.cs b/GameCode/BuildingManager.cs new file mode 100644 index 0000000..4ace1ac --- /dev/null +++ b/GameCode/BuildingManager.cs @@ -0,0 +1,163 @@ +using UnityEngine; + +public class BuildingManager : MonoBehaviour +{ + public static BuildingManager instance; + + [SerializeField] + private GameObject buildingGhost; + + private GameObject currentGhost; + + [SerializeField] + private GameObject placementFXObject; + + [SerializeField] + public GameObject levelUpFX; + + [SerializeField] + private LayerMask buildableMask; + + private bool buildSpotAvailable; + + private GameObject thingToBuild; + + private int buildingCost; + + private int priceIncrease; + + private TowerType tType; + + public bool buildMode { get; private set; } + + private void Awake() + { + instance = this; + } + + private void Start() + { + buildMode = false; + } + + private void FixedUpdate() + { + if (buildMode) + { + buildSpotAvailable = SamplePoint(); + } + } + + private void Update() + { + if (!buildMode) + { + return; + } + if (Input.GetMouseButtonDown(0) && BuildingCheck()) + { + ResourceManager.instance.Spend(buildingCost); + DamageTracker.instance.AddCost(tType, buildingCost); + Build(); + if (!Input.GetKey(KeyCode.LeftShift)) + { + ExitBuildMode(); + } + else + { + buildingCost += priceIncrease; + } + } + if (Input.GetMouseButtonDown(1) || Input.GetKeyDown(KeyCode.Escape)) + { + ExitBuildMode(); + } + } + + public void EnterBuildMode(GameObject objectToBuild, int cost, int _priceIncrease, TowerType type) + { + buildMode = true; + thingToBuild = objectToBuild; + buildingCost = cost; + priceIncrease = _priceIncrease; + tType = type; + } + + private void ExitBuildMode() + { + HideGhost(); + buildMode = false; + } + + private void Build() + { + GameObject gameObject = Object.Instantiate(thingToBuild, currentGhost.transform.position, Quaternion.identity); + gameObject.GetComponent<IBuildable>()?.SetStats(); + Object.Instantiate(placementFXObject, gameObject.transform.position + Vector3.up * 0.333f, Quaternion.identity); + buildSpotAvailable = SamplePoint(); + } + + private bool BuildingCheck() + { + if (!PauseMenu.instance.paused && buildSpotAvailable && ResourceManager.instance.CheckMoney(buildingCost)) + { + return true; + } + if (!ResourceManager.instance.CheckMoney(buildingCost) && !PauseMenu.instance.paused && buildSpotAvailable) + { + DamageNumber component = ObjectPool.instance.SpawnObject(ObjectPool.ObjectType.DamageNumber, currentGhost.transform.position + Vector3.up, Quaternion.identity).GetComponent<DamageNumber>(); + component.SetText("Not enough gold", "Grey", 1f); + component.SetHoldTime(0.25f); + } + return false; + } + + private bool SamplePoint() + { + if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out var hitInfo, 2000f, buildableMask, QueryTriggerInteraction.Ignore)) + { + if (hitInfo.collider.gameObject.layer != LayerMask.NameToLayer("Grass")) + { + HideGhost(); + return false; + } + Vector3 vector = new Vector3(Mathf.Round(hitInfo.point.x), Mathf.Round(3f * hitInfo.point.y) / 3f, Mathf.Round(hitInfo.point.z)); + if (Vector3.SqrMagnitude(hitInfo.point - vector) < 0.25f) + { + string text = ""; + if (vector.y > 0.34f) + { + text = "+" + (Mathf.RoundToInt(vector.y * 3f) - 1); + } + DisplayGhost(vector, text); + return true; + } + HideGhost(); + return false; + } + HideGhost(); + return false; + } + + private void DisplayGhost(Vector3 pos, string text) + { + if (currentGhost == null) + { + currentGhost = Object.Instantiate(buildingGhost, pos, Quaternion.identity); + } + else + { + currentGhost.SetActive(value: true); + currentGhost.transform.position = pos; + } + currentGhost.GetComponent<BuildingGhost>().SetText(text); + } + + private void HideGhost() + { + if (currentGhost != null) + { + currentGhost.SetActive(value: false); + } + } +} diff --git a/GameCode/CameraController.cs b/GameCode/CameraController.cs new file mode 100644 index 0000000..2b91184 --- /dev/null +++ b/GameCode/CameraController.cs @@ -0,0 +1,96 @@ +using UnityEngine; + +public class CameraController : MonoBehaviour +{ + public static CameraController instance; + + [SerializeField] + private Vector3 velocity = Vector3.zero; + + [SerializeField] + private float cameraSpeed = 10f; + + [SerializeField] + private float cameraBaseZoom = 10f; + + [SerializeField] + private GameObject cameraHolder; + + [SerializeField] + private Transform audioListenerObject; + + [SerializeField] + private LayerMask zeroMask; + + private Vector3 clickMoveOrigin; + + private Vector3 cameraOrigin; + + private void Awake() + { + instance = this; + } + + private void Start() + { + Camera.main.orthographicSize = cameraBaseZoom; + if (audioListenerObject != null) + { + audioListenerObject.position = new Vector3(audioListenerObject.position.x, cameraBaseZoom, audioListenerObject.position.z); + } + } + + private void Update() + { + UpdateMovement(); + UpdateZoom(); + } + + private void UpdateMovement() + { + if (Input.GetKeyDown(KeyCode.C)) + { + base.transform.position = Vector3.zero; + } + if (Input.GetMouseButtonDown(1) && Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out var hitInfo, 2000f, zeroMask, QueryTriggerInteraction.Collide)) + { + clickMoveOrigin = hitInfo.point; + cameraOrigin = base.transform.position; + } + if (Input.GetMouseButton(1)) + { + if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out var hitInfo2, 2000f, zeroMask, QueryTriggerInteraction.Collide)) + { + Vector3 vector = cameraOrigin - 2f * (hitInfo2.point - clickMoveOrigin); + base.transform.position = (base.transform.position + vector) / 2f; + } + return; + } + if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) + { + velocity *= 1f - Time.deltaTime; + velocity += new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical")) * Time.deltaTime * 2f; + float num = Mathf.Clamp(Camera.main.orthographicSize / 10f, 1f, 5f); + base.transform.Translate(velocity * Time.deltaTime * cameraSpeed * num); + return; + } + velocity = Vector3.zero; + Vector3 vector2 = new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical")); + if (vector2.sqrMagnitude > 0.1f) + { + float num2 = Mathf.Clamp(Camera.main.orthographicSize / 10f, 1f, 5f); + base.transform.Translate(vector2.normalized * Time.deltaTime * cameraSpeed * num2); + } + } + + private void UpdateZoom() + { + float num = Mathf.Clamp(Camera.main.orthographicSize - Input.mouseScrollDelta.y, 1f, 50f); + Camera.main.orthographicSize = num; + cameraHolder.transform.localPosition = new Vector3(0f, 5f + 2f * num, -2f * num - 5f); + if (audioListenerObject != null) + { + audioListenerObject.position = new Vector3(audioListenerObject.position.x, (num + 10f) / 2f, audioListenerObject.position.z); + } + } +} diff --git a/GameCode/CardManager.cs b/GameCode/CardManager.cs new file mode 100644 index 0000000..08797d3 --- /dev/null +++ b/GameCode/CardManager.cs @@ -0,0 +1,177 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +public class CardManager : MonoBehaviour +{ + public static CardManager instance; + + private List<int> queuedDraws = new List<int>(); + + [SerializeField] + private int baseCardDraw = 3; + + [SerializeField] + private GameObject ui; + + [SerializeField] + private List<UpgradeCard> availableCards = new List<UpgradeCard>(); + + [SerializeField] + private List<UpgradeCard> startCardsCheck = new List<UpgradeCard>(); + + private UpgradeCard[] cards = new UpgradeCard[6]; + + [SerializeField] + private Text[] titles = new Text[6]; + + [SerializeField] + private Image[] images = new Image[6]; + + [SerializeField] + private Text[] descriptions = new Text[6]; + + [SerializeField] + private GameObject[] cardHolders = new GameObject[6]; + + public bool drawingCards { get; private set; } + + private void Awake() + { + instance = this; + } + + private void Start() + { + baseCardDraw = 3 + PlayerPrefs.GetInt("CardDraw1", 0) + PlayerPrefs.GetInt("CardDraw2", 0) + PlayerPrefs.GetInt("CardDraw3", 0); + foreach (UpgradeCard item in startCardsCheck) + { + if (item.unlocked) + { + availableCards.Add(item); + } + } + ArrangeCards(baseCardDraw); + } + + public void DrawCards() + { + DrawCards(baseCardDraw); + } + + public void DrawCards(int numb) + { + if (drawingCards) + { + Debug.Log("Queueing Draw call of " + numb); + queuedDraws.Add(numb); + return; + } + int num = numb; + if (availableCards.Count < num) + { + num = availableCards.Count; + if (num <= 0) + { + Debug.LogError("No cards to draw. (Only " + availableCards.Count + " available)"); + SpawnManager.instance.ShowSpawnUIs(state: true); + return; + } + } + ArrangeCards(num); + SFXManager.instance.PlaySound(Sound.Cards, MusicManager.instance.transform.position, MusicManager.instance.transform); + SpawnManager.instance.ShowSpawnUIs(state: false); + ui.SetActive(value: true); + drawingCards = true; + int[] array = new int[num]; + for (int i = 0; i < num; i++) + { + array[i] = -1; + } + for (int j = 0; j < num; j++) + { + int num2 = Random.Range(0, availableCards.Count); + int num3 = 0; + while (CheckArray(array, num2)) + { + num2 = Random.Range(0, availableCards.Count); + num3++; + if (num3 > 100) + { + Debug.LogError("Possible infinite loop in card selection"); + break; + } + } + array[j] = num2; + } + for (int k = 0; k < num; k++) + { + cards[k] = availableCards[array[k]]; + } + DisplayCards(num); + } + + private void ArrangeCards(int count) + { + for (int i = 0; i < count; i++) + { + cardHolders[i].SetActive(value: true); + } + for (int j = count; j < 6; j++) + { + cardHolders[j].SetActive(value: false); + } + for (int k = 0; k < count; k++) + { + cardHolders[k].transform.localPosition = new Vector3(200 * k - 100 * count + 100, 0f, 0f); + } + } + + private void DisplayCards(int count) + { + for (int i = 0; i < count; i++) + { + titles[i].text = cards[i].title; + images[i].sprite = cards[i].image; + descriptions[i].text = cards[i].description; + } + } + + public void ActivateCard(int index) + { + cards[index].Upgrade(); + foreach (UpgradeCard unlock in cards[index].unlocks) + { + if (unlock.unlocked) + { + availableCards.Add(unlock); + } + } + availableCards.Remove(cards[index]); + drawingCards = false; + if (queuedDraws.Count > 0) + { + int numb = queuedDraws[0]; + queuedDraws.RemoveAt(0); + DrawCards(numb); + return; + } + if (!SpawnManager.instance.combat) + { + SpawnManager.instance.ShowSpawnUIs(state: true); + } + ui.SetActive(value: false); + } + + private bool CheckArray(int[] array, int val) + { + for (int i = 0; i < array.Length; i++) + { + if (array[i] == val) + { + return true; + } + } + return false; + } +} diff --git a/GameCode/DOTUpgradeCard.cs b/GameCode/DOTUpgradeCard.cs new file mode 100644 index 0000000..e90b065 --- /dev/null +++ b/GameCode/DOTUpgradeCard.cs @@ -0,0 +1,109 @@ +using UnityEngine; +using UnityEngine.UI; + +public class DOTUpgradeCard : UpgradeCard +{ + [SerializeField] + private int bleedAmount; + + [SerializeField] + private int burnAmount; + + [SerializeField] + private int poisonAmount; + + [SerializeField] + private GameObject bleedUI; + + [SerializeField] + private GameObject burnUI; + + [SerializeField] + private GameObject poisonUI; + + [SerializeField] + private GameObject stunDmgUI; + + [SerializeField] + private Text bleedText; + + [SerializeField] + private Text burnText; + + [SerializeField] + private Text poisonText; + + [SerializeField] + private Text stunDmgText; + + [SerializeField] + private int bonusDamageOnBleed; + + [SerializeField] + private int bonusDamageOnBurn; + + [SerializeField] + private int bonusDamageOnPoison; + + [SerializeField] + private int bonusDamageOnStun; + + [SerializeField] + private float poisonSlowPercent; + + [SerializeField] + private float burnSpeedDamagePercentBonus; + + [SerializeField] + private float bleedingCritChance; + + [SerializeField] + private float bleedPop; + + [SerializeField] + private float burnPop; + + [SerializeField] + private float poisonPop; + + public override void Upgrade() + { + base.Upgrade(); + GameManager.instance.dotTick += new Vector3(bleedAmount, burnAmount, poisonAmount); + MonsterManager.instance.bonusDamageOnBleed += bonusDamageOnBleed; + MonsterManager.instance.bonusDamageOnBurn += bonusDamageOnBurn; + MonsterManager.instance.bonusDamageOnPoison += bonusDamageOnPoison; + MonsterManager.instance.bonusDamageOnStun += bonusDamageOnStun; + MonsterManager.instance.poisonSlowPercent += poisonSlowPercent; + MonsterManager.instance.burnSpeedDamagePercentBonus += burnSpeedDamagePercentBonus; + MonsterManager.instance.bleedingCritChance += bleedingCritChance; + MonsterManager.instance.bleedPop += bleedPop; + MonsterManager.instance.burnPop += burnPop; + MonsterManager.instance.poisonPop += poisonPop; + if (bleedAmount > 0 || bonusDamageOnBleed > 0) + { + bleedUI.SetActive(value: true); + bleedText.text = GameManager.instance.dotTick.x + " \n (+" + (1 + MonsterManager.instance.bonusDamageOnBleed) + ")"; + } + if (burnAmount > 0 || bonusDamageOnBurn > 0 || burnSpeedDamagePercentBonus > 0f) + { + burnUI.SetActive(value: true); + string text = GameManager.instance.dotTick.y + " \n (+" + (1 + MonsterManager.instance.bonusDamageOnBurn) + ")"; + if (MonsterManager.instance.burnSpeedDamagePercentBonus > 0f) + { + text = text + "\n" + Mathf.FloorToInt(0.01f + MonsterManager.instance.burnSpeedDamagePercentBonus) + "xSlow%"; + } + burnText.text = text; + } + if (poisonAmount > 0 || bonusDamageOnPoison > 0) + { + poisonUI.SetActive(value: true); + poisonText.text = GameManager.instance.dotTick.z + " \n (+" + (1 + MonsterManager.instance.bonusDamageOnPoison) + ")"; + } + if (bonusDamageOnStun > 0) + { + stunDmgUI.SetActive(value: true); + stunDmgText.text = "+" + MonsterManager.instance.bonusDamageOnStun; + } + } +} diff --git a/GameCode/DamageNumber.cs b/GameCode/DamageNumber.cs new file mode 100644 index 0000000..4355328 --- /dev/null +++ b/GameCode/DamageNumber.cs @@ -0,0 +1,138 @@ +using System.Collections; +using UnityEngine; +using UnityEngine.UI; + +public class DamageNumber : MonoBehaviour +{ + [SerializeField] + private Transform holder; + + [SerializeField] + private Text text; + + [SerializeField] + private int baseTextSize; + + [SerializeField] + private float zoom = 0.25f; + + private float hold = 0.5f; + + [SerializeField] + private float spin = 0.5f; + + [SerializeField] + private Color healthColor; + + [SerializeField] + private Color armorColor; + + [SerializeField] + private Color shieldColor; + + [SerializeField] + private Color greyColor; + + [SerializeField] + private Color greenColor; + + public void Start() + { + StartCoroutine(Bloop()); + } + + public void SetNumber(int num, string color, float fontScale) + { + text.fontSize = (int)((float)baseTextSize * fontScale); + text.text = num.ToString(); + switch (color) + { + case "Blue": + text.color = shieldColor; + break; + case "Yellow": + text.color = armorColor; + break; + case "Red": + text.color = healthColor; + break; + case "Grey": + text.color = greyColor; + break; + case "Green": + text.color = greenColor; + break; + } + } + + public void SetText(string _text, string color, float fontScale) + { + text.fontSize = (int)((float)baseTextSize * fontScale); + text.text = _text; + switch (color) + { + case "Blue": + text.color = shieldColor; + break; + case "Yellow": + text.color = armorColor; + break; + case "Red": + text.color = healthColor; + break; + case "Grey": + text.color = greyColor; + break; + case "Green": + text.color = greenColor; + break; + } + } + + public void SetHoldTime(float time) + { + hold = time; + } + + private IEnumerator Bloop() + { + Vector3 scale = Vector3.zero; + holder.localScale = scale; + holder.localPosition = new Vector3(-1.5f, 2.12132f, 1.5f); + text.rectTransform.localRotation = Quaternion.identity; + float t2 = zoom; + while (t2 > 0f) + { + scale += Vector3.one * (1f / zoom) * Time.deltaTime; + holder.localScale = scale; + t2 -= Time.deltaTime; + yield return null; + } + scale = Vector3.one; + holder.localScale = scale; + t2 = hold; + Vector3 direction = new Vector3(Random.Range(-1f, 1f), Random.Range(0f, 1f), 0f); + while (t2 > 0f) + { + holder.localPosition += direction * Time.deltaTime; + t2 -= Time.deltaTime; + yield return null; + } + t2 = spin; + int r = 1; + if (Random.Range(1f, 100f) <= 50f) + { + r = -1; + } + while (t2 > 0f) + { + holder.localPosition += direction * Time.deltaTime; + scale -= Vector3.one * (1f / spin) * Time.deltaTime; + holder.localScale = scale; + text.rectTransform.eulerAngles += r * 180 * Vector3.forward * Time.deltaTime / spin; + t2 -= Time.deltaTime; + yield return null; + } + ObjectPool.instance.PoolDamageNumber(base.gameObject); + } +} diff --git a/GameCode/DamageTracker.cs b/GameCode/DamageTracker.cs new file mode 100644 index 0000000..2d80e8f --- /dev/null +++ b/GameCode/DamageTracker.cs @@ -0,0 +1,101 @@ +using UnityEngine; +using UnityEngine.UI; + +public class DamageTracker : MonoBehaviour +{ + public enum IncomeType + { + Monster, + House, + Haunted, + Bonus + } + + public static DamageTracker instance; + + public GameObject uiObject; + + [SerializeField] + private Text healthDmg; + + [SerializeField] + private Text armorDmg; + + [SerializeField] + private Text shieldDmg; + + [SerializeField] + private Text totalDmg; + + [SerializeField] + private Text cost; + + [SerializeField] + private Text ratio; + + [SerializeField] + private Text incomeTotals; + + [SerializeField] + private Text incomePercent; + + private Vector3[] towerDamage = new Vector3[15]; + + private int[] towerCost = new int[15]; + + private int[] income = new int[4]; + + private void Awake() + { + instance = this; + } + + public void AddDamage(TowerType type, int healthDmg, int armorDmg, int shieldDmg) + { + towerDamage[(int)type].x += (float)healthDmg / 1000f; + towerDamage[(int)type].y += (float)armorDmg / 1000f; + towerDamage[(int)type].z += (float)shieldDmg / 1000f; + } + + public void AddCost(TowerType type, int gold) + { + towerCost[(int)type] += gold; + } + + public void AddIncome(IncomeType type, int gold) + { + income[(int)type] += gold; + } + + public void DisplayIncomeTotals() + { + float num = 0f; + for (int i = 0; i < income.Length; i++) + { + num += (float)income[i]; + } + num = Mathf.Max(num, 1f); + string text = "Gold Generated\n" + income[0] + "g\n" + income[1] + "g\n" + income[2] + "g\n" + income[3] + "g\n"; + incomeTotals.text = text; + string text2 = "Income Share\n" + Mathf.FloorToInt((float)(100 * income[0]) / num) + "%\n" + Mathf.FloorToInt((float)(100 * income[1]) / num) + "%\n" + Mathf.FloorToInt((float)(100 * income[2]) / num) + "%\n" + Mathf.FloorToInt((float)(100 * income[3]) / num) + "%\n"; + incomePercent.text = text2; + } + + public void DisplayDamageTotals() + { + uiObject.SetActive(value: true); + DisplayIncomeTotals(); + string text = "Health\n" + (int)towerDamage[0].x + "K\n" + (int)towerDamage[1].x + "K\n" + (int)towerDamage[2].x + "K\n" + (int)towerDamage[3].x + "K\n" + (int)towerDamage[5].x + "K\n" + (int)towerDamage[6].x + "K\n" + (int)towerDamage[12].x + "K\n" + (int)towerDamage[13].x + "K\n" + (int)towerDamage[14].x + "K\n" + (int)towerDamage[8].x + "K\n" + (int)towerDamage[4].x + "K\n" + (int)towerDamage[9].x + "K\n" + (int)towerDamage[10].x + "K\n"; + healthDmg.text = text; + string text2 = "Armor\n" + (int)towerDamage[0].y + "K\n" + (int)towerDamage[1].y + "K\n" + (int)towerDamage[2].y + "K\n" + (int)towerDamage[3].y + "K\n" + (int)towerDamage[5].y + "K\n" + (int)towerDamage[6].y + "K\n" + (int)towerDamage[12].y + "K\n" + (int)towerDamage[13].y + "K\n" + (int)towerDamage[14].y + "K\n" + (int)towerDamage[8].y + "K\n" + (int)towerDamage[4].y + "K\n" + (int)towerDamage[9].y + "K\n" + (int)towerDamage[10].y + "K\n"; + armorDmg.text = text2; + string text3 = "Shield\n" + (int)towerDamage[0].z + "K\n" + (int)towerDamage[1].z + "K\n" + (int)towerDamage[2].z + "K\n" + (int)towerDamage[3].z + "K\n" + (int)towerDamage[5].z + "K\n" + (int)towerDamage[6].z + "K\n" + (int)towerDamage[12].z + "K\n" + (int)towerDamage[13].z + "K\n" + (int)towerDamage[14].z + "K\n" + (int)towerDamage[8].z + "K\n" + (int)towerDamage[4].z + "K\n" + (int)towerDamage[9].z + "K\n" + (int)towerDamage[10].z + "K\n"; + shieldDmg.text = text3; + string text4 = "Total\n" + (int)(towerDamage[0].x + towerDamage[0].y + towerDamage[0].z) + "K\n" + (int)(towerDamage[1].x + towerDamage[1].y + towerDamage[1].z) + "K\n" + (int)(towerDamage[2].x + towerDamage[2].y + towerDamage[2].z) + "K\n" + (int)(towerDamage[3].x + towerDamage[3].y + towerDamage[3].z) + "K\n" + (int)(towerDamage[5].x + towerDamage[5].y + towerDamage[5].z) + "K\n" + (int)(towerDamage[6].x + towerDamage[6].y + towerDamage[6].z) + "K\n" + (int)(towerDamage[12].x + towerDamage[12].y + towerDamage[12].z) + "K\n" + (int)(towerDamage[13].x + towerDamage[13].y + towerDamage[13].z) + "K\n" + (int)(towerDamage[14].x + towerDamage[14].y + towerDamage[14].z) + "K\n" + (int)(towerDamage[8].x + towerDamage[8].y + towerDamage[8].z) + "K\n" + (int)(towerDamage[4].x + towerDamage[4].y + towerDamage[4].z) + "K\n" + (int)(towerDamage[9].x + towerDamage[9].y + towerDamage[9].z) + "K\n" + (int)(towerDamage[10].x + towerDamage[10].y + towerDamage[10].z) + "K\n"; + totalDmg.text = text4; + string text5 = "Cost\n" + towerCost[0] + "g\n" + towerCost[1] + "g\n" + towerCost[2] + "g\n" + towerCost[3] + "g\n" + towerCost[5] + "g\n" + towerCost[6] + "g\n" + towerCost[12] + "g\n" + towerCost[13] + "g\n" + towerCost[14] + "g\n" + towerCost[8] + "g\n" + towerCost[4] + "g\n" + towerCost[9] + "g\n"; + cost.text = text5; + string text6 = "Dmg/g\n" + (1000f * ((towerDamage[0].x + towerDamage[0].y + towerDamage[0].z) / (float)Mathf.Max(towerCost[0], 1))).ToString("F2") + "\n" + (1000f * ((towerDamage[1].x + towerDamage[1].y + towerDamage[1].z) / (float)Mathf.Max(towerCost[1], 1))).ToString("F2") + "\n" + (1000f * ((towerDamage[2].x + towerDamage[2].y + towerDamage[2].z) / (float)Mathf.Max(towerCost[2], 1))).ToString("F2") + "\n" + (1000f * ((towerDamage[3].x + towerDamage[3].y + towerDamage[3].z) / (float)Mathf.Max(towerCost[3], 1))).ToString("F2") + "\n" + (1000f * ((towerDamage[5].x + towerDamage[5].y + towerDamage[5].z) / (float)Mathf.Max(towerCost[5], 1))).ToString("F2") + "\n" + (1000f * ((towerDamage[6].x + towerDamage[6].y + towerDamage[6].z) / (float)Mathf.Max(towerCost[6], 1))).ToString("F2") + "\n" + (1000f * ((towerDamage[12].x + towerDamage[12].y + towerDamage[12].z) / (float)Mathf.Max(towerCost[12], 1))).ToString("F2") + "\n" + (1000f * ((towerDamage[13].x + towerDamage[13].y + towerDamage[13].z) / (float)Mathf.Max(towerCost[13], 1))).ToString("F2") + "\n" + (1000f * ((towerDamage[14].x + towerDamage[14].y + towerDamage[14].z) / (float)Mathf.Max(towerCost[14], 1))).ToString("F2") + "\n" + (1000f * ((towerDamage[8].x + towerDamage[8].y + towerDamage[8].z) / (float)Mathf.Max(towerCost[8], 1))).ToString("F2") + "\n" + (1000f * ((towerDamage[4].x + towerDamage[4].y + towerDamage[4].z) / (float)Mathf.Max(towerCost[4], 1))).ToString("F2") + "\n" + (1000f * ((towerDamage[9].x + towerDamage[9].y + towerDamage[9].z) / (float)Mathf.Max(towerCost[9], 1))).ToString("F2") + "\n"; + ratio.text = text6; + } +} diff --git a/GameCode/DevelopmentManager.cs b/GameCode/DevelopmentManager.cs new file mode 100644 index 0000000..7caec25 --- /dev/null +++ b/GameCode/DevelopmentManager.cs @@ -0,0 +1,23 @@ +using UnityEngine; + +public class DevelopmentManager : MonoBehaviour +{ + [SerializeField] + private GameObject[] startingDevelopments; + + private float developmentPercent; + + private void Start() + { + developmentPercent = PlayerPrefs.GetInt("UnlockedCardCount", 0) + PlayerPrefs.GetInt("Development", 0); + developmentPercent *= 0.4f; + GameObject[] array = startingDevelopments; + foreach (GameObject obj in array) + { + if (Random.Range(0f, 100f) > developmentPercent) + { + Object.Destroy(obj); + } + } + } +} diff --git a/GameCode/Dropper.cs b/GameCode/Dropper.cs new file mode 100644 index 0000000..0dc7a10 --- /dev/null +++ b/GameCode/Dropper.cs @@ -0,0 +1,126 @@ +using System.Collections.Generic; +using UnityEngine; + +public class Dropper : Tower +{ + [SerializeField] + private int manaPerSecond; + + [SerializeField] + private float dropHeight = 3f; + + [SerializeField] + private LayerMask dropSetMask; + + [SerializeField] + protected Vector2[] dropPoints; + + [SerializeField] + private bool requireTargetToDrop; + + private int currentLevel; + + public float dropperRPMdisplay; + + private float timeOfNextManaCheck; + + private bool canFire = true; + + protected override void Start() + { + base.Start(); + SetDropPoints(); + } + + public override void SetStats() + { + base.SetStats(); + rps = 60f / rpm * (10f / (10f + (float)dropPoints.Length)); + dropperRPMdisplay = rpm * (10f + (float)dropPoints.Length) / 10f; + } + + private void SetDropPoints() + { + List<Vector2> list = new List<Vector2>(); + for (int i = -(int)base.range; (float)i <= base.range; i++) + { + for (int j = -(int)base.range; (float)j <= base.range; j++) + { + if (Physics.Raycast(new Vector3(base.transform.position.x + (float)i, dropHeight, base.transform.position.z + (float)j), Vector3.down, out var hitInfo, 1.5f * dropHeight, dropSetMask, QueryTriggerInteraction.Ignore) && hitInfo.transform.gameObject.layer == LayerMask.NameToLayer("Path")) + { + list.Add(new Vector2(i, j)); + } + } + } + dropPoints = list.ToArray(); + rps = 60f / rpm * (10f / (10f + (float)dropPoints.Length)); + dropperRPMdisplay = rpm * (10f + (float)dropPoints.Length) / 10f; + } + + protected override void Update() + { + if (SpawnManager.instance.level != currentLevel) + { + SetDropPoints(); + currentLevel = SpawnManager.instance.level; + } + if (currentTarget != null) + { + if (turret != null) + { + AimTurret(); + } + GainXP(); + } + if (manaPerSecond > 0 && Time.time >= timeOfNextManaCheck && SpawnManager.instance.combat) + { + timeOfNextManaCheck = Time.time + 1f; + if (ResourceManager.instance.CheckMana(manaPerSecond)) + { + ResourceManager.instance.SpendMana(manaPerSecond); + canFire = true; + } + else + { + canFire = false; + } + } + timeSinceLastShot += Time.deltaTime; + if (canFire && TargetingCheck() && timeSinceLastShot > rps && SpawnManager.instance.combat) + { + Fire(); + timeSinceLastShot = 0f; + } + } + + private bool TargetingCheck() + { + if (requireTargetToDrop) + { + if (currentTarget != null) + { + return true; + } + return false; + } + return true; + } + + protected override void Fire() + { + if (consumesMana) + { + int manaCost = (int)((float)base.damage * manaConsumptionRate); + if (!ResourceManager.instance.CheckMana(manaCost)) + { + return; + } + ResourceManager.instance.SpendMana(manaCost); + } + if (dropPoints.Length != 0) + { + Vector2 vector = dropPoints[Random.Range(0, dropPoints.Length)]; + Object.Instantiate(projectile, new Vector3(vector.x, dropHeight, vector.y) + base.transform.position, Quaternion.identity).GetComponent<Projectile>().SetStats(towerType, null, projectileSpeed, base.damage, base.healthDamage, base.armorDamage, base.shieldDamage, base.slowPercent, base.bleedPercent, base.burnPercent, base.poisonPercent, base.critChance, base.stunChance); + } + } +} diff --git a/GameCode/Encampment.cs b/GameCode/Encampment.cs new file mode 100644 index 0000000..eaa8ab7 --- /dev/null +++ b/GameCode/Encampment.cs @@ -0,0 +1,26 @@ +using UnityEngine; + +public class Encampment : Dropper +{ + protected override void Fire() + { + if (consumesMana) + { + int manaCost = (int)((float)base.damage * manaConsumptionRate); + if (!ResourceManager.instance.CheckMana(manaCost)) + { + return; + } + ResourceManager.instance.SpendMana(manaCost); + } + if (dropPoints.Length != 0) + { + Vector2 vector = dropPoints[Random.Range(0, dropPoints.Length)]; + Vector3 endPosition = new Vector3(vector.x + Random.Range(-0.125f, 0.125f) + base.transform.position.x, 0f, vector.y + Random.Range(-0.125f, 0.125f) + base.transform.position.z); + GameObject obj = Object.Instantiate(projectile, base.transform.position, Quaternion.identity); + obj.GetComponent<Projectile>().SetStats(towerType, null, projectileSpeed, base.damage, base.healthDamage, base.armorDamage, base.shieldDamage, base.slowPercent, base.bleedPercent, base.burnPercent, base.poisonPercent, base.critChance, base.stunChance); + obj.GetComponent<Landmine>().blastRadius = base.blastRadius; + obj.GetComponent<Landmine>().SetEndPosition(endPosition); + } + } +} diff --git a/GameCode/Enemy.cs b/GameCode/Enemy.cs new file mode 100644 index 0000000..2e7ce7d --- /dev/null +++ b/GameCode/Enemy.cs @@ -0,0 +1,669 @@ +using System.Collections.Generic; +using UnityEngine; + +public class Enemy : MonoBehaviour, IDamageable +{ + [SerializeField] + private Renderer renderer; + + [SerializeField] + private Pathfinder pathfinder; + + [SerializeField] + private HealthBar healthBar; + + [SerializeField] + private GameObject deathObjectSpawn; + + [SerializeField] + private BattleCry[] battleCries; + + [SerializeField] + private GameObject treasureObject; + + [SerializeField] + private Vector2 spawnRange; + + public int level = 1; + + [SerializeField] + private int damageToTower = 1; + + [SerializeField] + private int bonusGoldDrop; + + [SerializeField] + private bool dropsGold = true; + + [SerializeField] + private int hpScaleDegree = 1; + + public int baseHealth; + + public int baseArmor; + + public int baseShield; + + public float baseSpeed; + + public int healthRegen; + + public int armorRegen; + + public int shieldRegen; + + private float timeSinceRegen; + + private float currentSpeed; + + private float currentSlowPercentage; + + private float hastePercentage; + + private float freezeTime; + + private float fortifiedTime; + + private bool fortified; + + private int bleed; + + private int burn; + + private int poison; + + private bool bleeding; + + private bool burning; + + private bool poisoned; + + private float timeSinceBleed; + + private float timeSinceBurn; + + private float timeSincePoison; + + private float dotTick; + + private HashSet<TowerType> typesOfTowers = new HashSet<TowerType>(); + + public Lookout mark; + + private bool dead; + + public int health { get; private set; } + + public int armor { get; private set; } + + public int shield { get; private set; } + + private void Start() + { + CheckBattleCries(BattleCry.BattleCryTrigger.Spawn); + healthBar.UpdateFortified(fortifiedTime); + healthBar.UpdateHaste(hastePercentage); + if (bonusGoldDrop == 0) + { + bonusGoldDrop = ResourceManager.instance.enemyBonusGoldDrop; + } + else + { + bonusGoldDrop += ResourceManager.instance.enemyBonusGoldDrop; + } + } + + public void SetStats() + { + health = baseHealth; + armor = baseArmor; + shield = baseShield; + currentSpeed = baseSpeed + MonsterManager.instance.speedBonus; + pathfinder.speed = currentSpeed; + healthBar.SetHealth(health + armor + shield, health, armor, shield, hpScaleDegree); + } + + public void SetFirstSpawnPoint(Waypoint point) + { + pathfinder.currentWaypoint = point; + } + + private void Update() + { + if (fortifiedTime > 0f) + { + FortifiedUpdate(); + } + if (currentSlowPercentage > 0f || hastePercentage > 0f || freezeTime > 0f) + { + SpeedUpdate(); + } + DOTUpdate(); + RegenUpdate(); + } + + private void SpeedUpdate() + { + float num = freezeTime; + freezeTime = Mathf.Max(0f, freezeTime - Time.deltaTime); + currentSlowPercentage = Mathf.Max(0f, currentSlowPercentage - Time.deltaTime * 0.05f); + hastePercentage = Mathf.Max(0f, hastePercentage - Time.deltaTime * 0.05f); + if (freezeTime > 0f) + { + currentSpeed = 0f; + } + else + { + currentSpeed = (baseSpeed + MonsterManager.instance.speedBonus) * (1f - currentSlowPercentage + hastePercentage); + } + pathfinder.speed = currentSpeed; + if (freezeTime <= 0f && num > 0f && renderer != null) + { + renderer.material.color = Color.white; + } + healthBar.UpdateSlow(currentSlowPercentage); + healthBar.UpdateHaste(hastePercentage); + } + + public void CheckBattleCries(BattleCry.BattleCryTrigger cryType) + { + if (battleCries.Length != 0) + { + BattleCry[] array = battleCries; + for (int i = 0; i < array.Length; i++) + { + array[i].CheckBattleCry(cryType); + } + } + } + + private void AddSlow(float newPercentage) + { + currentSlowPercentage = Mathf.Clamp(currentSlowPercentage + newPercentage, 0f, 0.6f + MonsterManager.instance.slowCapModifier); + } + + public void AddHaste(float amount) + { + hastePercentage = Mathf.Clamp(hastePercentage + amount, 0f, 0.6f + MonsterManager.instance.hasteCapModifier); + if (OptionsMenu.instance.showConditionText) + { + DamageNumber component = ObjectPool.instance.SpawnObject(ObjectPool.ObjectType.DamageNumber, base.transform.position, Quaternion.identity).GetComponent<DamageNumber>(); + component.SetText("HASTED", "Grey", 1f); + component.SetHoldTime(0.5f); + } + } + + public void Freeze() + { + freezeTime = 1f; + if (renderer != null) + { + renderer.material.color = Color.blue; + } + if (OptionsMenu.instance.showConditionText) + { + DamageNumber component = ObjectPool.instance.SpawnObject(ObjectPool.ObjectType.DamageNumber, base.transform.position, Quaternion.identity).GetComponent<DamageNumber>(); + component.SetText("FROZEN", "Grey", 1f); + component.SetHoldTime(0.5f); + } + } + + private void FortifiedUpdate() + { + fortifiedTime = Mathf.Max(fortifiedTime - Time.deltaTime, 0f); + if (fortifiedTime <= 0f) + { + fortified = false; + } + healthBar.UpdateFortified(fortifiedTime); + } + + public void Fortify(float time) + { + fortifiedTime = Mathf.Clamp(fortifiedTime + time, 0f, 12f); + healthBar.UpdateFortified(fortifiedTime); + fortified = true; + if (OptionsMenu.instance.showConditionText) + { + DamageNumber component = ObjectPool.instance.SpawnObject(ObjectPool.ObjectType.DamageNumber, base.transform.position, Quaternion.identity).GetComponent<DamageNumber>(); + component.SetText("FORTIFIED", "Grey", 1f); + component.SetHoldTime(0.5f); + } + } + + private void RegenUpdate() + { + if (timeSinceRegen >= 1f) + { + if (healthRegen > 0 && health > 0) + { + HealHealth(healthRegen); + } + if (armorRegen > 0 && armor > 0) + { + HealArmor(armorRegen); + } + if (shieldRegen > 0 && shield > 0) + { + HealShield(shieldRegen); + } + timeSinceRegen = 0f; + } + else + { + timeSinceRegen += Time.deltaTime; + } + } + + private void HealHealth(int amount) + { + if (health >= baseHealth || bleeding) + { + if (bleeding) + { + DamageTracker.instance.AddDamage(TowerType.DOT, amount, 0, 0); + } + return; + } + if (health + amount >= baseHealth) + { + if (OptionsMenu.instance.showDamageNumbers) + { + DamageNumber component = ObjectPool.instance.SpawnObject(ObjectPool.ObjectType.DamageNumber, base.transform.position, Quaternion.identity).GetComponent<DamageNumber>(); + component.SetText("+" + (baseHealth - health), "Green", 1f); + component.SetHoldTime(0.5f); + } + health = baseHealth; + } + else + { + health += amount; + if (OptionsMenu.instance.showDamageNumbers) + { + DamageNumber component2 = ObjectPool.instance.SpawnObject(ObjectPool.ObjectType.DamageNumber, base.transform.position, Quaternion.identity).GetComponent<DamageNumber>(); + component2.SetText("+" + amount, "Green", 1f); + component2.SetHoldTime(0.5f); + } + } + if (healthBar != null) + { + healthBar.UpdateHealth(health, armor, shield, currentSlowPercentage, bleeding, burning, poisoned, bleed, burn, poison); + } + } + + private void HealArmor(int amount) + { + if (armor >= baseArmor || burning) + { + if (burning) + { + DamageTracker.instance.AddDamage(TowerType.DOT, 0, amount, 0); + } + return; + } + if (armor + amount >= baseArmor) + { + if (OptionsMenu.instance.showDamageNumbers) + { + DamageNumber component = ObjectPool.instance.SpawnObject(ObjectPool.ObjectType.DamageNumber, base.transform.position, Quaternion.identity).GetComponent<DamageNumber>(); + component.SetText("+" + (baseArmor - armor), "Yellow", 1f); + component.SetHoldTime(0.5f); + } + armor = baseArmor; + } + else + { + armor += amount; + if (OptionsMenu.instance.showDamageNumbers) + { + DamageNumber component2 = ObjectPool.instance.SpawnObject(ObjectPool.ObjectType.DamageNumber, base.transform.position, Quaternion.identity).GetComponent<DamageNumber>(); + component2.SetText("+" + amount, "Yellow", 1f); + component2.SetHoldTime(0.5f); + } + } + if (healthBar != null) + { + healthBar.UpdateHealth(health, armor, shield, currentSlowPercentage, bleeding, burning, poisoned, bleed, burn, poison); + } + } + + private void HealShield(int amount) + { + if (shield >= baseShield || poisoned) + { + if (poisoned) + { + DamageTracker.instance.AddDamage(TowerType.DOT, 0, 0, amount); + } + return; + } + if (shield + amount >= baseShield) + { + if (OptionsMenu.instance.showDamageNumbers) + { + DamageNumber component = ObjectPool.instance.SpawnObject(ObjectPool.ObjectType.DamageNumber, base.transform.position, Quaternion.identity).GetComponent<DamageNumber>(); + component.SetText("+" + (baseShield - shield), "Blue", 1f); + component.SetHoldTime(0.5f); + } + shield = baseShield; + } + else + { + shield += amount; + if (OptionsMenu.instance.showDamageNumbers) + { + DamageNumber component2 = ObjectPool.instance.SpawnObject(ObjectPool.ObjectType.DamageNumber, base.transform.position, Quaternion.identity).GetComponent<DamageNumber>(); + component2.SetText("+" + amount, "Blue", 1f); + component2.SetHoldTime(0.5f); + } + } + if (healthBar != null) + { + healthBar.UpdateHealth(health, armor, shield, currentSlowPercentage, bleeding, burning, poisoned, bleed, burn, poison); + } + } + + private void DOTUpdate() + { + if (!dead) + { + BleedCheck(); + BurnCheck(); + PoisonCheck(); + if (poisoned && timeSincePoison <= 0f && dotTick <= 0f) + { + int num = poison; + poison = Mathf.Max(poison - (int)GameManager.instance.dotTick.z, 0); + num -= poison; + int num2 = Mathf.Max(num / 2, 1); + TakeDamage(TowerType.DOT, -999, num2, num2, num, 0f, 0f, 0f, 0f, 0f, 0f); + timeSincePoison = 1f; + dotTick = 0.1f; + } + if (burning && timeSinceBurn <= 0f && dotTick <= 0f) + { + int num3 = burn; + burn = Mathf.Max(burn - (int)(GameManager.instance.dotTick.y * Mathf.Max(1f + MonsterManager.instance.burnSpeedDamagePercentBonus * currentSlowPercentage, 1f)), 0); + num3 -= burn; + int num4 = num3 / 2; + TakeDamage(TowerType.DOT, -999, num4, num3, num4, 0f, 0f, 0f, 0f, 0f, 0f); + timeSinceBurn = 1f; + dotTick = 0.1f; + } + if (bleeding && timeSinceBleed <= 0f && dotTick <= 0f) + { + int num5 = bleed; + bleed = Mathf.Max(bleed - (int)GameManager.instance.dotTick.x, 0); + num5 -= bleed; + int num6 = num5 / 2; + TakeDamage(TowerType.DOT, -999, num5, num6, num6, 0f, 0f, 0f, 0f, 0f, 0f); + timeSinceBleed = 1f; + dotTick = 0.1f; + } + timeSinceBleed -= Time.deltaTime; + timeSinceBurn -= Time.deltaTime; + timeSincePoison -= Time.deltaTime; + dotTick -= Time.deltaTime; + healthBar.UpdateBleed(bleeding, bleed); + healthBar.UpdateBurn(burning, burn); + healthBar.UpdatePoison(poisoned, poison); + } + } + + private int FortifiedCheck() + { + if (fortified) + { + return 5; + } + return 0; + } + + private int BleedCheck() + { + if (bleed > 0) + { + bleeding = true; + return 1 + MonsterManager.instance.bonusDamageOnBleed; + } + bleeding = false; + return 0; + } + + private int BurnCheck() + { + if (burn > 0) + { + burning = true; + return 1 + MonsterManager.instance.bonusDamageOnBurn; + } + burning = false; + return 0; + } + + private int PoisonCheck() + { + if (poison > 0) + { + poisoned = true; + return 1 + MonsterManager.instance.bonusDamageOnPoison; + } + poisoned = false; + return 0; + } + + private int FreezeDmgCheck() + { + if (freezeTime > 0f) + { + return MonsterManager.instance.bonusDamageOnStun; + } + return 0; + } + + public float CurrentHealth() + { + return (float)(health + armor + shield) / (float)(baseHealth + baseArmor + baseShield); + } + + public void TakeDamage(TowerType whoHitMe, int _baseDmg, int healthDmg, int armorDmg, int shieldDmg, float slowPercentage, float bleedPercentage, float burnPercentage, float poisonPercentage, float critChance, float stunChance) + { + if (dead) + { + Debug.Log("Dead enemy taking damage"); + return; + } + typesOfTowers.Add(whoHitMe); + if (Random.Range(0f, 1f) < stunChance) + { + Freeze(); + } + float num = critChance; + if (_baseDmg > -1 && BleedCheck() > 0) + { + num += MonsterManager.instance.bleedingCritChance; + if (mark != null) + { + num += mark.critChance; + } + } + int num2 = _baseDmg; + string text = ""; + float num3 = 1f; + if (Random.Range(0f, 1f) < Mathf.Min(num - 1f, 0.5f)) + { + num2 *= 4; + text = "!!!"; + num3 = 2.5f; + SFXManager.instance.PlaySound(Sound.CritBig, base.transform.position); + } + else if (Random.Range(0f, 1f) < Mathf.Min(num - 0.5f, 0.5f)) + { + num2 *= 3; + text = "!!"; + num3 = 2f; + SFXManager.instance.PlaySound(Sound.CritBig, base.transform.position); + } + else if (Random.Range(0f, 1f) < Mathf.Min(num, 0.5f)) + { + num2 *= 2; + text = "!"; + num3 = 1.5f; + SFXManager.instance.PlaySound(Sound.CritBig, base.transform.position); + } + int num4 = 0; + int num5 = 0; + string color; + if (shield > 0) + { + num4 = Mathf.Max(num2 - FortifiedCheck() + (int)MarkCheck().x + FreezeDmgCheck(), 1) * (shieldDmg + PoisonCheck() + (int)MarkCheck().w); + if (num4 > shield) + { + num5 = (int)((float)(num4 - shield) / (float)shieldDmg); + } + shield -= num4; + color = "Blue"; + DamageTracker.instance.AddDamage(whoHitMe, 0, 0, num4); + shield = Mathf.Max(shield, 0); + if (shield == 0) + { + CheckBattleCries(BattleCry.BattleCryTrigger.ShieldBreak); + } + } + else if (armor > 0) + { + num4 = Mathf.Max(num2 - FortifiedCheck() + (int)MarkCheck().x + FreezeDmgCheck(), 1) * (armorDmg + BurnCheck() + (int)MarkCheck().z); + if (num4 > armor) + { + num5 = (int)((float)(num4 - armor) / (float)armorDmg); + } + armor -= num4; + color = "Yellow"; + DamageTracker.instance.AddDamage(whoHitMe, 0, num4, 0); + armor = Mathf.Max(armor, 0); + if (armor == 0) + { + CheckBattleCries(BattleCry.BattleCryTrigger.ArmorBreak); + } + } + else + { + num4 = Mathf.Max(num2 - FortifiedCheck() + (int)MarkCheck().x + FreezeDmgCheck(), 1) * (healthDmg + BleedCheck() + (int)MarkCheck().y); + if (num4 >= health) + { + DamageTracker.instance.AddDamage(whoHitMe, health, 0, 0); + } + else + { + DamageTracker.instance.AddDamage(whoHitMe, num4, 0, 0); + } + health -= num4; + color = "Red"; + } + if (OptionsMenu.instance.showDamageNumbers) + { + DamageNumber component = ObjectPool.instance.SpawnObject(ObjectPool.ObjectType.DamageNumber, base.transform.position, Quaternion.identity).GetComponent<DamageNumber>(); + component.SetText(num4 + text, color, num3); + component.SetHoldTime(0.25f); + } + if (health <= 0) + { + Die(); + return; + } + bleed += (int)((float)num4 * bleedPercentage); + burn += (int)((float)num4 * burnPercentage); + poison += (int)((float)num4 * poisonPercentage); + if (slowPercentage > 0f) + { + AddSlow((float)num4 * slowPercentage / 100f); + } + if (poisonPercentage > 0f) + { + AddSlow(MonsterManager.instance.poisonSlowPercent * poisonPercentage * (float)num4 / 100f); + } + if (num3 > 1f && _baseDmg > -1 && MonsterManager.instance.bleedPop > 0f && !dead) + { + int num6 = (int)((float)bleed * MonsterManager.instance.bleedPop); + bleed -= num6; + TakeDamage(TowerType.DOT, -999, num6, num6 / 2, num6 / 2, 0f, 0f, 0f, 0f, 0f, 0f); + } + if (num3 > 1f && _baseDmg > -1 && MonsterManager.instance.burnPop > 0f && !dead) + { + int num7 = (int)((float)burn * MonsterManager.instance.burnPop); + burn -= num7; + TakeDamage(TowerType.DOT, -999, num7 / 2, num7, num7 / 2, 0f, 0f, 0f, 0f, 0f, 0f); + } + if (num3 > 1f && _baseDmg > -1 && MonsterManager.instance.poisonPop > 0f && !dead) + { + int num8 = (int)((float)poison * MonsterManager.instance.poisonPop); + poison -= num8; + TakeDamage(TowerType.DOT, -999, num8 / 2, num8 / 2, num8, 0f, 0f, 0f, 0f, 0f, 0f); + } + if (healthBar != null) + { + healthBar.UpdateHealth(health, armor, shield, currentSlowPercentage, bleeding, burning, poisoned, bleed, burn, poison); + } + if (num5 > 0 && !dead) + { + TakeDamage(whoHitMe, num5, healthDmg, armorDmg, shieldDmg, slowPercentage, bleedPercentage, burnPercentage, poisonPercentage, 0f, 0f); + } + } + + private Vector4 MarkCheck() + { + Vector4 zero = Vector4.zero; + if (mark != null) + { + zero.x = mark.damage; + zero.y = mark.healthDamage; + zero.z = mark.armorDamage; + zero.w = mark.shieldDamage; + } + return zero; + } + + public Vector3 GetFuturePosition(float t) + { + float distance = currentSpeed * t; + return pathfinder.GetFuturePosition(distance); + } + + public void AtEnd() + { + GameManager.instance.TakeDamage(damageToTower + MonsterManager.instance.extraTowerDamage); + SpawnManager.instance.currentEnemies.Remove(this); + Object.Destroy(base.gameObject); + } + + private void Die() + { + if (!dead) + { + dead = true; + if (deathObjectSpawn != null) + { + Object.Instantiate(deathObjectSpawn, base.transform.position, Quaternion.identity); + } + if (treasureObject != null && spawnRange.y > 0f) + { + int numberOfDrops = Random.Range((int)spawnRange.x, (int)spawnRange.y + GameManager.instance.gameMode); + Object.Instantiate(treasureObject, base.transform.position, Quaternion.identity).GetComponent<TreasureChest>().numberOfDrops = numberOfDrops; + } + CheckBattleCries(BattleCry.BattleCryTrigger.Death); + typesOfTowers.Remove(TowerType.DOT); + if (dropsGold) + { + int num = level + typesOfTowers.Count + bonusGoldDrop + MonsterManager.instance.extraGoldDrop; + ResourceManager.instance.AddMoney(num); + ResourceManager.instance.AddManaPercentMax(MonsterManager.instance.manaDropOnDeath); + DamageTracker.instance.AddIncome(DamageTracker.IncomeType.Monster, num - MonsterManager.instance.extraGoldDrop); + DamageTracker.instance.AddIncome(DamageTracker.IncomeType.Bonus, MonsterManager.instance.extraGoldDrop); + } + SpawnManager.instance.currentEnemies.Remove(this); + SFXManager.instance.PlaySound(Sound.CoinLong, base.transform.position); + AchievementManager.instance.EnemyKilled(); + Object.Destroy(base.gameObject); + } + } +} diff --git a/GameCode/Explosion.cs b/GameCode/Explosion.cs new file mode 100644 index 0000000..a01aa17 --- /dev/null +++ b/GameCode/Explosion.cs @@ -0,0 +1,27 @@ +using UnityEngine; + +public class Explosion : MonoBehaviour +{ + [SerializeField] + private float duration = 2f; + + [SerializeField] + private Sound sound; + + private void Start() + { + if (sound != 0) + { + SFXManager.instance.PlaySound(sound, base.transform.position); + } + } + + private void FixedUpdate() + { + duration -= Time.fixedDeltaTime; + if (duration <= 0f) + { + Object.Destroy(base.gameObject); + } + } +} diff --git a/GameCode/FlameThrower.cs b/GameCode/FlameThrower.cs new file mode 100644 index 0000000..d415d88 --- /dev/null +++ b/GameCode/FlameThrower.cs @@ -0,0 +1,68 @@ +using UnityEngine; + +public class FlameThrower : Tower +{ + [SerializeField] + private ParticleSystem flames; + + public bool flaming; + + private bool hasMana = true; + + [SerializeField] + private AudioSource audioS; + + private bool soundPlaying; + + protected override void Update() + { + if (hasMana && currentTarget != null && !flaming) + { + flames.Play(); + PlaySound(onOff: true); + flaming = true; + } + else if (!hasMana || (currentTarget == null && flaming)) + { + flames.Stop(); + PlaySound(onOff: false); + flaming = false; + } + base.Update(); + } + + protected override void Fire() + { + if (consumesMana) + { + int manaCost = (int)((float)base.damage * manaConsumptionRate); + if (!ResourceManager.instance.CheckMana(manaCost)) + { + hasMana = false; + return; + } + ResourceManager.instance.SpendMana(manaCost); + hasMana = true; + } + RaycastHit[] array = Physics.SphereCastAll(muzzle.position, base.range / 6f, muzzle.transform.forward, base.range * 1.5f, enemyLayerMask, QueryTriggerInteraction.Collide); + foreach (RaycastHit raycastHit in array) + { + raycastHit.collider.GetComponent<IDamageable>()?.TakeDamage(towerType, base.damage, base.healthDamage, base.armorDamage, base.shieldDamage, base.slowPercent, base.bleedPercent, base.burnPercent, base.poisonPercent, base.critChance, base.stunChance); + } + } + + private void PlaySound(bool onOff) + { + if (onOff && !soundPlaying) + { + audioS.volume = OptionsMenu.instance.masterVolume * OptionsMenu.instance.sfxVolume; + audioS.Play(); + soundPlaying = true; + } + else if (!onOff && soundPlaying) + { + audioS.Stop(); + soundPlaying = false; + } + } +} diff --git a/GameCode/GameManager.cs b/GameCode/GameManager.cs new file mode 100644 index 0000000..bfa59e1 --- /dev/null +++ b/GameCode/GameManager.cs @@ -0,0 +1,476 @@ +using UnityEngine; +using UnityEngine.UI; + +public class GameManager : MonoBehaviour +{ + [SerializeField] + private TileManager tileManager; + + [SerializeField] + private SpawnManager spawnManager; + + public int gameMode = 3; + + [SerializeField] + private TerrainTile singleStartTile; + + [SerializeField] + private Waypoint[] singleStartWaypoints; + + [SerializeField] + private TerrainTile doubleStartTile; + + [SerializeField] + private Waypoint[] doubleStartWaypoints; + + [SerializeField] + private TerrainTile tripleStartTile; + + [SerializeField] + private Waypoint[] tripleStartWaypoints; + + public bool gameOver; + + public int health; + + public int maxHealth; + + private float healthLoss; + + [SerializeField] + private Text healthText; + + [SerializeField] + private Image maskBar; + + [SerializeField] + private Image healthBar; + + [SerializeField] + private Image healthLossBar; + + [SerializeField] + private GameObject gameOverMenu; + + [SerializeField] + private Text levelsCompletedText; + + [SerializeField] + private Text xpGainText; + + [SerializeField] + private Text newRecordText; + + [SerializeField] + private GameObject victoryScreen; + + [SerializeField] + private Text vicLevelsText; + + [SerializeField] + private Text vicLevelXpText; + + [SerializeField] + private Text vicXpBonusText; + + [SerializeField] + private Text vicNewRecordText; + + public Vector3 dotTick = 24f * Vector3.one; + + public int hauntedHouseEfficiency = 1; + + public int universityBonus; + + public static GameManager instance; + + private void Awake() + { + instance = this; + gameMode = PlayerPrefs.GetInt("GameMode", 1); + if (gameMode == 1) + { + singleStartTile.transform.Rotate(0f, 90 * Random.Range(-1, 3), 0f); + singleStartTile.SetCardinalDirections(); + tileManager.startTile = singleStartTile; + spawnManager.initialSpawns = singleStartWaypoints; + doubleStartTile.gameObject.SetActive(value: false); + tripleStartTile.gameObject.SetActive(value: false); + } + else if (gameMode == 2) + { + doubleStartTile.transform.Rotate(0f, 90 * Random.Range(-1, 3), 0f); + doubleStartTile.SetCardinalDirections(); + tileManager.startTile = doubleStartTile; + spawnManager.initialSpawns = doubleStartWaypoints; + singleStartTile.gameObject.SetActive(value: false); + tripleStartTile.gameObject.SetActive(value: false); + } + else if (gameMode == 3) + { + tripleStartTile.transform.Rotate(0f, 90 * Random.Range(-1, 3), 0f); + tripleStartTile.SetCardinalDirections(); + tileManager.startTile = tripleStartTile; + spawnManager.initialSpawns = tripleStartWaypoints; + doubleStartTile.gameObject.SetActive(value: false); + singleStartTile.gameObject.SetActive(value: false); + } + + } + + private void Start() + { + maxHealth = 100 + 10 * (PlayerPrefs.GetInt("TowerHealth1", 0) + PlayerPrefs.GetInt("TowerHealth2", 0) + PlayerPrefs.GetInt("TowerHealth3", 0) + PlayerPrefs.GetInt("TowerHealth4", 0) + PlayerPrefs.GetInt("TowerHealth5", 0) + PlayerPrefs.GetInt("TowerHealth6", 0) + PlayerPrefs.GetInt("TowerHealth7", 0) + PlayerPrefs.GetInt("TowerHealth8", 0) + PlayerPrefs.GetInt("TowerHealth9", 0) + PlayerPrefs.GetInt("TowerHealth10", 0)); + health = maxHealth; + healthLoss = maxHealth; + SetHealthBar(); + int num = 0; + num = PlayerPrefs.GetInt("BalistaPHealth", 0); + if (num > 0) + { + TowerManager.instance.AddBonusHealthDamage(TowerType.Crossbow, num); + } + num = PlayerPrefs.GetInt("BalistaPArmor", 0); + if (num > 0) + { + TowerManager.instance.AddBonusArmorDamage(TowerType.Crossbow, num); + } + num = PlayerPrefs.GetInt("BalistaPShield", 0); + if (num > 0) + { + TowerManager.instance.AddBonusShieldDamage(TowerType.Crossbow, num); + } + num = PlayerPrefs.GetInt("MortarPHealth", 0); + if (num > 0) + { + TowerManager.instance.AddBonusHealthDamage(TowerType.Morter, num); + } + num = PlayerPrefs.GetInt("MortarPArmor", 0); + if (num > 0) + { + TowerManager.instance.AddBonusArmorDamage(TowerType.Morter, num); + } + num = PlayerPrefs.GetInt("MortarPShield", 0); + if (num > 0) + { + TowerManager.instance.AddBonusShieldDamage(TowerType.Morter, num); + } + num = PlayerPrefs.GetInt("TeslaPHealth", 0); + if (num > 0) + { + TowerManager.instance.AddBonusHealthDamage(TowerType.TeslaCoil, num); + } + num = PlayerPrefs.GetInt("TeslaPArmor", 0); + if (num > 0) + { + TowerManager.instance.AddBonusArmorDamage(TowerType.TeslaCoil, num); + } + num = PlayerPrefs.GetInt("TeslaPShield", 0); + if (num > 0) + { + TowerManager.instance.AddBonusShieldDamage(TowerType.TeslaCoil, num); + } + num = PlayerPrefs.GetInt("FrostPHealth", 0); + if (num > 0) + { + TowerManager.instance.AddBonusHealthDamage(TowerType.Frost, num); + } + num = PlayerPrefs.GetInt("FrostPArmor", 0); + if (num > 0) + { + TowerManager.instance.AddBonusArmorDamage(TowerType.Frost, num); + } + num = PlayerPrefs.GetInt("FrostPShield", 0); + if (num > 0) + { + TowerManager.instance.AddBonusShieldDamage(TowerType.Frost, num); + } + num = PlayerPrefs.GetInt("FlamePHealth", 0); + if (num > 0) + { + TowerManager.instance.AddBonusHealthDamage(TowerType.FlameThrower, num); + } + num = PlayerPrefs.GetInt("FlamePArmor", 0); + if (num > 0) + { + TowerManager.instance.AddBonusArmorDamage(TowerType.FlameThrower, num); + } + num = PlayerPrefs.GetInt("FlamePShield", 0); + if (num > 0) + { + TowerManager.instance.AddBonusShieldDamage(TowerType.FlameThrower, num); + } + num = PlayerPrefs.GetInt("PoisonPHealth", 0); + if (num > 0) + { + TowerManager.instance.AddBonusHealthDamage(TowerType.PoisonSprayer, num); + } + num = PlayerPrefs.GetInt("PoisonPArmor", 0); + if (num > 0) + { + TowerManager.instance.AddBonusArmorDamage(TowerType.PoisonSprayer, num); + } + num = PlayerPrefs.GetInt("PoisonPShield", 0); + if (num > 0) + { + TowerManager.instance.AddBonusShieldDamage(TowerType.PoisonSprayer, num); + } + num = PlayerPrefs.GetInt("ShredderPHealth", 0); + if (num > 0) + { + TowerManager.instance.AddBonusHealthDamage(TowerType.Shredder, num); + } + num = PlayerPrefs.GetInt("ShredderPArmor", 0); + if (num > 0) + { + TowerManager.instance.AddBonusArmorDamage(TowerType.Shredder, num); + } + num = PlayerPrefs.GetInt("ShredderPShield", 0); + if (num > 0) + { + TowerManager.instance.AddBonusShieldDamage(TowerType.Shredder, num); + } + num = PlayerPrefs.GetInt("EncampmentPHealth", 0); + if (num > 0) + { + TowerManager.instance.AddBonusHealthDamage(TowerType.Encampment, num); + } + num = PlayerPrefs.GetInt("EncampmentPArmor", 0); + if (num > 0) + { + TowerManager.instance.AddBonusArmorDamage(TowerType.Encampment, num); + } + num = PlayerPrefs.GetInt("EncampmentPShield", 0); + if (num > 0) + { + TowerManager.instance.AddBonusShieldDamage(TowerType.Encampment, num); + } + num = PlayerPrefs.GetInt("LookoutPHealth", 0); + if (num > 0) + { + TowerManager.instance.AddBonusHealthDamage(TowerType.Lookout, num); + } + num = PlayerPrefs.GetInt("LookoutPArmor", 0); + if (num > 0) + { + TowerManager.instance.AddBonusArmorDamage(TowerType.Lookout, num); + } + num = PlayerPrefs.GetInt("LookoutPShield", 0); + if (num > 0) + { + TowerManager.instance.AddBonusShieldDamage(TowerType.Lookout, num); + } + num = PlayerPrefs.GetInt("RadarPHealth", 0); + if (num > 0) + { + TowerManager.instance.AddBonusHealthDamage(TowerType.Radar, num); + } + num = PlayerPrefs.GetInt("RadarPArmor", 0); + if (num > 0) + { + TowerManager.instance.AddBonusArmorDamage(TowerType.Radar, num); + } + num = PlayerPrefs.GetInt("RadarPShield", 0); + if (num > 0) + { + TowerManager.instance.AddBonusShieldDamage(TowerType.Radar, num); + } + num = PlayerPrefs.GetInt("ObeliskPHealth", 0); + if (num > 0) + { + TowerManager.instance.AddBonusHealthDamage(TowerType.Obelisk, num); + } + num = PlayerPrefs.GetInt("ObeliskPArmor", 0); + if (num > 0) + { + TowerManager.instance.AddBonusArmorDamage(TowerType.Obelisk, num); + } + num = PlayerPrefs.GetInt("ObeliskPShield", 0); + if (num > 0) + { + TowerManager.instance.AddBonusShieldDamage(TowerType.Obelisk, num); + } + num = PlayerPrefs.GetInt("ParticleCannonPHealth", 0); + if (num > 0) + { + TowerManager.instance.AddBonusHealthDamage(TowerType.ParticleCannon, num); + } + num = PlayerPrefs.GetInt("ParticleCannonPArmor", 0); + if (num > 0) + { + TowerManager.instance.AddBonusArmorDamage(TowerType.ParticleCannon, num); + } + num = PlayerPrefs.GetInt("ParticleCannonPShield", 0); + if (num > 0) + { + TowerManager.instance.AddBonusShieldDamage(TowerType.ParticleCannon, num); + } + } + + private void Update() + { + if (healthLoss > (float)health) + { + healthLoss = Mathf.Clamp(healthLoss - 4f * Time.deltaTime, health, healthLoss); + healthLossBar.rectTransform.sizeDelta = new Vector2(healthLoss / 10f, 0.25f); + } + } + + public void IncreaseTowerHealth(int amt) + { + maxHealth += amt * 10; + health += amt * 10; + healthLoss = health; + SetHealthBar(); + if (maxHealth / 10 >= 50) + { + AchievementManager.instance.UnlockAchievement("TowerHealth50"); + } + else if (maxHealth / 10 >= 40) + { + AchievementManager.instance.UnlockAchievement("TowerHealth40"); + } + else if (maxHealth / 10 >= 30) + { + AchievementManager.instance.UnlockAchievement("TowerHealth30"); + } + } + + private void SetHealthBar() + { + maskBar.rectTransform.localScale = new Vector3(2000 / maxHealth, 50f, 10f); + maskBar.rectTransform.sizeDelta = new Vector2((float)maxHealth / 10f, 0.25f); + healthLossBar.rectTransform.sizeDelta = new Vector2((float)health / 10f, 0.25f); + UpdateHealthText(); + } + + private void UpdateHealthText() + { + healthText.text = "Tower: " + health / 10 + "/" + maxHealth / 10; + healthBar.rectTransform.sizeDelta = new Vector2((float)health / 10f, 0.25f); + } + + public void TakeDamage(int damage) + { + health = Mathf.Max(health - 10 * damage, 0); + UpdateHealthText(); + if (health <= 0 && !gameOver) + { + gameOver = true; + GameOver(); + } + } + + public void RepairTower(int heal) + { + health = Mathf.Clamp(health + heal, 0, maxHealth); + if (healthLoss < (float)health) + { + healthLoss = health; + } + UpdateHealthText(); + } + + public void GameOverQuit() + { + if (!SpawnManager.instance.combat) + { + SpawnManager.instance.level++; + } + if (Time.timeScale != 1f) + { + Time.timeScale = 1f; + } + gameOver = true; + GameOver(); + } + + public int NaturalSum(int value) + { + return value * (value + 1) / 2; + } + + private void GameOver() + { + gameOverMenu.SetActive(value: true); + DamageTracker.instance.DisplayDamageTotals(); + int num = NaturalSum(SpawnManager.instance.level - 1) * gameMode; + int num2 = 0; + int @int = PlayerPrefs.GetInt("Record" + gameMode, 0); + if (SpawnManager.instance.level - 1 - @int > 0) + { + num2 = (NaturalSum(SpawnManager.instance.level - 1) - NaturalSum(@int)) * 3; + PlayerPrefs.SetInt("Record" + gameMode, SpawnManager.instance.level - 1); + string text = ""; + if (gameMode == 1) + { + text = "single"; + } + else if (gameMode == 2) + { + text = "double"; + } + else if (gameMode == 3) + { + text = "triple"; + } + newRecordText.text = "New " + text + " defense record!\n +" + num2 + " bonus xp"; + } + else + { + newRecordText.text = ""; + } + int int2 = PlayerPrefs.GetInt("XP", 0); + PlayerPrefs.SetInt("XP", int2 + num2); + levelsCompletedText.text = "Defended " + (SpawnManager.instance.level - 1) + " levels"; + xpGainText.text = "+" + num + " xp"; + } + + public void Victory() + { + AchievementManager.instance.CheckTowerTypesVictory(); + victoryScreen.SetActive(value: true); + DamageTracker.instance.DisplayDamageTotals(); + int num = NaturalSum(SpawnManager.instance.level - 1) * gameMode; + int num2 = SpawnManager.instance.lastLevel * gameMode * 10; + int num3 = 0; + int @int = PlayerPrefs.GetInt("Record" + gameMode, 0); + if (SpawnManager.instance.lastLevel - @int > 0) + { + num3 = (NaturalSum(SpawnManager.instance.level - 1) - NaturalSum(@int)) * 3; + PlayerPrefs.SetInt("Record" + gameMode, SpawnManager.instance.lastLevel); + string text = ""; + if (gameMode == 1) + { + text = "single"; + } + else if (gameMode == 2) + { + text = "double"; + } + else if (gameMode == 3) + { + text = "triple"; + } + vicNewRecordText.text = "New " + text + " defense record!\n +" + num3 + " bonus xp"; + } + else + { + vicNewRecordText.text = ""; + } + int int2 = PlayerPrefs.GetInt("XP", 0); + PlayerPrefs.SetInt("XP", int2 + num3 + num2); + vicLevelsText.text = "Defended all " + SpawnManager.instance.lastLevel + " levels"; + vicLevelXpText.text = "+" + num + " xp"; + vicXpBonusText.text = "+" + num2 + " xp"; + } + + public void LoadScene(string sceneName) + { + if (AchievementManager.instance != null) + { + AchievementManager.instance.OnSceneClose(); + } + LevelLoader.instance.LoadLevel(sceneName); + } +} diff --git a/GameCode/GoldRushCard.cs b/GameCode/GoldRushCard.cs new file mode 100644 index 0000000..79663ce --- /dev/null +++ b/GameCode/GoldRushCard.cs @@ -0,0 +1,17 @@ +using UnityEngine; + +public class GoldRushCard : UpgradeCard +{ + [SerializeField] + private int goldGain; + + [SerializeField] + private float speedBonus; + + public override void Upgrade() + { + base.Upgrade(); + MonsterManager.instance.speedBonus += speedBonus; + ResourceManager.instance.AddMoney(goldGain); + } +} diff --git a/GameCode/Grave.cs b/GameCode/Grave.cs new file mode 100644 index 0000000..45abddc --- /dev/null +++ b/GameCode/Grave.cs @@ -0,0 +1,3 @@ +public class Grave : SpawnableObject +{ +} diff --git a/GameCode/HauntedHouse.cs b/GameCode/HauntedHouse.cs new file mode 100644 index 0000000..9a23eda --- /dev/null +++ b/GameCode/HauntedHouse.cs @@ -0,0 +1,111 @@ +using UnityEngine; + +public class HauntedHouse : IncomeGenerator, IBuildable +{ + [SerializeField] + private LayerMask graveLayerMask; + + [SerializeField] + private GameObject UIObject; + + [SerializeField] + private int goldBackOnDemolish; + + private bool isGathering; + + private int graveCount; + + private int manaUsed; + + private float timer; + + private SimpleUI myUI; + + protected override void Start() + { + base.Start(); + DetectGraves(); + } + + private void Update() + { + if (myUI != null && isGathering) + { + string text = "Mana used: " + manaUsed; + text = text + "\nNearby graves: x" + graveCount; + text = text + "\nTax efficiency: x" + GameManager.instance.hauntedHouseEfficiency; + text = text + "\nDeath tax due: " + Mathf.Max((int)Mathf.Sqrt(manaUsed * GameManager.instance.hauntedHouseEfficiency * graveCount), 1) + "g"; + text = text + "\nNet tax collected: " + base.netGold + "g."; + myUI.SetDiscriptionText(text); + } + if (!isGathering || !SpawnManager.instance.combat) + { + return; + } + if (timer <= 0f) + { + if (ResourceManager.instance.CheckMana(1)) + { + ResourceManager.instance.SpendMana(1); + manaUsed++; + timer = 1f; + } + } + else + { + timer -= Time.deltaTime; + } + } + + public override void GenerateIncome() + { + incomePerRound = Mathf.Max((int)Mathf.Sqrt(manaUsed * GameManager.instance.hauntedHouseEfficiency * graveCount), 1); + base.GenerateIncome(); + manaUsed = 0; + incomePerRound = 1; + } + + public void SetStats() + { + } + + private void DetectGraves() + { + if (Physics.Raycast(base.transform.position + new Vector3(1f, 1f, 0f), -base.transform.up, out var hitInfo, 1f, graveLayerMask, QueryTriggerInteraction.Ignore)) + { + CheckGrave(hitInfo); + } + if (Physics.Raycast(base.transform.position + new Vector3(-1f, 1f, 0f), -base.transform.up, out hitInfo, 1f, graveLayerMask, QueryTriggerInteraction.Ignore)) + { + CheckGrave(hitInfo); + } + if (Physics.Raycast(base.transform.position + new Vector3(0f, 1f, 1f), -base.transform.up, out hitInfo, 1f, graveLayerMask, QueryTriggerInteraction.Ignore)) + { + CheckGrave(hitInfo); + } + if (Physics.Raycast(base.transform.position + new Vector3(0f, 1f, -1f), -base.transform.up, out hitInfo, 1f, graveLayerMask, QueryTriggerInteraction.Ignore)) + { + CheckGrave(hitInfo); + } + } + + private void CheckGrave(RaycastHit hit) + { + if (hit.collider.GetComponent<Grave>() != null && (double)Mathf.Abs(hit.collider.transform.position.y - base.transform.position.y) <= 0.001) + { + graveCount++; + isGathering = true; + } + } + + public void SpawnUI() + { + myUI = Object.Instantiate(UIObject, base.transform.position, Quaternion.identity).GetComponent<SimpleUI>(); + myUI.SetDemolishable(base.gameObject, goldBackOnDemolish); + } + + public void Demolish() + { + RemoveIncomeGeneration(); + } +} diff --git a/GameCode/HauntedHouseUpgrade.cs b/GameCode/HauntedHouseUpgrade.cs new file mode 100644 index 0000000..47d4c8a --- /dev/null +++ b/GameCode/HauntedHouseUpgrade.cs @@ -0,0 +1,8 @@ +public class HauntedHouseUpgrade : UpgradeCard +{ + public override void Upgrade() + { + base.Upgrade(); + GameManager.instance.hauntedHouseEfficiency++; + } +} diff --git a/GameCode/HealthBar.cs b/GameCode/HealthBar.cs new file mode 100644 index 0000000..558df63 --- /dev/null +++ b/GameCode/HealthBar.cs @@ -0,0 +1,157 @@ +using UnityEngine; +using UnityEngine.UI; + +public class HealthBar : MonoBehaviour +{ + [SerializeField] + private Image maskBar; + + [SerializeField] + private Image healthBar; + + [SerializeField] + private Image armorBar; + + [SerializeField] + private Image shieldBar; + + [SerializeField] + private Image dmgBar; + + [SerializeField] + private Image slowImageLeft; + + [SerializeField] + private Image slowImageRight; + + [SerializeField] + private GameObject BleedImage; + + [SerializeField] + private GameObject BurnImage; + + [SerializeField] + private GameObject PoisonImage; + + [SerializeField] + private Text bleedText; + + [SerializeField] + private Text burnText; + + [SerializeField] + private Text poisonText; + + [SerializeField] + private Image fortImageLeft; + + [SerializeField] + private Image fortImageRight; + + [SerializeField] + private Image hasteImageLeft; + + [SerializeField] + private Image hasteImageRight; + + private float maxHp; + + private float health; + + private float armor; + + private float shield; + + private float dmg; + + private float barScaler = 100f; + + private void Update() + { + if (dmg > health + armor + shield) + { + dmg = Mathf.Clamp(dmg - 4f * Time.deltaTime, health + armor + shield, dmg); + dmgBar.rectTransform.sizeDelta = new Vector2(dmg, 0.25f); + } + } + + public void SetHealth(int max, int heal, int armr, int shld, int scaleDegree) + { + barScaler = 10f * Mathf.Pow(10f, scaleDegree); + maxHp = (float)max / barScaler; + dmg = maxHp; + health = (float)heal / barScaler; + armor = (float)armr / barScaler; + shield = (float)shld / barScaler; + maskBar.rectTransform.localScale = new Vector3(3f / (maxHp + 3f), 1f, 1f); + maskBar.rectTransform.sizeDelta = new Vector2(maxHp, 0.25f); + dmgBar.rectTransform.sizeDelta = new Vector2(dmg, 0.25f); + UpdateHealth(heal, armr, shld, 0f, isBleeding: false, isBurning: false, isPoisoned: false, 0, 0, 0); + } + + public void UpdateHealth(int heal, int armr, int shld, float currentSlow, bool isBleeding, bool isBurning, bool isPoisoned, int currentBleed, int currentBurn, int currentPoison) + { + health = (float)heal / barScaler; + armor = (float)armr / barScaler; + shield = (float)shld / barScaler; + healthBar.rectTransform.sizeDelta = new Vector2(health, 0.25f); + armorBar.rectTransform.sizeDelta = new Vector2(armor, 0.25f); + shieldBar.rectTransform.sizeDelta = new Vector2(shield, 0.25f); + armorBar.rectTransform.localPosition = new Vector3(health - maskBar.rectTransform.sizeDelta.x / 2f, 0f, 0f); + shieldBar.rectTransform.localPosition = new Vector3(health + armor - maskBar.rectTransform.sizeDelta.x / 2f, 0f, 0f); + Image image = slowImageLeft; + float fillAmount = (slowImageRight.fillAmount = currentSlow); + image.fillAmount = fillAmount; + BleedImage.SetActive(isBleeding); + bleedText.gameObject.SetActive(isBleeding); + bleedText.text = currentBleed.ToString(); + BurnImage.SetActive(isBurning); + burnText.gameObject.SetActive(isBurning); + burnText.text = currentBurn.ToString(); + PoisonImage.SetActive(isPoisoned); + poisonText.gameObject.SetActive(isPoisoned); + poisonText.text = currentPoison.ToString(); + } + + public void UpdateSlow(float currentSlow) + { + Image image = slowImageLeft; + float fillAmount = (slowImageRight.fillAmount = currentSlow); + image.fillAmount = fillAmount; + } + + public void UpdateBleed(bool status, int amt) + { + BleedImage.SetActive(status); + bleedText.gameObject.SetActive(status); + bleedText.text = amt.ToString(); + } + + public void UpdateBurn(bool status, int amt) + { + BurnImage.SetActive(status); + burnText.gameObject.SetActive(status); + burnText.text = amt.ToString(); + } + + public void UpdatePoison(bool status, int amt) + { + PoisonImage.SetActive(status); + poisonText.gameObject.SetActive(status); + poisonText.text = amt.ToString(); + } + + public void UpdateFortified(float fortTime) + { + Image image = fortImageLeft; + float fillAmount = (fortImageRight.fillAmount = fortTime * 0.083333f); + image.fillAmount = fillAmount; + } + + public void UpdateHaste(float hastePercentage) + { + Image image = hasteImageLeft; + float fillAmount = (hasteImageRight.fillAmount = hastePercentage); + image.fillAmount = fillAmount; + } +} diff --git a/GameCode/House.cs b/GameCode/House.cs new file mode 100644 index 0000000..16bb26d --- /dev/null +++ b/GameCode/House.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using UnityEngine; + +public class House : SpawnableObject +{ + private List<Tower> defenders = new List<Tower>(); + + [SerializeField] + private IncomeGenerator myIncomeGenerator; + + protected override void Start() + { + base.Start(); + SpawnManager.instance.houses.Add(this); + } + + public void AddDefender(Tower t) + { + if (!defenders.Contains(t)) + { + defenders.Add(t); + } + CheckTowers(); + } + + public void CheckTowers() + { + for (int num = defenders.Count - 1; num > -1; num--) + { + if (defenders[num] == null) + { + defenders.RemoveAt(num); + } + } + myIncomeGenerator.incomeTimesLevel = defenders.Count; + } + + public override void SpawnUI() + { + SimpleUI component = Object.Instantiate(UIObject, base.transform.position, Quaternion.identity).GetComponent<SimpleUI>(); + if (defenders.Count > 0) + { + string text = "This house is protected by " + defenders.Count + " towers."; + text = text + "\nIts next gift will be " + (SpawnManager.instance.level + 1) * defenders.Count + "g."; + text = text + "\nNet gold gifted: " + myIncomeGenerator.netGold + "g."; + component.SetDiscriptionText(text); + } + } +} diff --git a/GameCode/IBuildable.cs b/GameCode/IBuildable.cs new file mode 100644 index 0000000..5fcdc7e --- /dev/null +++ b/GameCode/IBuildable.cs @@ -0,0 +1,8 @@ +public interface IBuildable +{ + void SetStats(); + + void Demolish(); + + void SpawnUI(); +} diff --git a/GameCode/IDamageable.cs b/GameCode/IDamageable.cs new file mode 100644 index 0000000..d010ef5 --- /dev/null +++ b/GameCode/IDamageable.cs @@ -0,0 +1,4 @@ +public interface IDamageable +{ + void TakeDamage(TowerType whoHitMe, int baseDmg, int healthDmg, int armorDmg, int shieldDmg, float slowPercentage, float bleedPercentage, float burnPercentage, float poisonPercentage, float critChance, float stunChance); +} diff --git a/GameCode/IncomeGenerator.cs b/GameCode/IncomeGenerator.cs new file mode 100644 index 0000000..9afd8f5 --- /dev/null +++ b/GameCode/IncomeGenerator.cs @@ -0,0 +1,39 @@ +using UnityEngine; + +public class IncomeGenerator : MonoBehaviour +{ + public int incomePerRound; + + public float incomeTimesLevel; + + [SerializeField] + private DamageTracker.IncomeType myIncomeType; + + public int netGold { get; private set; } + + protected virtual void Start() + { + SpawnManager.instance.incomeGenerators.Add(this); + netGold = 0; + } + + public virtual void GenerateIncome() + { + int num = incomePerRound + (int)(incomeTimesLevel * (float)SpawnManager.instance.level); + if (num > 0) + { + ResourceManager.instance.AddMoney(num); + netGold += num; + DamageTracker.instance.AddIncome(myIncomeType, num); + SFXManager.instance.PlaySound(Sound.CoinShort, base.transform.position); + DamageNumber component = ObjectPool.instance.SpawnObject(ObjectPool.ObjectType.DamageNumber, base.transform.position, Quaternion.identity).GetComponent<DamageNumber>(); + component.SetText("+" + num + "g", "Grey", 1f); + component.SetHoldTime(2.5f); + } + } + + public void RemoveIncomeGeneration() + { + SpawnManager.instance.incomeGenerators.Remove(this); + } +} diff --git a/GameCode/IronVein.cs b/GameCode/IronVein.cs new file mode 100644 index 0000000..06af952 --- /dev/null +++ b/GameCode/IronVein.cs @@ -0,0 +1,3 @@ +public class IronVein : SpawnableObject +{ +} diff --git a/GameCode/KeyDisappear.cs b/GameCode/KeyDisappear.cs new file mode 100644 index 0000000..d997703 --- /dev/null +++ b/GameCode/KeyDisappear.cs @@ -0,0 +1,61 @@ +using UnityEngine; + +public class KeyDisappear : MonoBehaviour +{ + [SerializeField] + private GameObject wKey; + + [SerializeField] + private GameObject aKey; + + [SerializeField] + private GameObject sKey; + + [SerializeField] + private GameObject dKey; + + private bool w; + + private bool a; + + private bool s; + + private bool d; + + [SerializeField] + private bool destroyOnCompletion = true; + + private float time; + + private void Update() + { + time += Time.deltaTime; + if (time > 3f) + { + if (Input.GetKeyUp(KeyCode.W)) + { + wKey.SetActive(value: false); + w = true; + } + if (Input.GetKeyUp(KeyCode.A)) + { + aKey.SetActive(value: false); + a = true; + } + if (Input.GetKeyUp(KeyCode.S)) + { + sKey.SetActive(value: false); + s = true; + } + if (Input.GetKeyUp(KeyCode.D)) + { + dKey.SetActive(value: false); + d = true; + } + if (destroyOnCompletion && w && a && s && d) + { + Object.Destroy(base.gameObject); + } + } + } +} diff --git a/GameCode/Landmine.cs b/GameCode/Landmine.cs new file mode 100644 index 0000000..5422016 --- /dev/null +++ b/GameCode/Landmine.cs @@ -0,0 +1,67 @@ +using System.Collections; +using UnityEngine; + +public class Landmine : Projectile +{ + public float blastRadius = 0.5f; + + private bool armed; + + [SerializeField] + private GameObject explosion; + + protected override void Start() + { + base.Start(); + SpawnManager.instance.destroyOnNewLevel.Add(base.gameObject); + } + + public void SetEndPosition(Vector3 endPos) + { + StartCoroutine(ThrowMine(endPos)); + } + + protected override void FixedUpdate() + { + } + + private void OnTriggerEnter(Collider other) + { + if (armed && other.gameObject.layer == LayerMask.NameToLayer("Enemy")) + { + Explode(); + } + } + + private void Explode() + { + Collider[] array = Physics.OverlapSphere(base.transform.position, blastRadius, layermask, QueryTriggerInteraction.Collide); + for (int i = 0; i < array.Length; i++) + { + IDamageable component = array[i].GetComponent<IDamageable>(); + if (component != null) + { + DealDamage(component); + } + } + Object.Instantiate(explosion, base.transform.position, Quaternion.identity).transform.localScale = Vector3.one * 0.5f; + SpawnManager.instance.destroyOnNewLevel.Remove(base.gameObject); + Object.Destroy(base.gameObject); + } + + private IEnumerator ThrowMine(Vector3 endPos) + { + Vector3 direction = endPos - base.transform.position; + float throwTime = 1f; + base.transform.localScale = Vector3.zero; + for (float i = 0f; i < 1f; i += Time.deltaTime / throwTime) + { + base.transform.localScale = Vector3.one * i; + base.transform.Translate(direction * Time.deltaTime / throwTime); + yield return null; + } + base.transform.localScale = Vector3.one; + base.transform.position = endPos; + armed = true; + } +} diff --git a/GameCode/LevelLoader.cs b/GameCode/LevelLoader.cs new file mode 100644 index 0000000..1698c15 --- /dev/null +++ b/GameCode/LevelLoader.cs @@ -0,0 +1,116 @@ +using System.Collections; +using UnityEngine; +using UnityEngine.SceneManagement; +using UnityEngine.UI; + +public class LevelLoader : MonoBehaviour +{ + public static LevelLoader instance; + + [SerializeField] + private Image circle; + + [SerializeField] + private Text loadingText; + + [SerializeField] + private Text tipText; + + [SerializeField] + private string[] tips; + + private void Awake() + { + instance = this; + } + + private void Start() + { + loadingText.text = ""; + tipText.text = ""; + StartCoroutine(CircleExitStart()); + } + + public void LoadLevel(string sceneName) + { + if (MusicManager.instance != null) + { + MusicManager.instance.FadeOut(2.5f); + } + StartCoroutine(LoadAsyncronously(sceneName)); + } + + private IEnumerator LoadAsyncronously(string sceneName) + { + float num = Mathf.Sqrt(Screen.height * Screen.width) * 1.1f; + Vector2 endSize = new Vector2(2f, 1f) * num * 2f; + Vector2 startSize = new Vector2(0f, 1f) * num * 2f; + circle.rectTransform.sizeDelta = startSize; + Vector3 endPosition = new Vector3((float)Screen.height / 2f, (float)Screen.height / 2f, 0f); + Vector3 startPosition = new Vector3((float)Screen.width * 1.1f, (float)Screen.height / 2f, 0f); + circle.transform.position = startPosition; + float t = 0f; + while (t < 1f) + { + circle.rectTransform.sizeDelta = Vector2.Lerp(startSize, endSize, t); + circle.transform.position = Vector3.Lerp(startPosition, endPosition, t); + t += Time.deltaTime / 1.5f; + yield return null; + } + circle.rectTransform.sizeDelta = endSize; + circle.transform.position = endPosition; + tipText.text = GetTipsText(); + AsyncOperation operation = SceneManager.LoadSceneAsync(sceneName); + operation.allowSceneActivation = false; + float waitFill = 0f; + while (!operation.isDone || waitFill < 1f) + { + waitFill = Mathf.Clamp(waitFill + Time.deltaTime / 3f, 0f, 1f); + float num2 = Mathf.Clamp(operation.progress / 0.9f, 0f, 1f); + if (waitFill >= 1f) + { + operation.allowSceneActivation = true; + } + loadingText.text = GetLoadingText((waitFill * num2 + waitFill) / 2f); + yield return null; + } + } + + private string GetLoadingText(float percent) + { + return "Loading...".Substring(0, (int)Mathf.Round(percent * 10f)); + } + + private string GetTipsText() + { + int num = Random.Range(0, tips.Length); + int @int = PlayerPrefs.GetInt("PreviousTip", 0); + if (num == @int) + { + num = (num + 1) % tips.Length; + } + PlayerPrefs.SetInt("PreviousTip", num); + return tips[num]; + } + + private IEnumerator CircleExitStart() + { + float num = Mathf.Sqrt(Screen.height * Screen.width) * 1.1f; + Vector2 startSize = new Vector2(2f, 1f) * num * 2f; + Vector2 endSize = new Vector2(0f, 1f) * num * 2f; + circle.rectTransform.sizeDelta = startSize; + Vector3 startPosition = new Vector3((float)Screen.height / 2f, (float)Screen.height / 2f, 0f); + Vector3 endPosition = new Vector3((float)(-Screen.width) * 0.1f, (float)Screen.height / 2f, 0f); + circle.transform.position = startPosition; + float t = 0f; + while (t < 1f) + { + circle.rectTransform.sizeDelta = Vector2.Lerp(startSize, endSize, t); + circle.transform.position = Vector3.Lerp(startPosition, endPosition, t); + t += Time.deltaTime / 1.5f; + yield return null; + } + circle.rectTransform.sizeDelta = endSize; + circle.transform.position = endPosition; + } +} diff --git a/GameCode/LightManager.cs b/GameCode/LightManager.cs new file mode 100644 index 0000000..e38ac0f --- /dev/null +++ b/GameCode/LightManager.cs @@ -0,0 +1,62 @@ +using System.Collections; +using UnityEngine; + +public class LightManager : MonoBehaviour +{ + [SerializeField] + private Color stage2Color; + + [SerializeField] + private Color stage3Color; + + [SerializeField] + private Color stage4Color; + + [SerializeField] + private Light light; + + private void Start() + { + } + + public void ChangeColor(int stage) + { + switch (stage) + { + case 2: + StartCoroutine(ShiftLight(stage2Color, 180f)); + break; + case 3: + StartCoroutine(ShiftLight(stage3Color, 180f)); + break; + case 4: + StartCoroutine(ShiftLight(stage4Color, 180f)); + break; + } + } + + private IEnumerator ShiftLight(Color newColor, float rotationInDeg) + { + Color startColor = light.color; + Vector3 startEuler = light.transform.eulerAngles; + Vector3 newEuler = startEuler + new Vector3(0f, rotationInDeg, 0f); + float timer = 0f; + float count = 0f; + while (timer < 1f) + { + light.color = Color.Lerp(startColor, newColor, timer); + light.transform.eulerAngles = Vector3.Lerp(startEuler, newEuler, timer); + count += Time.deltaTime; + if (count > 60f) + { + Debug.LogError("Possible infinite loop"); + break; + } + timer += Time.deltaTime / 30f; + yield return new WaitForEndOfFrame(); + } + light.color = newColor; + light.transform.eulerAngles = newEuler; + yield return null; + } +} diff --git a/GameCode/Lookout.cs b/GameCode/Lookout.cs new file mode 100644 index 0000000..3abd55b --- /dev/null +++ b/GameCode/Lookout.cs @@ -0,0 +1,97 @@ +using UnityEngine; + +public class Lookout : Tower +{ + [SerializeField] + private GameObject markIcon; + + private GameObject currentMark; + + protected override void Update() + { + if (currentTarget != null) + { + markIcon.SetActive(value: true); + UpdateMark(); + GainXP(); + } + else + { + markIcon.SetActive(value: false); + } + } + + private void UpdateMark() + { + if (currentTarget != currentMark) + { + if (currentMark != null) + { + currentMark.GetComponent<Enemy>().mark = null; + } + currentMark = currentTarget; + currentMark.GetComponent<Enemy>().mark = this; + } + markIcon.transform.position = currentMark.transform.position; + } + + protected override GameObject SelectEnemy(Collider[] possibleTargets) + { + GameObject result = null; + float num = -1f; + for (int i = 0; i < possibleTargets.Length; i++) + { + float num2 = 1f; + Enemy component = possibleTargets[i].GetComponent<Enemy>(); + if (!(component.mark != this) || !(component.mark != null)) + { + if (CheckPriority(Priority.Progress)) + { + num2 /= Mathf.Max(0.001f, possibleTargets[i].GetComponent<Pathfinder>().distanceFromEnd); + } + if (CheckPriority(Priority.NearDeath)) + { + num2 /= Mathf.Max(0.001f, component.CurrentHealth()); + } + if (CheckPriority(Priority.MostHealth)) + { + num2 *= (float)Mathf.Max(1, component.health); + } + if (CheckPriority(Priority.MostArmor)) + { + num2 *= (float)Mathf.Max(1, component.armor); + } + if (CheckPriority(Priority.MostShield)) + { + num2 *= (float)Mathf.Max(1, component.shield); + } + if (CheckPriority(Priority.LeastHealth)) + { + num2 /= (float)Mathf.Max(1, component.health); + } + if (CheckPriority(Priority.LeastArmor)) + { + num2 /= (float)Mathf.Max(1, component.armor); + } + if (CheckPriority(Priority.LeastShield)) + { + num2 /= (float)Mathf.Max(1, component.shield); + } + if (CheckPriority(Priority.Fastest)) + { + num2 *= Mathf.Max(0.001f, possibleTargets[i].GetComponent<Pathfinder>().speed); + } + if (CheckPriority(Priority.Slowest)) + { + num2 /= Mathf.Max(0.001f, possibleTargets[i].GetComponent<Pathfinder>().speed); + } + if (num2 > num) + { + result = component.gameObject; + num = num2; + } + } + } + return result; + } +} diff --git a/GameCode/MainMenu.cs b/GameCode/MainMenu.cs new file mode 100644 index 0000000..1028d13 --- /dev/null +++ b/GameCode/MainMenu.cs @@ -0,0 +1,16 @@ +using UnityEngine; + +public class MainMenu : MonoBehaviour +{ + + void Awake() + { + Screen.fullScreen = false; + Screen.SetResolution(1920, 1080, false); + } + + public void QuitGame() + { + Application.Quit(); + } +} diff --git a/GameCode/ManaBank.cs b/GameCode/ManaBank.cs new file mode 100644 index 0000000..b82d36e --- /dev/null +++ b/GameCode/ManaBank.cs @@ -0,0 +1,68 @@ +using UnityEngine; + +public class ManaBank : MonoBehaviour, IBuildable +{ + [SerializeField] + private int gatherRatePerSec; + + [SerializeField] + private int maxManaIncrease; + + [SerializeField] + private GameObject UIObject; + + [SerializeField] + private int goldBackOnDemolish; + + private float timer = 1f; + + private void Start() + { + maxManaIncrease += ResourceManager.instance.manaBankBonusMana; + ResourceManager.instance.UpdateManaGatherRate(gatherRatePerSec); + ResourceManager.instance.AddMaxMana(maxManaIncrease); + ResourceManager.instance.manaBanks.Add(this); + } + + private void Update() + { + if (timer <= 0f) + { + Gather(); + timer = 1f; + } + else if (SpawnManager.instance.combat) + { + timer -= Time.deltaTime; + } + } + + public void SetStats() + { + } + + public void UpgradeMaxMana(int addition) + { + ResourceManager.instance.AddMaxMana(addition); + maxManaIncrease += addition; + } + + public void SpawnUI() + { + SimpleUI component = Object.Instantiate(UIObject, base.transform.position, Quaternion.identity).GetComponent<SimpleUI>(); + component.SetDemolishable(base.gameObject, goldBackOnDemolish); + component.SetDiscriptionText("This bank currently stores " + maxManaIncrease + " mana. It is generating " + ((float)Mathf.FloorToInt(10f * ResourceManager.instance.manaMaxRegenPercent * (float)maxManaIncrease) / 10f + 1f) + " mana/s through sorcery and clever investing."); + } + + public void Demolish() + { + ResourceManager.instance.UpdateManaGatherRate(-gatherRatePerSec); + ResourceManager.instance.AddMaxMana(-maxManaIncrease); + ResourceManager.instance.manaBanks.Remove(this); + } + + private void Gather() + { + ResourceManager.instance.AddMana(gatherRatePerSec); + } +} diff --git a/GameCode/ManaCrystal.cs b/GameCode/ManaCrystal.cs new file mode 100644 index 0000000..4b84e56 --- /dev/null +++ b/GameCode/ManaCrystal.cs @@ -0,0 +1,3 @@ +public class ManaCrystal : SpawnableObject +{ +} diff --git a/GameCode/ManaGenUpgradeCard.cs b/GameCode/ManaGenUpgradeCard.cs new file mode 100644 index 0000000..e56b63a --- /dev/null +++ b/GameCode/ManaGenUpgradeCard.cs @@ -0,0 +1,21 @@ +using UnityEngine; + +public class ManaGenUpgradeCard : UpgradeCard +{ + [SerializeField] + private float manaPercentRegenIncrease; + + [SerializeField] + private int manaBankMaxManaIncrease; + + public override void Upgrade() + { + base.Upgrade(); + ResourceManager.instance.AddPercentManaGathering(manaPercentRegenIncrease); + ResourceManager.instance.UpdateManaHUD(); + if (manaBankMaxManaIncrease != 0) + { + ResourceManager.instance.UpgradeManaBankMaxMana(manaBankMaxManaIncrease); + } + } +} diff --git a/GameCode/ManaSiphon.cs b/GameCode/ManaSiphon.cs new file mode 100644 index 0000000..89e578e --- /dev/null +++ b/GameCode/ManaSiphon.cs @@ -0,0 +1,92 @@ +using UnityEngine; + +public class ManaSiphon : MonoBehaviour, IBuildable +{ + [SerializeField] + private int gatherRatePerSec; + + [SerializeField] + private LayerMask layermask; + + [SerializeField] + private GameObject UIObject; + + [SerializeField] + private int goldBackOnDemolish; + + private bool gathering; + + private float timer = 1f; + + private void Start() + { + DetectMana(); + if (gathering) + { + ResourceManager.instance.UpdateManaGatherRate(gatherRatePerSec); + } + } + + private void Update() + { + if (timer <= 0f) + { + Gather(); + timer = 1f; + } + else if (gathering && SpawnManager.instance.combat) + { + timer -= Time.deltaTime; + } + } + + public void SetStats() + { + } + + public void SpawnUI() + { + SimpleUI component = Object.Instantiate(UIObject, base.transform.position, Quaternion.identity).GetComponent<SimpleUI>(); + component.SetDemolishable(base.gameObject, goldBackOnDemolish); + if (gathering) + { + component.SetDiscriptionText("Currently gathering 1 mana/sec."); + } + } + + public void Demolish() + { + if (gathering) + { + ResourceManager.instance.UpdateManaGatherRate(-gatherRatePerSec); + } + } + + private void Gather() + { + ResourceManager.instance.AddMana(gatherRatePerSec); + } + + private void DetectMana() + { + if ((!Physics.Raycast(base.transform.position + new Vector3(1f, 1f, 0f), -base.transform.up, out var hitInfo, 1f, layermask, QueryTriggerInteraction.Ignore) || !Rotate(hitInfo)) && (!Physics.Raycast(base.transform.position + new Vector3(-1f, 1f, 0f), -base.transform.up, out hitInfo, 1f, layermask, QueryTriggerInteraction.Ignore) || !Rotate(hitInfo)) && (!Physics.Raycast(base.transform.position + new Vector3(0f, 1f, 1f), -base.transform.up, out hitInfo, 1f, layermask, QueryTriggerInteraction.Ignore) || !Rotate(hitInfo)) && Physics.Raycast(base.transform.position + new Vector3(0f, 1f, -1f), -base.transform.up, out hitInfo, 1f, layermask, QueryTriggerInteraction.Ignore)) + { + Rotate(hitInfo); + } + } + + private bool Rotate(RaycastHit hit) + { + if (hit.collider.GetComponent<ManaCrystal>() == null) + { + return false; + } + if ((double)Mathf.Abs(hit.collider.transform.position.y - base.transform.position.y) > 0.001) + { + return false; + } + base.transform.LookAt(hit.collider.transform.position, Vector3.up); + gathering = true; + return true; + } +} diff --git a/GameCode/MaxHealthUpgradeCard.cs b/GameCode/MaxHealthUpgradeCard.cs new file mode 100644 index 0000000..467b669 --- /dev/null +++ b/GameCode/MaxHealthUpgradeCard.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +public class MaxHealthUpgradeCard : UpgradeCard +{ + [SerializeField] + private int healthIncrease; + + public override void Upgrade() + { + base.Upgrade(); + GameManager.instance.IncreaseTowerHealth(healthIncrease); + } +} diff --git a/GameCode/Mine.cs b/GameCode/Mine.cs new file mode 100644 index 0000000..55d7b6f --- /dev/null +++ b/GameCode/Mine.cs @@ -0,0 +1,81 @@ +using UnityEngine; + +public class Mine : MonoBehaviour, IBuildable +{ + [SerializeField] + private int goldBackOnDemolish; + + [SerializeField] + private LayerMask layermask; + + [SerializeField] + private GameObject UIObject; + + private bool gathering; + + private void Start() + { + SpawnManager.instance.mines.Add(this); + DetectIron(); + } + + public void SetStats() + { + } + + public void Repair() + { + if (gathering && Random.Range(0f, 1f) < 0.1f) + { + GameManager.instance.RepairTower(10); + } + } + + private void SetBonus(int value) + { + GameManager.instance.IncreaseTowerHealth(value); + } + + public void SpawnUI() + { + SimpleUI component = Object.Instantiate(UIObject, base.transform.position, Quaternion.identity).GetComponent<SimpleUI>(); + component.SetDemolishable(base.gameObject, goldBackOnDemolish); + if (gathering) + { + component.SetDiscriptionText("Currently mining. Tower maximum health increased by 1 and a 10% chance to repair damage."); + } + } + + private void DetectIron() + { + if ((!Physics.Raycast(base.transform.position + new Vector3(1f, 1f, 0f), -base.transform.up, out var hitInfo, 1f, layermask, QueryTriggerInteraction.Ignore) || !Rotate(hitInfo)) && (!Physics.Raycast(base.transform.position + new Vector3(-1f, 1f, 0f), -base.transform.up, out hitInfo, 1f, layermask, QueryTriggerInteraction.Ignore) || !Rotate(hitInfo)) && (!Physics.Raycast(base.transform.position + new Vector3(0f, 1f, 1f), -base.transform.up, out hitInfo, 1f, layermask, QueryTriggerInteraction.Ignore) || !Rotate(hitInfo)) && Physics.Raycast(base.transform.position + new Vector3(0f, 1f, -1f), -base.transform.up, out hitInfo, 1f, layermask, QueryTriggerInteraction.Ignore)) + { + Rotate(hitInfo); + } + } + + private bool Rotate(RaycastHit hit) + { + if (hit.collider.GetComponent<IronVein>() == null) + { + return false; + } + if ((double)Mathf.Abs(hit.collider.transform.position.y - base.transform.position.y) > 0.001) + { + return false; + } + base.transform.LookAt(hit.collider.transform.position, Vector3.up); + gathering = true; + SetBonus(1); + return true; + } + + public void Demolish() + { + SpawnManager.instance.mines.Remove(this); + if (gathering) + { + SetBonus(-1); + } + } +} diff --git a/GameCode/MonsterManager.cs b/GameCode/MonsterManager.cs new file mode 100644 index 0000000..40a7a35 --- /dev/null +++ b/GameCode/MonsterManager.cs @@ -0,0 +1,43 @@ +using UnityEngine; + +public class MonsterManager : MonoBehaviour +{ + public static MonsterManager instance; + + public int extraTowerDamage; + + public int extraGoldDrop; + + public float manaDropOnDeath; + + public float speedBonus; + + public int bonusDamageOnBleed; + + public int bonusDamageOnBurn; + + public int bonusDamageOnPoison; + + public int bonusDamageOnStun; + + public float poisonSlowPercent; + + public float burnSpeedDamagePercentBonus; + + public float bleedingCritChance; + + public float bleedPop; + + public float burnPop; + + public float poisonPop; + + public float slowCapModifier; + + public float hasteCapModifier; + + private void Awake() + { + instance = this; + } +} diff --git a/GameCode/MonsterManualEntry.cs b/GameCode/MonsterManualEntry.cs new file mode 100644 index 0000000..6c5156c --- /dev/null +++ b/GameCode/MonsterManualEntry.cs @@ -0,0 +1,63 @@ +using UnityEngine; +using UnityEngine.UI; + +public class MonsterManualEntry : MonoBehaviour +{ + [SerializeField] + private int level; + + [SerializeField] + private Enemy prefab; + + [SerializeField] + private Text titleText; + + [SerializeField] + private Text descriptionText; + + [SerializeField] + private Image img; + + [SerializeField] + private Sprite unknownSprite; + + private void Start() + { + int b = 0; + b = Mathf.Max(PlayerPrefs.GetInt("Record1", 0), b); + b = Mathf.Max(PlayerPrefs.GetInt("Record2", 0), b); + b = Mathf.Max(PlayerPrefs.GetInt("Record3", 0), b); + if (b + 1 < prefab.level) + { + titleText.text = "???"; + descriptionText.text = "???"; + img.sprite = unknownSprite; + return; + } + string text = descriptionText.text; + string text2 = ""; + text2 = text2 + "Speed: " + prefab.baseSpeed; + text2 = text2 + "| Health: " + prefab.baseHealth; + if (prefab.baseArmor > 0) + { + text2 = text2 + "| Armor: " + prefab.baseArmor; + } + if (prefab.baseShield > 0) + { + text2 = text2 + "| Shield: " + prefab.baseShield; + } + if (prefab.healthRegen > 0) + { + text2 = text2 + "| Heal: " + prefab.healthRegen + "/sec"; + } + if (prefab.armorRegen > 0) + { + text2 = text2 + "| Armor repair: " + prefab.armorRegen + "/sec"; + } + if (prefab.shieldRegen > 0) + { + text2 = text2 + "| Shield regen: " + prefab.shieldRegen + "/sec"; + } + descriptionText.text = text2 + "\n" + text; + } +} diff --git a/GameCode/MonsterUpgradeCard.cs b/GameCode/MonsterUpgradeCard.cs new file mode 100644 index 0000000..d78ab81 --- /dev/null +++ b/GameCode/MonsterUpgradeCard.cs @@ -0,0 +1,57 @@ +using UnityEngine; +using UnityEngine.UI; + +public class MonsterUpgradeCard : UpgradeCard +{ + [SerializeField] + private GameObject banditObject; + + [SerializeField] + private Text banditText; + + [SerializeField] + private int extraTowerDamage; + + [SerializeField] + private int extraGoldDrop; + + [SerializeField] + private float manaDropOnDeath; + + [SerializeField] + private float speedBonus; + + [SerializeField] + private float slowCapMod; + + [SerializeField] + private float hasteCapMod; + + public override void Upgrade() + { + base.Upgrade(); + MonsterManager.instance.extraTowerDamage += extraTowerDamage; + MonsterManager.instance.extraGoldDrop += extraGoldDrop; + MonsterManager.instance.manaDropOnDeath += manaDropOnDeath; + MonsterManager.instance.speedBonus += speedBonus; + MonsterManager.instance.slowCapModifier += slowCapMod; + MonsterManager.instance.hasteCapModifier += hasteCapMod; + if (extraGoldDrop > 0) + { + banditObject.SetActive(value: true); + banditText.text = "+" + MonsterManager.instance.extraGoldDrop + "g"; + } + if (manaDropOnDeath > 0f) + { + ResourceManager.instance.UpdateManaHUD(); + } + if ((double)MonsterManager.instance.slowCapModifier >= 0.3) + { + AchievementManager.instance.UnlockAchievement("MaxSlow"); + } + if (MonsterManager.instance.hasteCapModifier <= -0.6f) + { + AchievementManager.instance.UnlockAchievement("MaxHaste"); + } + } +} diff --git a/GameCode/Morter.cs b/GameCode/Morter.cs new file mode 100644 index 0000000..2170da3 --- /dev/null +++ b/GameCode/Morter.cs @@ -0,0 +1,39 @@ +using UnityEngine; + +public class Morter : Tower +{ + protected override void AimTurret() + { + } + + protected override void Fire() + { + if (consumesMana) + { + int manaCost = (int)((float)base.damage * finalManaConsumption); + if (!ResourceManager.instance.CheckMana(manaCost)) + { + return; + } + ResourceManager.instance.SpendMana(manaCost); + } + float num = projectileSpeed * Mathf.Clamp(Vector3.SqrMagnitude(currentTarget.transform.position - base.transform.position) / (2f * baseRange * baseRange), 1f, float.MaxValue); + Vector3 vector = currentTarget.GetComponent<Enemy>().GetFuturePosition(num) - turret.transform.position; + GameObject gameObject = Object.Instantiate(rotation: Quaternion.LookRotation(new Vector3(vector.x, 0f, vector.z), Vector3.up), original: projectile, position: muzzle.position); + gameObject.GetComponent<Projectile>().SetStats(towerType, currentTarget, num, base.damage, base.healthDamage, base.armorDamage, base.shieldDamage, base.slowPercent, base.bleedPercent, base.burnPercent, base.poisonPercent, base.critChance, base.stunChance); + gameObject.GetComponent<MorterShell>().SetMorterPhysics(currentTarget.GetComponent<Enemy>().GetFuturePosition(num)); + gameObject.GetComponent<MorterShell>().blastRadius = base.blastRadius; + if (extraProjectileFX != null) + { + GameObject gameObject2 = Object.Instantiate(extraProjectileFX, gameObject.transform.position, gameObject.transform.rotation); + gameObject2.transform.SetParent(gameObject.transform); + gameObject2.GetComponent<ProjectileFX>().SetFX(base.bleedPercent, base.burnPercent, base.poisonPercent, base.slowPercent, consumesMana); + Projectile component = gameObject.GetComponent<Projectile>(); + if (component.detachOnDestruction == null) + { + component.detachOnDestruction = gameObject2; + component.extraFX = gameObject2.GetComponent<ProjectileFX>(); + } + } + } +} diff --git a/GameCode/MorterShell.cs b/GameCode/MorterShell.cs new file mode 100644 index 0000000..ce93441 --- /dev/null +++ b/GameCode/MorterShell.cs @@ -0,0 +1,81 @@ +using UnityEngine; + +public class MorterShell : Projectile +{ + [SerializeField] + private GameObject artObject; + + [SerializeField] + private LayerMask layersAffectedByBlast; + + public float blastRadius = 1f; + + private Vector3 destination; + + private float timeOfFlight; + + [SerializeField] + private float vSpeed; + + [SerializeField] + private float hSpeed; + + [SerializeField] + private float gravity = 5f; + + [SerializeField] + private GameObject explosion; + + private float lookAhead; + + private Vector3 previousPos; + + public void SetMorterPhysics(Vector3 pos) + { + destination = pos; + timeOfFlight = speed; + vSpeed = gravity * timeOfFlight / 2f; + hSpeed = Vector3.Magnitude(base.transform.position - destination) / timeOfFlight; + lookAhead = vSpeed + hSpeed; + } + + protected override void MoveProjectile() + { + previousPos = base.transform.position; + base.transform.Translate(Vector3.forward * hSpeed * Time.fixedDeltaTime); + base.transform.Translate(Vector3.up * vSpeed * Time.fixedDeltaTime); + vSpeed -= gravity * Time.fixedDeltaTime; + artObject.transform.rotation = Quaternion.LookRotation(base.transform.position - previousPos, Vector3.up); + } + + protected override void CheckForHits() + { + if (!(vSpeed > 0f) && Physics.Raycast(artObject.transform.position, artObject.transform.forward, out var hitInfo, lookAhead * Time.fixedDeltaTime, layermask, QueryTriggerInteraction.Collide)) + { + OnHit(hitInfo); + } + } + + protected override void OnHit(RaycastHit hit) + { + Collider[] array = Physics.OverlapSphere(base.transform.position, blastRadius, layersAffectedByBlast, QueryTriggerInteraction.Collide); + for (int i = 0; i < array.Length; i++) + { + IDamageable component = array[i].GetComponent<IDamageable>(); + if (component != null) + { + DealDamage(component); + } + } + if (detachOnDestruction != null) + { + detachOnDestruction.transform.parent = null; + } + if (extraFX != null) + { + extraFX.OnDetach(); + } + Object.Instantiate(explosion, base.transform.position, Quaternion.identity); + Object.Destroy(base.gameObject); + } +} diff --git a/GameCode/MusicManager.cs b/GameCode/MusicManager.cs new file mode 100644 index 0000000..8a39705 --- /dev/null +++ b/GameCode/MusicManager.cs @@ -0,0 +1,164 @@ +using System.Collections; +using UnityEngine; + +public class MusicManager : MonoBehaviour +{ + public static MusicManager instance; + + [SerializeField] + private AudioSource[] hard; + + [SerializeField] + private AudioSource[] soft; + + [SerializeField] + private int currentSorceIndex; + + [SerializeField] + private int currentSong; + + private float currentSongLoopDuration; + + [SerializeField] + private AudioClip[] hardTracks; + + [SerializeField] + private AudioClip[] softTracks; + + [SerializeField] + private int[] BPMin; + + [SerializeField] + private int[] BPMeasure; + + [SerializeField] + private int[] measures; + + private int intensity = 1; + + private void Awake() + { + instance = this; + } + + private void Start() + { + PlaySong(0, action: false); + } + + private void Update() + { + if (hard[currentSorceIndex].time >= currentSongLoopDuration) + { + int num = (currentSorceIndex + 1) % 2; + hard[num].Stop(); + soft[num].Stop(); + hard[num].Play(); + soft[num].Play(); + currentSorceIndex = num; + } + int num2 = (currentSorceIndex + 1) % 2; + if (hard[num2].time >= hard[num2].clip.length - 0.1f) + { + hard[num2].Stop(); + soft[num2].Stop(); + } + } + + public void SetIntensity(bool action) + { + int num = (action ? 1 : 0); + if (num != intensity) + { + intensity = num; + StartCoroutine(CrossFade(intensity)); + } + } + + public void UpdateVolume(float newVolume) + { + hard[0].volume = newVolume * (float)intensity; + hard[1].volume = newVolume * (float)intensity; + soft[0].volume = newVolume * (float)(1 - intensity); + soft[1].volume = newVolume * (float)(1 - intensity); + } + + public void PlaySong(int songNumber, bool action) + { + StopAllCoroutines(); + hard[0].Stop(); + hard[1].Stop(); + soft[0].Stop(); + soft[1].Stop(); + currentSong = songNumber; + currentSongLoopDuration = (float)(60 * measures[currentSong] * BPMeasure[currentSong]) / (float)BPMin[currentSong]; + hard[0].clip = hardTracks[currentSong]; + hard[1].clip = hardTracks[currentSong]; + soft[0].clip = softTracks[currentSong]; + soft[1].clip = softTracks[currentSong]; + intensity = (action ? 1 : 0); + float num = OptionsMenu.instance.masterVolume * OptionsMenu.instance.musicVolume; + hard[0].volume = (float)intensity * num; + hard[1].volume = (float)intensity * num; + soft[0].volume = (float)(1 - intensity) * num; + soft[1].volume = (float)(1 - intensity) * num; + currentSorceIndex = 0; + hard[0].Play(); + soft[0].Play(); + } + + private IEnumerator CrossFade(int newIntensity) + { + float startIntensity = ((newIntensity != 1) ? 1 : 0); + float vMod = OptionsMenu.instance.masterVolume * OptionsMenu.instance.musicVolume; + float fadeTime = 2f; + int saftyCount = 0; + for (float f = startIntensity; f != (startIntensity + 1f) % 2f; f = Mathf.Clamp(f + Time.unscaledDeltaTime * ((float)newIntensity - startIntensity) / fadeTime, 0f, 1f)) + { + hard[0].volume = f * vMod; + hard[1].volume = f * vMod; + soft[0].volume = (1f - f) * vMod; + soft[1].volume = (1f - f) * vMod; + yield return null; + saftyCount++; + if ((float)saftyCount > 1000f * fadeTime) + { + Debug.LogError("Possible infinite loop"); + break; + } + } + hard[0].volume = (float)newIntensity * vMod; + hard[1].volume = (float)newIntensity * vMod; + soft[0].volume = (float)(1 - newIntensity) * vMod; + soft[1].volume = (float)(1 - newIntensity) * vMod; + } + + public void FadeOut(float t) + { + StartCoroutine(FadeOutCo(t)); + } + + private IEnumerator FadeOutCo(float fadeTime) + { + float vMod = OptionsMenu.instance.masterVolume * OptionsMenu.instance.musicVolume; + int saftyCount = 0; + for (float f = 1f; f > 0f; f -= Time.unscaledDeltaTime / fadeTime) + { + hard[0].volume = (float)intensity * vMod * f; + hard[1].volume = (float)intensity * vMod * f; + soft[0].volume = (float)(1 - intensity) * vMod * f; + soft[1].volume = (float)(1 - intensity) * vMod * f; + yield return null; + saftyCount++; + if ((float)saftyCount > 1000f * fadeTime) + { + Debug.LogError("Possible infinite loop"); + break; + } + } + hard[0].volume = 0f; + hard[1].volume = 0f; + soft[0].volume = 0f; + soft[1].volume = 0f; + } +} diff --git a/GameCode/Obelisk.cs b/GameCode/Obelisk.cs new file mode 100644 index 0000000..549f3b4 --- /dev/null +++ b/GameCode/Obelisk.cs @@ -0,0 +1,99 @@ +using UnityEngine; + +public class Obelisk : Tower +{ + [SerializeField] + private GameObject beam; + + [SerializeField] + private AudioSource audioS; + + private bool soundPlaying; + + private IDamageable lastThingIHit; + + private float timeOnTarget; + + protected override void Update() + { + if (currentTarget != null) + { + if (turret != null) + { + AimTurret(); + } + GainXP(); + } + else + { + beam.SetActive(value: false); + PlaySound(onOff: false); + } + timeSinceLastShot += Time.deltaTime; + if (currentTarget != null && timeSinceLastShot > rps) + { + Fire(); + timeSinceLastShot = 0f; + } + } + + protected override void Fire() + { + if (consumesMana) + { + int manaCost = (int)((float)base.damage * manaConsumptionRate); + if (!ResourceManager.instance.CheckMana(manaCost)) + { + beam.SetActive(value: false); + PlaySound(onOff: false); + return; + } + ResourceManager.instance.SpendMana(manaCost); + } + DealDamage(); + } + + protected override void AimTurret() + { + Vector3 forward = currentTarget.transform.position - turret.transform.position + Vector3.up * 0.5f; + Quaternion rotation = Quaternion.LookRotation(forward, Vector3.up); + turret.transform.rotation = rotation; + beam.transform.localScale = new Vector3(1f, 1f, forward.magnitude); + } + + private void DealDamage() + { + IDamageable component = currentTarget.GetComponent<IDamageable>(); + if (component != null) + { + if (component == lastThingIHit) + { + timeOnTarget += rps; + } + else + { + timeOnTarget = 0f; + lastThingIHit = component; + } + int num = Mathf.Clamp(Mathf.FloorToInt(timeOnTarget * TowerManager.instance.obeliskTimeOnTargetMultiplier), 0, base.damage); + component.TakeDamage(towerType, base.damage + num, base.healthDamage, base.armorDamage, base.shieldDamage, base.slowPercent, base.bleedPercent, base.burnPercent, base.poisonPercent, base.critChance, base.stunChance); + beam.SetActive(value: true); + PlaySound(onOff: true); + } + } + + private void PlaySound(bool onOff) + { + if (onOff && !soundPlaying) + { + audioS.volume = OptionsMenu.instance.masterVolume * OptionsMenu.instance.sfxVolume; + audioS.Play(); + soundPlaying = true; + } + else if (!onOff && soundPlaying) + { + audioS.Stop(); + soundPlaying = false; + } + } +} diff --git a/GameCode/ObjectPool.cs b/GameCode/ObjectPool.cs new file mode 100644 index 0000000..feb9c40 --- /dev/null +++ b/GameCode/ObjectPool.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using UnityEngine; + +public class ObjectPool : MonoBehaviour +{ + public enum ObjectType + { + DamageNumber + } + + public static ObjectPool instance; + + [SerializeField] + private GameObject damageNumberPrefab; + + [SerializeField] + private List<GameObject> pooledDamageNumbers = new List<GameObject>(); + + private void Awake() + { + instance = this; + } + + public GameObject SpawnObject(ObjectType type, Vector3 position, Quaternion rotation) + { + if (type == ObjectType.DamageNumber) + { + return SpawnDamageNumber(position, rotation); + } + Debug.LogError("Failed to spawn object from pool"); + return null; + } + + private GameObject SpawnDamageNumber(Vector3 position, Quaternion rotation) + { + while (pooledDamageNumbers.Count > 0 && pooledDamageNumbers[0] == null) + { + pooledDamageNumbers.RemoveAt(0); + } + if (pooledDamageNumbers.Count > 0) + { + GameObject gameObject = pooledDamageNumbers[0]; + pooledDamageNumbers.Remove(gameObject); + gameObject.SetActive(value: true); + gameObject.transform.position = position; + gameObject.transform.rotation = rotation; + gameObject.GetComponent<DamageNumber>().Start(); + return gameObject; + } + return Object.Instantiate(damageNumberPrefab, position, rotation); + } + + public void PoolDamageNumber(GameObject damageNumber) + { + pooledDamageNumbers.Add(damageNumber); + damageNumber.SetActive(value: false); + } +} diff --git a/GameCode/OptionsMenu.cs b/GameCode/OptionsMenu.cs new file mode 100644 index 0000000..7377cfd --- /dev/null +++ b/GameCode/OptionsMenu.cs @@ -0,0 +1,187 @@ +using UnityEngine; +using UnityEngine.UI; + +public class OptionsMenu : MonoBehaviour +{ + public static OptionsMenu instance; + + public bool showConditionText; + + public bool showDamageNumbers = true; + + public bool extraProjectileEffects = true; + + public float masterVolume; + + public float musicVolume; + + public float sfxVolume; + + [SerializeField] + private Transform[] scalableUIs; + + public float uiScale; + + [SerializeField] + private Toggle showDamageToggle; + + [SerializeField] + private Toggle showConditionToggle; + + [SerializeField] + private Toggle projectileFXToggle; + + [SerializeField] + private Slider masterVolumeSlider; + + [SerializeField] + private Slider musicVolumeSlider; + + [SerializeField] + private Slider sfxVolumeSlider; + + [SerializeField] + private Slider uiScaleSlider; + + private float timer = 1f; + + private void Awake() + { + instance = this; + } + + private void Update() + { + if (timer >= 0f) + { + timer -= Time.deltaTime; + } + } + + private void Start() + { + if (PlayerPrefs.GetInt("ShowConditionText", 0) == 1) + { + showConditionText = true; + } + else + { + showConditionText = false; + } + if (showConditionToggle != null) + { + showConditionToggle.isOn = showConditionText; + } + if (PlayerPrefs.GetInt("ShowDamageNumbers", 1) == 1) + { + showDamageNumbers = true; + } + else + { + showDamageNumbers = false; + } + if (showDamageToggle != null) + { + showDamageToggle.isOn = showDamageNumbers; + } + if (PlayerPrefs.GetInt("ExtraProjectileFX", 1) == 1) + { + extraProjectileEffects = true; + } + else + { + extraProjectileEffects = false; + } + if (projectileFXToggle != null) + { + projectileFXToggle.isOn = extraProjectileEffects; + } + masterVolume = PlayerPrefs.GetFloat("MasterVolume", 1f); + musicVolume = PlayerPrefs.GetFloat("MusicVolume", 0.5f); + sfxVolume = PlayerPrefs.GetFloat("SFXVolume", 0.5f); + masterVolumeSlider.value = masterVolume; + musicVolumeSlider.value = musicVolume; + sfxVolumeSlider.value = sfxVolume; + if (uiScaleSlider != null) + { + uiScale = PlayerPrefs.GetFloat("UIScale", 0.5f); + uiScaleSlider.value = uiScale; + } + } + + public void ToggleDamageNumbers() + { + showDamageNumbers = showDamageToggle.isOn; + PlayerPrefs.SetInt("ShowDamageNumbers", showDamageNumbers ? 1 : 0); + if (timer < 0f) + { + SFXManager.instance.ButtonClick(); + } + } + + public void ToggleConditionTexts() + { + showConditionText = showConditionToggle.isOn; + PlayerPrefs.SetInt("ShowConditionText", showConditionText ? 1 : 0); + if (timer < 0f) + { + SFXManager.instance.ButtonClick(); + } + } + + public void ToggleProjectileFX() + { + extraProjectileEffects = projectileFXToggle.isOn; + PlayerPrefs.SetInt("ExtraProjectileFX", extraProjectileEffects ? 1 : 0); + if (timer < 0f) + { + SFXManager.instance.ButtonClick(); + } + } + + public void ChangeMasterVolume() + { + masterVolume = masterVolumeSlider.value; + PlayerPrefs.SetFloat("MasterVolume", masterVolume); + if (MusicManager.instance != null) + { + MusicManager.instance.UpdateVolume(masterVolume * musicVolume); + } + if (SFXManager.instance != null) + { + SFXManager.instance.volume = masterVolume * sfxVolume; + } + } + + public void ChangeMusicVolume() + { + musicVolume = musicVolumeSlider.value; + PlayerPrefs.SetFloat("MusicVolume", musicVolume); + if (MusicManager.instance != null) + { + MusicManager.instance.UpdateVolume(masterVolume * musicVolume); + } + } + + public void ChangeSFXVolume() + { + sfxVolume = sfxVolumeSlider.value; + PlayerPrefs.SetFloat("SFXVolume", sfxVolume); + if (SFXManager.instance != null) + { + SFXManager.instance.volume = masterVolume * sfxVolume; + } + } + + public void ChangeUIScale() + { + uiScale = uiScaleSlider.value; + PlayerPrefs.SetFloat("UIScale", uiScale); + float num = Mathf.Max(uiScale + 0.5f, (uiScale + 0.5f) * 2f - 1f); + Transform[] array = scalableUIs; + for (int i = 0; i < array.Length; i++) + { + array[i].localScale = num * Vector3.one; + } + } +} diff --git a/GameCode/ParticleBeam.cs b/GameCode/ParticleBeam.cs new file mode 100644 index 0000000..6a7bf2a --- /dev/null +++ b/GameCode/ParticleBeam.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +public class ParticleBeam : Projectile +{ + [SerializeField] + private GameObject beamTrail; + + protected override void MoveProjectile() + { + base.MoveProjectile(); + beamTrail.transform.position = base.transform.position + new Vector3(Random.Range(-1f, 1f), Random.Range(0f, 1f), Random.Range(-1f, 1f)); + } + + protected new virtual void OnHit(RaycastHit hit) + { + beamTrail.transform.position = hit.point; + base.OnHit(hit); + } +} diff --git a/GameCode/Pathfinder.cs b/GameCode/Pathfinder.cs new file mode 100644 index 0000000..5426574 --- /dev/null +++ b/GameCode/Pathfinder.cs @@ -0,0 +1,91 @@ +using UnityEngine; + +public class Pathfinder : MonoBehaviour +{ + public float distanceFromEnd = 2.1474836E+09f; + + public bool atEnd; + + public float speed = 1f; + + public Waypoint currentWaypoint; + + [SerializeField] + private Enemy enemyScript; + + private void Start() + { + if (enemyScript == null) + { + enemyScript = GetComponent<Enemy>(); + } + } + + private void FixedUpdate() + { + CheckWaypointDistance(); + Move(); + } + + private void Move() + { + Vector3 vector = currentWaypoint.transform.position - base.transform.position; + vector.Normalize(); + base.transform.Translate(vector * speed * Time.fixedDeltaTime); + distanceFromEnd -= speed * Time.fixedDeltaTime; + } + + private void CheckWaypointDistance() + { + if (Vector3.SqrMagnitude(currentWaypoint.transform.position - base.transform.position) < 4f * speed * speed * Time.fixedDeltaTime * Time.fixedDeltaTime && !GetNewWaypoint()) + { + atEnd = true; + enemyScript.AtEnd(); + } + } + + public Vector3 GetFuturePosition(float distance) + { + Vector3 position = base.transform.position; + Waypoint nextWaypoint = currentWaypoint; + float num = distance; + int num2 = 0; + while (num > 0f) + { + if (Vector3.SqrMagnitude(nextWaypoint.transform.position - position) >= num * num) + { + return position + (nextWaypoint.transform.position - position).normalized * num; + } + if (nextWaypoint.GetNextWaypoint() == nextWaypoint) + { + return nextWaypoint.transform.position; + } + num -= Vector3.Magnitude(nextWaypoint.transform.position - position); + position = nextWaypoint.transform.position; + nextWaypoint = nextWaypoint.GetNextWaypoint(); + num2++; + if (num2 > 100) + { + Debug.LogError("GetFuturePosition looping too much"); + break; + } + } + Debug.LogError("GetFuturePosition broken"); + return Vector3.zero; + } + + private bool GetNewWaypoint() + { + if (currentWaypoint.GetNextWaypoint() == currentWaypoint) + { + return false; + } + distanceFromEnd = currentWaypoint.distanceFromEnd; + currentWaypoint = currentWaypoint.GetNextWaypoint(); + if (distanceFromEnd <= 24f) + { + enemyScript.CheckBattleCries(BattleCry.BattleCryTrigger.NearEnd); + } + return true; + } +} diff --git a/GameCode/PauseMenu.cs b/GameCode/PauseMenu.cs new file mode 100644 index 0000000..0ccfc28 --- /dev/null +++ b/GameCode/PauseMenu.cs @@ -0,0 +1,140 @@ +using UnityEngine; + +public class PauseMenu : MonoBehaviour +{ + [SerializeField] + private KeyCode pauseKey1; + + [SerializeField] + private KeyCode pauseKey2; + + [SerializeField] + private KeyCode hideUIKey; + + [SerializeField] + private KeyCode damageTrackerKey; + + [SerializeField] + private GameObject pauseMenu; + + [SerializeField] + private GameObject areYouSureMenu; + + [SerializeField] + private GameObject optionsMenu; + + [SerializeField] + private GameObject[] hideableUI; + + [SerializeField] + private GameObject[] hideableWithTracker; + + private bool uiHidden; + + private bool trackerHidden = true; + + public bool paused; + + public static PauseMenu instance; + + private void Awake() + { + instance = this; + } + + private void Update() + { + if (Input.GetKeyDown(pauseKey1) || Input.GetKeyDown(pauseKey2)) + { + if (!paused) + { + UnHideUI(); + Pause(); + } + else + { + UnPause(); + } + } + if (Input.GetKeyDown(hideUIKey)) + { + if (uiHidden) + { + UnHideUI(); + } + else + { + hideUI(); + } + } + if (Input.GetKeyDown(damageTrackerKey)) + { + if (trackerHidden) + { + UnHideTracker(); + } + else + { + HideTracker(); + } + } + } + + public void Pause() + { + paused = true; + Time.timeScale = 0f; + pauseMenu.SetActive(value: true); + } + + public void UnPause() + { + pauseMenu.SetActive(value: false); + areYouSureMenu.SetActive(value: false); + optionsMenu.SetActive(value: false); + Time.timeScale = 1f; + paused = false; + } + + public void hideUI() + { + uiHidden = true; + GameObject[] array = hideableUI; + for (int i = 0; i < array.Length; i++) + { + array[i].SetActive(value: false); + } + } + + public void UnHideUI() + { + uiHidden = false; + GameObject[] array = hideableUI; + for (int i = 0; i < array.Length; i++) + { + array[i].SetActive(value: true); + } + } + + public void HideTracker() + { + trackerHidden = true; + DamageTracker.instance.uiObject.SetActive(value: false); + GameObject[] array = hideableWithTracker; + for (int i = 0; i < array.Length; i++) + { + array[i].SetActive(value: false); + } + } + + public void UnHideTracker() + { + trackerHidden = false; + DamageTracker.instance.DisplayDamageTotals(); + GameObject[] array = hideableWithTracker; + for (int i = 0; i < array.Length; i++) + { + array[i].SetActive(value: true); + } + } +} diff --git a/GameCode/PlayMenu.cs b/GameCode/PlayMenu.cs new file mode 100644 index 0000000..19514b3 --- /dev/null +++ b/GameCode/PlayMenu.cs @@ -0,0 +1,27 @@ +using UnityEngine; +using UnityEngine.UI; + +public class PlayMenu : MonoBehaviour +{ + [SerializeField] + private Text record1Text; + + [SerializeField] + private Text record2Text; + + [SerializeField] + private Text record3Text; + + private void Start() + { + record1Text.text = "Current Record\nLevel " + PlayerPrefs.GetInt("Record1", 0); + record2Text.text = "Current Record\nLevel " + PlayerPrefs.GetInt("Record2", 0); + record3Text.text = "Current Record\nLevel " + PlayerPrefs.GetInt("Record3", 0); + } + + public void StartGame(int mode) + { + PlayerPrefs.SetInt("GameMode", Mathf.Clamp(mode, 1, 3)); + LevelLoader.instance.LoadLevel("GameScene"); + } +} diff --git a/GameCode/Projectile.cs b/GameCode/Projectile.cs new file mode 100644 index 0000000..3c15fe4 --- /dev/null +++ b/GameCode/Projectile.cs @@ -0,0 +1,141 @@ +using UnityEngine; + +public class Projectile : MonoBehaviour +{ + [SerializeField] + protected Sound launchSound; + + [SerializeField] + protected Sound hitSound; + + protected TowerType shotBy; + + [SerializeField] + protected LayerMask layermask; + + [SerializeField] + protected float speed; + + [SerializeField] + protected bool homing; + + [SerializeField] + protected float maximumLifeTime = 10f; + + [SerializeField] + public GameObject detachOnDestruction; + + [SerializeField] + public ProjectileFX extraFX; + + protected GameObject target; + + protected int damage; + + protected int healthDamage; + + protected int armorDamage; + + protected int shieldDamage; + + protected float slowPercent; + + protected float bleedPercent; + + protected float burnPercent; + + protected float poisonPercent; + + protected float critChance; + + protected float stunChance; + + protected virtual void Start() + { + if (launchSound != 0) + { + SFXManager.instance.PlaySound(launchSound, base.transform.position); + } + } + + protected virtual void FixedUpdate() + { + maximumLifeTime -= Time.fixedDeltaTime; + if (maximumLifeTime < 0f) + { + Object.Destroy(base.gameObject); + } + CheckForHits(); + MoveProjectile(); + if (homing) + { + AlterCourse(); + } + } + + public virtual void SetStats(TowerType whoShotMe, GameObject _target, float spd, int dmg, int healthDmg, int armorDmg, int shieldDmg, float slow, float bleed, float burn, float poison, float crit, float stun) + { + shotBy = whoShotMe; + target = _target; + speed = spd; + damage = dmg; + healthDamage = healthDmg; + armorDamage = armorDmg; + shieldDamage = shieldDmg; + slowPercent = slow; + bleedPercent = bleed; + burnPercent = burn; + poisonPercent = poison; + critChance = crit; + stunChance = stun; + } + + protected virtual void MoveProjectile() + { + base.transform.Translate(Vector3.forward * speed * Time.fixedDeltaTime); + } + + protected virtual void AlterCourse() + { + if (!(target == null)) + { + Quaternion rotation = Quaternion.LookRotation(0.25f * Vector3.up + target.transform.position - base.transform.position, Vector3.up); + base.transform.rotation = rotation; + } + } + + protected virtual void CheckForHits() + { + if (Physics.Raycast(base.transform.position, base.transform.forward, out var hitInfo, speed * Time.fixedDeltaTime, layermask, QueryTriggerInteraction.Collide)) + { + OnHit(hitInfo); + } + } + + protected virtual void OnHit(RaycastHit hit) + { + IDamageable component = hit.transform.GetComponent<IDamageable>(); + if (component != null) + { + DealDamage(component); + } + if (detachOnDestruction != null) + { + detachOnDestruction.transform.parent = null; + } + if (extraFX != null) + { + extraFX.OnDetach(); + } + Object.Destroy(base.gameObject); + } + + protected virtual void DealDamage(IDamageable target) + { + target.TakeDamage(shotBy, damage, healthDamage, armorDamage, shieldDamage, slowPercent, bleedPercent, burnPercent, poisonPercent, critChance, stunChance); + if (hitSound != 0) + { + SFXManager.instance.PlaySound(hitSound, base.transform.position); + } + } +} diff --git a/GameCode/ProjectileFX.cs b/GameCode/ProjectileFX.cs new file mode 100644 index 0000000..df82c3d --- /dev/null +++ b/GameCode/ProjectileFX.cs @@ -0,0 +1,47 @@ +using System.Collections; +using UnityEngine; + +public class ProjectileFX : MonoBehaviour +{ + [SerializeField] + private GameObject bleedingPS; + + [SerializeField] + private GameObject burrningPS; + + [SerializeField] + private GameObject poisonPS; + + public void SetFX(float bleeding, float burning, float poison, float slow, bool arcane) + { + if (OptionsMenu.instance.extraProjectileEffects) + { + if (bleeding > 0f) + { + bleedingPS.SetActive(value: true); + } + if (burning > 0f) + { + burrningPS.SetActive(value: true); + } + if (poison > 0f) + { + poisonPS.SetActive(value: true); + } + } + } + + public void OnDetach() + { + StartCoroutine(Die()); + } + + private IEnumerator Die() + { + bleedingPS.GetComponent<ParticleSystem>().Stop(withChildren: true); + burrningPS.GetComponent<ParticleSystem>().Stop(withChildren: true); + poisonPS.GetComponent<ParticleSystem>().Stop(withChildren: true); + yield return new WaitForSeconds(1.1f); + Object.Destroy(base.gameObject); + } +} diff --git a/GameCode/RadarTower.cs b/GameCode/RadarTower.cs new file mode 100644 index 0000000..e0d8d1d --- /dev/null +++ b/GameCode/RadarTower.cs @@ -0,0 +1,71 @@ +using UnityEngine; + +public class RadarTower : Tower +{ + [SerializeField] + private GameObject biPlanePrefab; + + [SerializeField] + private BiPlane myPlane; + + protected override void Start() + { + if (myPlane == null) + { + myPlane = Object.Instantiate(biPlanePrefab, base.transform.position + new Vector3(-50f, 5f, 0f), Quaternion.identity).GetComponent<BiPlane>(); + } + base.Start(); + } + + public override void SetStats() + { + base.SetStats(); + if (myPlane == null) + { + myPlane = Object.Instantiate(biPlanePrefab, base.transform.position + new Vector3(-50f, 5f, 0f), Quaternion.identity).GetComponent<BiPlane>(); + } + myPlane.damage = base.damage; + myPlane.healthDamage = base.healthDamage; + myPlane.armorDamage = base.armorDamage; + myPlane.shieldDamage = base.shieldDamage; + myPlane.rps = rps; + myPlane.slowPercent = base.slowPercent; + myPlane.bleedPercent = base.bleedPercent; + myPlane.burnPercent = base.burnPercent; + myPlane.poisonPercent = base.poisonPercent; + myPlane.critChance = base.critChance; + myPlane.stunChance = base.stunChance; + } + + protected override void Update() + { + if (currentTarget != null) + { + if (turret != null) + { + AimTurret(); + } + GainXP(); + } + timeSinceLastShot += Time.deltaTime; + if (currentTarget != null && timeSinceLastShot > 3f) + { + SendTargetInfo(currentTarget); + timeSinceLastShot = 0f; + } + } + + private void SendTargetInfo(GameObject target) + { + if (myPlane.target == null) + { + myPlane.target = target; + } + } + + public override void Demolish() + { + Object.Destroy(myPlane.gameObject); + base.Demolish(); + } +} diff --git a/GameCode/ResourceManager.cs b/GameCode/ResourceManager.cs new file mode 100644 index 0000000..5b9867f --- /dev/null +++ b/GameCode/ResourceManager.cs @@ -0,0 +1,225 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +public class ResourceManager : MonoBehaviour +{ + public static ResourceManager instance; + + [SerializeField] + private int gold; + + [SerializeField] + private Text goldText; + + [SerializeField] + private int mana; + + private float manaLoss = 1f; + + [SerializeField] + private int maxMana; + + [SerializeField] + private int manaGatherRate; + + [SerializeField] + private Text manaText; + + [SerializeField] + private Image maskBar; + + [SerializeField] + private Image manaBar; + + [SerializeField] + private Image manaLossBar; + + private float manaTimer; + + private int manaGen; + + public float manaMaxRegenPercent; + + [SerializeField] + private GameObject manaHUDObject; + + [SerializeField] + private Text manaHUDText; + + public int enemyBonusGoldDrop; + + public List<ManaBank> manaBanks = new List<ManaBank>(); + + public int manaBankBonusMana; + + private void Awake() + { + instance = this; + } + + private void Start() + { + gold = 1000 + 100 * (PlayerPrefs.GetInt("StartGold1", 0) + PlayerPrefs.GetInt("StartGold2", 0) + PlayerPrefs.GetInt("StartGold3", 0) + PlayerPrefs.GetInt("StartGold4", 0) + PlayerPrefs.GetInt("StartGold5", 0) + PlayerPrefs.GetInt("StartGold6", 0) + PlayerPrefs.GetInt("StartGold7", 0) + PlayerPrefs.GetInt("StartGold8", 0) + PlayerPrefs.GetInt("StartGold9", 0) + PlayerPrefs.GetInt("StartGold10", 0)); + maxMana = 100 + 20 * (PlayerPrefs.GetInt("MaxMana1", 0) + PlayerPrefs.GetInt("MaxMana2", 0) + PlayerPrefs.GetInt("MaxMana3", 0) + PlayerPrefs.GetInt("MaxMana4", 0) + PlayerPrefs.GetInt("MaxMana5", 0)); + enemyBonusGoldDrop = PlayerPrefs.GetInt("GoldDrop1", 0) + PlayerPrefs.GetInt("GoldDrop2", 0) + PlayerPrefs.GetInt("GoldDrop3", 0) + PlayerPrefs.GetInt("GoldDrop4", 0) + PlayerPrefs.GetInt("GoldDrop5", 0); + manaGen = PlayerPrefs.GetInt("ManaGen1", 0) + PlayerPrefs.GetInt("ManaGen2", 0) + PlayerPrefs.GetInt("ManaGen3", 0); + UpdateManaGatherRate(manaGen); + SetManaBar(); + } + + private void Update() + { + if (manaLoss > (float)mana) + { + float num = 20f; + if (maxMana >= 500) + { + num = 100f; + } + manaLoss = Mathf.Clamp(manaLoss - num * Time.deltaTime, mana, manaLoss); + manaLossBar.rectTransform.sizeDelta = new Vector2(manaLoss / num, 0.25f); + } + if (manaTimer <= 0f) + { + AddMana(manaGen); + AddManaPercentMax(manaMaxRegenPercent); + manaTimer = 1f; + } + else if (manaGen > 0 && SpawnManager.instance.combat) + { + manaTimer -= Time.deltaTime; + } + } + + public void Spend(int goldCost) + { + gold -= goldCost; + UpdateResourceText(); + } + + public void AddMoney(int addedGold) + { + gold += addedGold; + UpdateResourceText(); + } + + public bool CheckMoney(int goldCost) + { + if (gold >= goldCost) + { + return true; + } + return false; + } + + public void SpendMana(int manaCost) + { + mana -= manaCost; + UpdateResourceText(); + } + + public void AddMana(int addedMana) + { + mana = Mathf.Clamp(mana + addedMana, 0, maxMana); + if (manaLoss < (float)mana) + { + manaLoss = mana; + } + UpdateResourceText(); + } + + public void AddManaPercentMax(float percent) + { + AddMana(Mathf.FloorToInt(percent * (float)maxMana)); + } + + public void AddMaxMana(int amount) + { + maxMana += amount; + float num = 20f; + if (maxMana >= 500) + { + num = 100f; + } + maskBar.rectTransform.localScale = new Vector3(num * 200f / (float)maxMana, 50f, 10f); + maskBar.rectTransform.sizeDelta = new Vector2((float)maxMana / num, 0.25f); + UpdateResourceText(); + } + + public bool CheckMana(int manaCost) + { + if (mana >= manaCost) + { + return true; + } + return false; + } + + public void UpdateManaGatherRate(int addedGatherRate) + { + manaGatherRate += addedGatherRate; + UpdateResourceText(); + } + + public void UpdateManaHUD() + { + string text = ""; + if (manaMaxRegenPercent > 0f) + { + text = text + "+" + Mathf.FloorToInt(101f * manaMaxRegenPercent) + "%/s\n"; + } + if (MonsterManager.instance.manaDropOnDeath > 0f) + { + text = text + Mathf.FloorToInt(101f * MonsterManager.instance.manaDropOnDeath) + "%/kill"; + } + if (text.Length > 1) + { + manaHUDObject.SetActive(value: true); + manaHUDText.text = text; + } + } + + public void AddPercentManaGathering(float percent) + { + manaMaxRegenPercent += percent; + UpdateResourceText(); + } + + private void UpdateResourceText() + { + goldText.text = "Gold: " + gold; + manaText.text = "Mana: " + mana + "/" + maxMana + " (+" + (manaGatherRate + Mathf.FloorToInt(manaMaxRegenPercent * (float)maxMana)) + "/s)"; + float num = 20f; + if (maxMana >= 500) + { + num = 100f; + } + manaBar.rectTransform.sizeDelta = new Vector2((float)mana / num, 0.25f); + } + + public void SetManaBar() + { + float num = 20f; + if (maxMana >= 500) + { + num = 100f; + } + maskBar.rectTransform.localScale = new Vector3(num * 200f / (float)maxMana, 50f, 10f); + maskBar.rectTransform.sizeDelta = new Vector2((float)maxMana / num, 0.25f); + manaLossBar.rectTransform.sizeDelta = new Vector2((float)maxMana / num, 0.25f); + UpdateResourceText(); + } + + public void UpgradeManaBankMaxMana(int addition) + { + manaBankBonusMana += addition; + foreach (ManaBank manaBank in manaBanks) + { + if (manaBank != null) + { + manaBank.UpgradeMaxMana(addition); + } + } + } +} diff --git a/GameCode/RogueTower.csproj b/GameCode/RogueTower.csproj new file mode 100644 index 0000000..4530366 --- /dev/null +++ b/GameCode/RogueTower.csproj @@ -0,0 +1,260 @@ +<Project Sdk="Microsoft.NET.Sdk"> + <PropertyGroup> + <AssemblyName>Assembly-CSharp</AssemblyName> + <GenerateAssemblyInfo>False</GenerateAssemblyInfo> + <TargetFramework>netstandard2.0</TargetFramework> + </PropertyGroup> + <PropertyGroup> + <LangVersion>11.0</LangVersion> + <AllowUnsafeBlocks>True</AllowUnsafeBlocks> + </PropertyGroup> + <PropertyGroup /> + <ItemGroup> + <Reference Include="Mono.Security"> + <HintPath>..\..\Rogue Tower_Data\Managed\Mono.Security.dll</HintPath> + </Reference> + <Reference Include="Newtonsoft.Json"> + <HintPath>..\..\Rogue Tower_Data\Managed\Newtonsoft.Json.dll</HintPath> + </Reference> + <Reference Include="System.Configuration"> + <HintPath>..\..\Rogue Tower_Data\Managed\System.Configuration.dll</HintPath> + </Reference> + <Reference Include="System.Diagnostics.StackTrace"> + <HintPath>..\..\Rogue Tower_Data\Managed\System.Diagnostics.StackTrace.dll</HintPath> + </Reference> + <Reference Include="System.EnterpriseServices"> + <HintPath>..\..\Rogue Tower_Data\Managed\System.EnterpriseServices.dll</HintPath> + </Reference> + <Reference Include="System.Globalization.Extensions"> + <HintPath>..\..\Rogue Tower_Data\Managed\System.Globalization.Extensions.dll</HintPath> + </Reference> + <Reference Include="System.ServiceModel.Internals"> + <HintPath>..\..\Rogue Tower_Data\Managed\System.ServiceModel.Internals.dll</HintPath> + </Reference> + <Reference Include="System.Xml.XPath.XDocument"> + <HintPath>..\..\Rogue Tower_Data\Managed\System.Xml.XPath.XDocument.dll</HintPath> + </Reference> + <Reference Include="Unity.Postprocessing.Runtime"> + <HintPath>..\..\Rogue Tower_Data\Managed\Unity.Postprocessing.Runtime.dll</HintPath> + </Reference> + <Reference Include="Unity.TextMeshPro"> + <HintPath>..\..\Rogue Tower_Data\Managed\Unity.TextMeshPro.dll</HintPath> + </Reference> + <Reference Include="Unity.Timeline"> + <HintPath>..\..\Rogue Tower_Data\Managed\Unity.Timeline.dll</HintPath> + </Reference> + <Reference Include="Unity.VisualScripting.Antlr3.Runtime"> + <HintPath>..\..\Rogue Tower_Data\Managed\Unity.VisualScripting.Antlr3.Runtime.dll</HintPath> + </Reference> + <Reference Include="Unity.VisualScripting.Core"> + <HintPath>..\..\Rogue Tower_Data\Managed\Unity.VisualScripting.Core.dll</HintPath> + </Reference> + <Reference Include="Unity.VisualScripting.Flow"> + <HintPath>..\..\Rogue Tower_Data\Managed\Unity.VisualScripting.Flow.dll</HintPath> + </Reference> + <Reference Include="Unity.VisualScripting.State"> + <HintPath>..\..\Rogue Tower_Data\Managed\Unity.VisualScripting.State.dll</HintPath> + </Reference> + <Reference Include="UnityEngine"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.AccessibilityModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.AccessibilityModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.AIModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.AIModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.AndroidJNIModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.AndroidJNIModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.AnimationModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.AnimationModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.ARModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.ARModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.AssetBundleModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.AssetBundleModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.ClothModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.ClothModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.ClusterInputModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.ClusterInputModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.ClusterRendererModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.ClusterRendererModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.CoreModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.CoreModule.dll</HintPath> + </Reference> + <Reference Include="Assembly-CSharp-firstpass"> + <HintPath>..\..\Rogue Tower_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.AudioModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.AudioModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.CrashReportingModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.CrashReportingModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.DirectorModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.DirectorModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.DSPGraphModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.DSPGraphModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.GameCenterModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.GameCenterModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.GIModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.GIModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.GridModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.GridModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.HotReloadModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.HotReloadModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.ImageConversionModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.ImageConversionModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.IMGUIModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.IMGUIModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.InputModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.InputModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.JSONSerializeModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.JSONSerializeModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.LocalizationModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.LocalizationModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.PerformanceReportingModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.PerformanceReportingModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.Physics2DModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.Physics2DModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.PhysicsModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.ProfilerModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.ProfilerModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.ScreenCaptureModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.ScreenCaptureModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.SharedInternalsModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.SharedInternalsModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.SpriteMaskModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.SpriteMaskModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.SpriteShapeModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.SpriteShapeModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.StreamingModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.StreamingModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.SubstanceModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.SubstanceModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.SubsystemsModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.SubsystemsModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.TerrainModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.TerrainModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.TerrainPhysicsModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.TerrainPhysicsModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.TextCoreModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.TextCoreModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.TextRenderingModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.TilemapModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.TilemapModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.TLSModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.TLSModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.UI"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.UI.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.ParticleSystemModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.ParticleSystemModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.InputLegacyModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.UIElementsModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.UIElementsModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.UIElementsNativeModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.UIElementsNativeModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.UIModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.UIModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.UmbraModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.UmbraModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.UNETModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.UNETModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.UnityAnalyticsModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.UnityAnalyticsModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.UnityConnectModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.UnityConnectModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.UnityCurlModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.UnityCurlModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.UnityTestProtocolModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.UnityTestProtocolModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.UnityWebRequestAssetBundleModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.UnityWebRequestAssetBundleModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.UnityWebRequestAudioModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.UnityWebRequestAudioModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.UnityWebRequestModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.UnityWebRequestModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.UnityWebRequestTextureModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.UnityWebRequestWWWModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.VehiclesModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.VehiclesModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.VFXModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.VFXModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.VideoModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.VideoModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.VirtualTexturingModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.VirtualTexturingModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.VRModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.VRModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.WindModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.WindModule.dll</HintPath> + </Reference> + <Reference Include="UnityEngine.XRModule"> + <HintPath>..\..\Rogue Tower_Data\Managed\UnityEngine.XRModule.dll</HintPath> + </Reference> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/GameCode/SFXManager.cs b/GameCode/SFXManager.cs new file mode 100644 index 0000000..9c972e5 --- /dev/null +++ b/GameCode/SFXManager.cs @@ -0,0 +1,158 @@ +using System.Collections.Generic; +using UnityEngine; + +public class SFXManager : MonoBehaviour +{ + public float volume = 0.5f; + + [SerializeField] + private AudioClip ballistaClip; + + [SerializeField] + private AudioClip mortarClip; + + [SerializeField] + private AudioClip teslaClip; + + [SerializeField] + private AudioClip[] explosions; + + [SerializeField] + private AudioClip biPlaneGunClip; + + [SerializeField] + private AudioClip particleCannonClip; + + [SerializeField] + private AudioClip shredderClip; + + [SerializeField] + private AudioClip[] ballistaHits; + + [SerializeField] + private AudioClip frostHitClip; + + [SerializeField] + private AudioClip shredderHitClip; + + [SerializeField] + private AudioClip[] bulletHits; + + [SerializeField] + private AudioClip particleHitClip; + + [SerializeField] + private AudioClip[] coinLongClips; + + [SerializeField] + private AudioClip[] coinShortClips; + + [SerializeField] + private AudioClip buttonClick; + + [SerializeField] + private AudioClip[] critSmall; + + [SerializeField] + private AudioClip[] critBig; + + [SerializeField] + private AudioClip cards; + + [SerializeField] + private GameObject sourceObject; + + public List<AudioPoolSource> sources = new List<AudioPoolSource>(); + + public static SFXManager instance; + + private void Awake() + { + instance = this; + } + + private void Start() + { + volume = OptionsMenu.instance.masterVolume * OptionsMenu.instance.sfxVolume; + } + + public void ButtonClick() + { + PlaySound(Sound.ButtonClick, MusicManager.instance.transform.position, MusicManager.instance.transform); + } + + public void PlaySound(Sound s, Vector3 pos) + { + PlaySound(s, pos, null); + } + + public void PlaySound(Sound s, Vector3 pos, Transform parent) + { + if (!(volume <= 0f)) + { + AudioClip clip = GetClip(s); + AudioPoolSource audioPoolSource; + if (sources.Count < 1) + { + audioPoolSource = Object.Instantiate(sourceObject).GetComponent<AudioPoolSource>(); + } + else + { + audioPoolSource = sources[0]; + sources.Remove(audioPoolSource); + } + audioPoolSource.transform.position = pos; + audioPoolSource.PlayClip(clip, volume, 0.08333f); + if (parent != null) + { + audioPoolSource.transform.parent = parent; + } + } + } + + private AudioClip GetClip(Sound s) + { + switch (s) + { + case Sound.Ballista: + return ballistaClip; + case Sound.Mortar: + return mortarClip; + case Sound.TeslaZap: + return teslaClip; + case Sound.Explosion: + return explosions[Random.Range(0, explosions.Length)]; + case Sound.BiPlaneGun: + return biPlaneGunClip; + case Sound.ParticleCannon: + return particleCannonClip; + case Sound.Shredder: + return shredderClip; + case Sound.BallistaHit: + return ballistaHits[Random.Range(0, ballistaHits.Length)]; + case Sound.FrostHit: + return frostHitClip; + case Sound.ShredderHit: + return shredderHitClip; + case Sound.BulletHit: + return bulletHits[Random.Range(0, bulletHits.Length)]; + case Sound.ParticleHit: + return particleHitClip; + case Sound.CoinLong: + return coinLongClips[Random.Range(0, coinLongClips.Length)]; + case Sound.CoinShort: + return coinShortClips[Random.Range(0, coinShortClips.Length)]; + case Sound.ButtonClick: + return buttonClick; + case Sound.CritSmall: + return critSmall[Random.Range(0, critSmall.Length)]; + case Sound.CritBig: + return critBig[Random.Range(0, critBig.Length)]; + case Sound.Cards: + return cards; + default: + Debug.LogError("No Audio Clip Found Type " + s); + return null; + } + } +} diff --git a/GameCode/Sawblade.cs b/GameCode/Sawblade.cs new file mode 100644 index 0000000..19038df --- /dev/null +++ b/GameCode/Sawblade.cs @@ -0,0 +1,87 @@ +using System.Collections.Generic; +using UnityEngine; + +public class Sawblade : Projectile +{ + private Pathfinder targetPathfinder; + + private Waypoint nextWaypoint; + + private bool pathMode; + + private HashSet<Collider> targetsHit = new HashSet<Collider>(); + + public override void SetStats(TowerType whoShotMe, GameObject _target, float spd, int dmg, int healthDmg, int armorDmg, int shieldDmg, float slow, float bleed, float burn, float poison, float crit, float stun) + { + base.SetStats(whoShotMe, _target, spd, dmg, healthDmg, armorDmg, shieldDmg, slow, bleed, burn, poison, crit, stun); + targetPathfinder = target.GetComponent<Pathfinder>(); + nextWaypoint = targetPathfinder.currentWaypoint; + } + + protected override void AlterCourse() + { + if (!pathMode && targetPathfinder != null) + { + nextWaypoint = targetPathfinder.currentWaypoint; + } + if (!pathMode && (target == null || Vector3.SqrMagnitude(target.transform.position - base.transform.position) < 0.125f)) + { + nextWaypoint = GetPreviousWaypoint(); + pathMode = true; + } + Vector3 position; + if (!pathMode) + { + position = target.transform.position; + } + else + { + if (Vector3.SqrMagnitude(nextWaypoint.transform.position - base.transform.position) < 0.125f) + { + nextWaypoint = GetPreviousWaypoint(); + } + position = nextWaypoint.transform.position; + } + Quaternion rotation = Quaternion.LookRotation(position - base.transform.position, Vector3.up); + base.transform.rotation = rotation; + } + + protected override void CheckForHits() + { + Collider[] array = Physics.OverlapBox(base.transform.position, Vector3.one * 0.25f, Quaternion.identity, layermask, QueryTriggerInteraction.Collide); + foreach (Collider collider in array) + { + if (!pathMode && collider.gameObject == target) + { + nextWaypoint = GetPreviousWaypoint(); + pathMode = true; + } + if (targetsHit.Contains(collider)) + { + continue; + } + IDamageable component = collider.GetComponent<IDamageable>(); + if (component != null) + { + DealDamage(component); + damage--; + if (damage <= 0) + { + Object.Destroy(base.gameObject); + } + } + targetsHit.Add(collider); + } + } + + private Waypoint GetPreviousWaypoint() + { + Waypoint[] previousWaypoints = nextWaypoint.GetPreviousWaypoints(); + if (previousWaypoints.Length == 0) + { + Object.Destroy(base.gameObject); + return nextWaypoint; + } + return previousWaypoints[Random.Range(0, previousWaypoints.Length)]; + } +} diff --git a/GameCode/Shrine.cs b/GameCode/Shrine.cs new file mode 100644 index 0000000..bbdfd2d --- /dev/null +++ b/GameCode/Shrine.cs @@ -0,0 +1,11 @@ +public class Shrine : SpawnableObject +{ + protected override void Start() + { + base.Start(); + if (spawned) + { + AchievementManager.instance.shrineSpawned = true; + } + } +} diff --git a/GameCode/SimpleUI.cs b/GameCode/SimpleUI.cs new file mode 100644 index 0000000..ec51413 --- /dev/null +++ b/GameCode/SimpleUI.cs @@ -0,0 +1,51 @@ +using UnityEngine; +using UnityEngine.UI; + +public class SimpleUI : MonoBehaviour +{ + private GameObject demolishableObject; + + private int goldBackOnDemolish; + + [SerializeField] + private Text demolishText; + + [SerializeField] + private Text discriptionText; + + [SerializeField] + private GameObject demolishButton; + + private void Start() + { + UIManager.instance.SetNewUI(base.gameObject); + } + + public void SetDemolishable(GameObject obj, int goldReturned) + { + demolishableObject = obj; + goldBackOnDemolish = goldReturned; + demolishButton.SetActive(value: true); + if (demolishText != null) + { + demolishText.text = "Demolish (" + goldBackOnDemolish + "g)"; + } + } + + public void Demolish() + { + demolishableObject.GetComponent<IBuildable>()?.Demolish(); + Object.Destroy(demolishableObject); + ResourceManager.instance.AddMoney(goldBackOnDemolish); + SFXManager.instance.ButtonClick(); + UIManager.instance.CloseUI(base.gameObject); + } + + public void SetDiscriptionText(string txt) + { + if (discriptionText != null) + { + discriptionText.text = txt; + } + } +} diff --git a/GameCode/SlowRotate.cs b/GameCode/SlowRotate.cs new file mode 100644 index 0000000..7a0306a --- /dev/null +++ b/GameCode/SlowRotate.cs @@ -0,0 +1,12 @@ +using UnityEngine; + +public class SlowRotate : MonoBehaviour +{ + [SerializeField] + private Vector3 rotation; + + private void Update() + { + base.transform.localEulerAngles += rotation * Time.deltaTime; + } +} diff --git a/GameCode/SnowFlake.cs b/GameCode/SnowFlake.cs new file mode 100644 index 0000000..238b829 --- /dev/null +++ b/GameCode/SnowFlake.cs @@ -0,0 +1,23 @@ +using UnityEngine; + +public class SnowFlake : Projectile +{ + protected override void Start() + { + base.Start(); + base.transform.Translate(new Vector3(Random.Range(-0.25f, 0.25f), Random.Range(-0.25f, 0.25f), Random.Range(-0.25f, 0.25f))); + } + + protected override void MoveProjectile() + { + base.transform.Translate(Vector3.down * speed * Time.fixedDeltaTime); + } + + protected override void CheckForHits() + { + if (Physics.SphereCast(base.transform.position, 0.125f, Vector3.down, out var hitInfo, speed * Time.fixedDeltaTime, layermask, QueryTriggerInteraction.Collide)) + { + OnHit(hitInfo); + } + } +} diff --git a/GameCode/SocialMediaManager.cs b/GameCode/SocialMediaManager.cs new file mode 100644 index 0000000..25f761f --- /dev/null +++ b/GameCode/SocialMediaManager.cs @@ -0,0 +1,9 @@ +using UnityEngine; + +public class SocialMediaManager : MonoBehaviour +{ + public void OpenLink(string s) + { + Application.OpenURL(s); + } +} diff --git a/GameCode/Sound.cs b/GameCode/Sound.cs new file mode 100644 index 0000000..8a1528f --- /dev/null +++ b/GameCode/Sound.cs @@ -0,0 +1,22 @@ +public enum Sound +{ + None, + Ballista, + Mortar, + TeslaZap, + Explosion, + BiPlaneGun, + ParticleCannon, + Shredder, + BallistaHit, + FrostHit, + ShredderHit, + BulletHit, + ParticleHit, + CoinLong, + CoinShort, + ButtonClick, + CritSmall, + CritBig, + Cards +} diff --git a/GameCode/SpawnManager.cs b/GameCode/SpawnManager.cs new file mode 100644 index 0000000..4e66c04 --- /dev/null +++ b/GameCode/SpawnManager.cs @@ -0,0 +1,495 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +public class SpawnManager : MonoBehaviour +{ + public static SpawnManager instance; + + public Waypoint[] initialSpawns; + + private HashSet<Waypoint> spawnPoints = new HashSet<Waypoint>(); + + public HashSet<IncomeGenerator> incomeGenerators = new HashSet<IncomeGenerator>(); + + public HashSet<University> universities = new HashSet<University>(); + + public HashSet<Mine> mines = new HashSet<Mine>(); + + public HashSet<House> houses = new HashSet<House>(); + + public HashSet<GameObject> destroyOnNewLevel = new HashSet<GameObject>(); + + public HashSet<GameObject> tileSpawnUis = new HashSet<GameObject>(); + + public HashSet<Enemy> currentEnemies = new HashSet<Enemy>(); + + public bool combat; + + private float levelTime; + + [SerializeField] + private Text levelText; + + [SerializeField] + private Text scoreText; + + [SerializeField] + private int cardDrawFrequency = 5; + + [SerializeField] + private float baseRepairChance; + + public int level; + + public int lastLevel = 30; + + [SerializeField] + private GameObject level1Enemy; + + [SerializeField] + private GameObject level3Enemy; + + [SerializeField] + private GameObject level5Enemy; + + [SerializeField] + private GameObject level7Enemy; + + [SerializeField] + private GameObject level9Enemy; + + [SerializeField] + private GameObject level12Enemy; + + [SerializeField] + private GameObject level16Enemy; + + [SerializeField] + private GameObject level18Enemy; + + [SerializeField] + private GameObject level20Enemy; + + [SerializeField] + private GameObject level21Enemy; + + [SerializeField] + private GameObject level23Enemy; + + [SerializeField] + private GameObject level26Enemy; + + [SerializeField] + private GameObject level28Enemy; + + [SerializeField] + private GameObject level30Enemy; + + [SerializeField] + private GameObject level32Enemy; + + [SerializeField] + private GameObject level36Enemy; + + [SerializeField] + private GameObject level38Enemy; + + [SerializeField] + private GameObject level40Enemy; + + [SerializeField] + private GameObject level15Boss; + + [SerializeField] + private GameObject level25Boss; + + [SerializeField] + private GameObject level35Boss; + + [SerializeField] + private GameObject level45Boss; + + [SerializeField] + private LightManager lightManager; + + [SerializeField] + private int secondStageLightLevel; + + [SerializeField] + private int thirdStageLightLevel; + + [SerializeField] + private int fourthStageLightLevel; + + private void Awake() + { + instance = this; + } + + private void Start() + { + Waypoint[] array = initialSpawns; + foreach (Waypoint item in array) + { + spawnPoints.Add(item); + } + levelText.text = "Level: " + level; + scoreText.text = "Score: " + 0; + cardDrawFrequency = 3 - PlayerPrefs.GetInt("CardFreq1", 0) - PlayerPrefs.GetInt("CardFreq2", 0); + baseRepairChance = 34f * (float)(PlayerPrefs.GetInt("TowerRepair1", 0) + PlayerPrefs.GetInt("TowerRepair2", 0) + PlayerPrefs.GetInt("TowerRepair3", 0)); + } + + private void Update() + { + if (combat && currentEnemies.Count == 0 && !GameManager.instance.gameOver && levelTime > 2f) + { + EndWave(); + } + else + { + levelTime += Time.deltaTime; + } + } + + private void EndWave() + { + combat = false; + AchievementManager.instance.BeatLevel(level); + int @int = PlayerPrefs.GetInt("XP", 0); + PlayerPrefs.SetInt("XP", @int + level * GameManager.instance.gameMode); + scoreText.text = "Score: " + GameManager.instance.NaturalSum(level) * GameManager.instance.gameMode; + if (level >= lastLevel) + { + GameManager.instance.Victory(); + return; + } + ShowSpawnUIs(state: true); + if (level % cardDrawFrequency == 0) + { + ShowSpawnUIs(state: false); + CardManager.instance.DrawCards(); + } + if (level == 15 || level == 25 || level == 35) + { + MusicManager.instance.FadeOut(6f); + } + else + { + MusicManager.instance.SetIntensity(action: false); + } + GameObject[] array = new GameObject[destroyOnNewLevel.Count]; + destroyOnNewLevel.CopyTo(array); + GameObject[] array2 = array; + foreach (GameObject gameObject in array2) + { + destroyOnNewLevel.Remove(gameObject); + Object.Destroy(gameObject); + } + if (tileSpawnUis.Count == 0) + { + Debug.Log("I GUESS ILL JUST DIE THEN"); + AchievementManager.instance.UnlockAchievement("NoMorePaths"); + StartNextWave(); + } + } + + public void StartNextWave() + { + levelTime = 0f; + UpdateSpawnPoints(); + float num = 1f - (float)(GameManager.instance.health / GameManager.instance.maxHealth); + if (Random.Range(1f, 100f) <= baseRepairChance * num) + { + GameManager.instance.RepairTower(10); + } + level++; + levelText.text = "Level: " + level; + if (level == secondStageLightLevel) + { + lightManager.ChangeColor(2); + } + else if (level == thirdStageLightLevel) + { + lightManager.ChangeColor(3); + } + else if (level == fourthStageLightLevel) + { + lightManager.ChangeColor(4); + } + if (level == 15 || level == 25 || level == 35 || level == 45) + { + SpawnBoss(level); + } + if (level == 16) + { + MusicManager.instance.PlaySong(1, action: true); + } + else if (level == 26) + { + MusicManager.instance.PlaySong(2, action: true); + } + else if (level == 36) + { + MusicManager.instance.PlaySong(3, action: true); + } + else if (level > 1) + { + MusicManager.instance.SetIntensity(action: true); + } + StartCoroutine(Spawn(level * level)); + combat = true; + ShowSpawnUIs(state: false); + foreach (House house in houses) + { + if (house != null) + { + house.CheckTowers(); + } + } + foreach (IncomeGenerator incomeGenerator in incomeGenerators) + { + if (incomeGenerator != null) + { + incomeGenerator.GenerateIncome(); + } + } + foreach (University university in universities) + { + if (university != null) + { + university.Research(); + } + } + foreach (Mine mine in mines) + { + if (mine != null) + { + mine.Repair(); + } + } + } + + public void ShowSpawnUIs(bool state) + { + foreach (GameObject tileSpawnUi in tileSpawnUis) + { + tileSpawnUi.SetActive(state); + } + } + + private void SpawnBoss(int lvl) + { + Waypoint spawnLocation = null; + float num = -1f; + foreach (Waypoint spawnPoint in spawnPoints) + { + if (spawnPoint.distanceFromEnd > num) + { + num = spawnPoint.distanceFromEnd; + spawnLocation = spawnPoint; + } + } + switch (lvl) + { + case 15: + SpawnEnemy(level15Boss, spawnLocation); + break; + case 25: + SpawnEnemy(level25Boss, spawnLocation); + break; + case 35: + SpawnEnemy(level35Boss, spawnLocation); + break; + case 45: + SpawnEnemy(level45Boss, spawnLocation); + break; + } + } + + private IEnumerator Spawn(int num) + { + int safetyCount = level * level + 100; + int count = num; + float t = 0.5f / (float)spawnPoints.Count; + while (count > 0) + { + foreach (Waypoint spawnPoint in spawnPoints) + { + if (count <= 0) + { + break; + } + count -= SpawnSelection(spawnPoint); + yield return new WaitForSeconds(t); + } + safetyCount--; + if (safetyCount <= 0) + { + Debug.LogError("Spawn loop might be looping infinitely"); + break; + } + } + } + + private int SpawnSelection(Waypoint spawnPoint) + { + if (level >= 40 && Random.Range(1f, 100f) < 10f) + { + SpawnEnemy(level40Enemy, spawnPoint); + return 10; + } + if (level >= 38 && Random.Range(1f, 100f) < 10f) + { + SpawnEnemy(level38Enemy, spawnPoint); + return 10; + } + if (level >= 36 && Random.Range(1f, 100f) < 12f) + { + SpawnEnemy(level36Enemy, spawnPoint); + return 9; + } + if (level >= 32 && Random.Range(1f, 100f) < 10f) + { + SpawnEnemy(level32Enemy, spawnPoint); + return 10; + } + if (level >= 30 && Random.Range(1f, 100f) < 10f) + { + SpawnEnemy(level30Enemy, spawnPoint); + return 10; + } + if (level >= 28 && Random.Range(1f, 100f) < 11f) + { + SpawnEnemy(level28Enemy, spawnPoint); + return 10; + } + if (level >= 26 && Random.Range(1f, 100f) < 12f) + { + SpawnEnemy(level26Enemy, spawnPoint); + return 7; + } + if (level >= 23 && Random.Range(1f, 100f) < 9f) + { + SpawnEnemy(level23Enemy, spawnPoint); + return 12; + } + if (level >= 21 && Random.Range(1f, 100f) < 10f) + { + SpawnEnemy(level21Enemy, spawnPoint); + return 10; + } + if (level >= 20 && Random.Range(1f, 100f) < 10f) + { + SpawnEnemy(level20Enemy, spawnPoint); + return 10; + } + if (level >= 18 && Random.Range(1f, 100f) < 12f) + { + SpawnEnemy(level18Enemy, spawnPoint); + return 9; + } + if (level >= 16 && Random.Range(1f, 100f) < 13f) + { + SpawnEnemy(level16Enemy, spawnPoint); + return 8; + } + if (level >= 12 && Random.Range(1f, 100f) < 9f) + { + SpawnEnemy(level12Enemy, spawnPoint); + return 12; + } + if (level >= 9 && Random.Range(1f, 100f) < 12f) + { + SpawnEnemy(level9Enemy, spawnPoint); + return 9; + } + if (level >= 7 && Random.Range(1f, 100f) < 14f) + { + SpawnEnemy(level7Enemy, spawnPoint); + return 7; + } + if (level >= 5 && Random.Range(1f, 100f) < 20f) + { + SpawnEnemy(level5Enemy, spawnPoint); + return 5; + } + if (level >= 3 && Random.Range(1f, 100f) < 34f) + { + SpawnEnemy(level3Enemy, spawnPoint); + return 3; + } + SpawnEnemy(level1Enemy, spawnPoint); + return 1; + } + + private void SpawnEnemy(GameObject unit, Waypoint spawnLocation) + { + Enemy component = Object.Instantiate(unit, spawnLocation.transform.position, Quaternion.identity).GetComponent<Enemy>(); + component.SetStats(); + component.SetFirstSpawnPoint(spawnLocation); + currentEnemies.Add(component); + } + + private void UpdateSpawnPoints() + { + List<Waypoint> list = new List<Waypoint>(); + List<Waypoint> list2 = new List<Waypoint>(); + foreach (Waypoint spawnPoint in spawnPoints) + { + if (!CheckSpawnPoint(spawnPoint)) + { + continue; + } + list.Add(spawnPoint); + foreach (Waypoint newSpawnPoint in GetNewSpawnPoints(spawnPoint, 1)) + { + list2.Add(newSpawnPoint); + } + } + foreach (Waypoint item in list) + { + spawnPoints.Remove(item); + } + foreach (Waypoint item2 in list2) + { + spawnPoints.Add(item2); + } + } + + private bool CheckSpawnPoint(Waypoint point) + { + if (point.GetPreviousWaypoints().Length != 0) + { + return true; + } + return false; + } + + private List<Waypoint> GetNewSpawnPoints(Waypoint start, int count) + { + if (count > 100) + { + Debug.LogError("Possible infinite loop while finding new spawn points (count over 100)"); + return null; + } + Waypoint[] previousWaypoints = start.GetPreviousWaypoints(); + List<Waypoint> list = new List<Waypoint>(); + if (previousWaypoints.Length == 0) + { + list.Add(start); + return list; + } + count++; + Waypoint[] array = previousWaypoints; + foreach (Waypoint start2 in array) + { + foreach (Waypoint newSpawnPoint in GetNewSpawnPoints(start2, count)) + { + list.Add(newSpawnPoint); + } + } + return list; + } +} diff --git a/GameCode/SpawnableObject.cs b/GameCode/SpawnableObject.cs new file mode 100644 index 0000000..fd7b169 --- /dev/null +++ b/GameCode/SpawnableObject.cs @@ -0,0 +1,54 @@ +using UnityEngine; + +public class SpawnableObject : MonoBehaviour, IBuildable +{ + [SerializeField] + private GameObject artStuff; + + [SerializeField] + private bool randomRotation = true; + + [SerializeField] + private float spawnChance; + + [SerializeField] + private Vector2 spawnLevels; + + [SerializeField] + protected GameObject UIObject; + + protected bool spawned; + + protected virtual void Start() + { + if ((float)SpawnManager.instance.level >= spawnLevels.x && (float)SpawnManager.instance.level <= spawnLevels.y && Random.Range(1f, 100f) < 100f * spawnChance) + { + if (randomRotation) + { + artStuff.transform.eulerAngles = new Vector3(0f, Random.Range(0, 4) * 90, 0f); + } + artStuff.SetActive(value: true); + spawned = true; + } + else + { + Object.Destroy(base.gameObject); + } + } + + public void SetStats() + { + } + + public virtual void SpawnUI() + { + if (UIObject != null) + { + Object.Instantiate(UIObject, base.transform.position, Quaternion.identity); + } + } + + public void Demolish() + { + } +} diff --git a/GameCode/SteamManager.cs b/GameCode/SteamManager.cs new file mode 100644 index 0000000..642003a --- /dev/null +++ b/GameCode/SteamManager.cs @@ -0,0 +1,123 @@ +using System; +using System.Text; +using AOT; +using Steamworks; +using UnityEngine; + +[DisallowMultipleComponent] +public class SteamManager : MonoBehaviour +{ + protected static bool s_EverInitialized; + + protected static SteamManager s_instance; + + protected bool m_bInitialized; + + protected SteamAPIWarningMessageHook_t m_SteamAPIWarningMessageHook; + + protected static SteamManager Instance + { + get + { + if (s_instance == null) + { + return new GameObject("SteamManager").AddComponent<SteamManager>(); + } + return s_instance; + } + } + + public static bool Initialized => Instance.m_bInitialized; + + [MonoPInvokeCallback(typeof(SteamAPIWarningMessageHook_t))] + protected static void SteamAPIDebugTextHook(int nSeverity, StringBuilder pchDebugText) + { + Debug.LogWarning(pchDebugText); + } + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + private static void InitOnPlayMode() + { + s_EverInitialized = false; + s_instance = null; + } + + protected virtual void Awake() + { + if (s_instance != null) + { + UnityEngine.Object.Destroy(base.gameObject); + return; + } + s_instance = this; + if (s_EverInitialized) + { + throw new Exception("Tried to Initialize the SteamAPI twice in one session!"); + } + UnityEngine.Object.DontDestroyOnLoad(base.gameObject); + if (!Packsize.Test()) + { + Debug.LogError("[Steamworks.NET] Packsize Test returned false, the wrong version of Steamworks.NET is being run in this platform.", this); + } + if (!DllCheck.Test()) + { + Debug.LogError("[Steamworks.NET] DllCheck Test returned false, One or more of the Steamworks binaries seems to be the wrong version.", this); + } + try + { + if (SteamAPI.RestartAppIfNecessary((AppId_t)1843760u)) + { + Application.Quit(); + return; + } + } + catch (DllNotFoundException ex) + { + Debug.LogError("[Steamworks.NET] Could not load [lib]steam_api.dll/so/dylib. It's likely not in the correct location. Refer to the README for more details.\n" + ex, this); + Application.Quit(); + return; + } + m_bInitialized = SteamAPI.Init(); + if (!m_bInitialized) + { + Debug.LogError("[Steamworks.NET] SteamAPI_Init() failed. Refer to Valve's documentation or the comment above this line for more information.", this); + } + else + { + s_EverInitialized = true; + } + } + + protected virtual void OnEnable() + { + if (s_instance == null) + { + s_instance = this; + } + if (m_bInitialized && m_SteamAPIWarningMessageHook == null) + { + m_SteamAPIWarningMessageHook = SteamAPIDebugTextHook; + SteamClient.SetWarningMessageHook(m_SteamAPIWarningMessageHook); + } + } + + protected virtual void OnDestroy() + { + if (!(s_instance != this)) + { + s_instance = null; + if (m_bInitialized) + { + SteamAPI.Shutdown(); + } + } + } + + protected virtual void Update() + { + if (m_bInitialized) + { + SteamAPI.RunCallbacks(); + } + } +} diff --git a/GameCode/TerrainTile.cs b/GameCode/TerrainTile.cs new file mode 100644 index 0000000..932ff37 --- /dev/null +++ b/GameCode/TerrainTile.cs @@ -0,0 +1,87 @@ +using UnityEngine; + +public class TerrainTile : MonoBehaviour +{ + public Waypoint last; + + [SerializeField] + private Waypoint left; + + [SerializeField] + private Waypoint top; + + [SerializeField] + private Waypoint right; + + public Waypoint south; + + public Waypoint west; + + public Waypoint north; + + public Waypoint east; + + public void SetCardinalDirections() + { + if (base.transform.eulerAngles.y == 0f) + { + south = last; + west = left; + north = top; + east = right; + } + else if (base.transform.eulerAngles.y == 90f) + { + south = right; + west = last; + north = left; + east = top; + } + else if (base.transform.eulerAngles.y == 180f) + { + south = top; + west = right; + north = last; + east = left; + } + else if (base.transform.eulerAngles.y == 270f) + { + south = left; + west = top; + north = right; + east = last; + } + else + { + Debug.LogError(base.name + " not at a proper rotation. Current rotation: " + base.transform.eulerAngles.y); + } + } + + public void ConnectToTile(TerrainTile next) + { + if (base.transform.eulerAngles.y == 0f) + { + last.SetNextWaypoint(next.north); + next.north.AddPreviousWaypoint(last); + } + else if (base.transform.eulerAngles.y == 90f) + { + last.SetNextWaypoint(next.east); + next.east.AddPreviousWaypoint(last); + } + else if (base.transform.eulerAngles.y == 180f) + { + last.SetNextWaypoint(next.south); + next.south.AddPreviousWaypoint(last); + } + else if (base.transform.eulerAngles.y == 270f) + { + last.SetNextWaypoint(next.west); + next.west.AddPreviousWaypoint(last); + } + else + { + Debug.LogError(base.name + " not at a proper rotation"); + } + } +} diff --git a/GameCode/TeslaCoil.cs b/GameCode/TeslaCoil.cs new file mode 100644 index 0000000..97954e7 --- /dev/null +++ b/GameCode/TeslaCoil.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections; +using UnityEngine; + +public class TeslaCoil : Tower +{ + [SerializeField] + private GameObject lightningTrail; + + protected override void AimTurret() + { + } + + protected override void Fire() + { + if (consumesMana) + { + int manaCost = (int)((float)base.damage * manaConsumptionRate); + if (!ResourceManager.instance.CheckMana(manaCost)) + { + return; + } + ResourceManager.instance.SpendMana(manaCost); + } + Vector3 position = base.transform.position; + position.y = 0f; + Collider[] array = Physics.OverlapSphere(position, base.range, enemyLayerMask, QueryTriggerInteraction.Collide); + for (int i = 0; i < array.Length; i++) + { + array[i].GetComponent<IDamageable>()?.TakeDamage(towerType, base.damage, base.healthDamage, base.armorDamage, base.shieldDamage, base.slowPercent, base.bleedPercent, base.burnPercent, base.poisonPercent, base.critChance, base.stunChance); + } + SFXManager.instance.PlaySound(Sound.TeslaZap, base.transform.position); + StartCoroutine(DrawLightning()); + } + + private IEnumerator DrawLightning() + { + for (float i = 0f; i <= (float)Math.PI * 2f; i += 0.5f) + { + Vector3 vector = new Vector3(UnityEngine.Random.Range(-0.5f, 0.5f), UnityEngine.Random.Range(-0.5f, 0.5f), UnityEngine.Random.Range(-0.5f, 0.5f)); + lightningTrail.transform.position = vector + new Vector3(base.transform.position.x + Mathf.Sin(i) * base.range, 0.75f, base.transform.position.z + Mathf.Cos(i) * base.range); + yield return new WaitForEndOfFrame(); + } + } +} diff --git a/GameCode/TileManager.cs b/GameCode/TileManager.cs new file mode 100644 index 0000000..592d861 --- /dev/null +++ b/GameCode/TileManager.cs @@ -0,0 +1,236 @@ +using System.Collections.Generic; +using UnityEngine; + +public class TileManager : MonoBehaviour +{ + public static TileManager instance; + + [SerializeField] + private GameObject tilePlacementFXObject; + + [SerializeField] + private GameObject[] deadEndTiles; + + [SerializeField] + private GameObject[] Ltiles; + + [SerializeField] + private GameObject[] Ttiles; + + [SerializeField] + private GameObject[] Rtiles; + + [SerializeField] + private GameObject[] LTtiles; + + [SerializeField] + private GameObject[] LRtiles; + + [SerializeField] + private GameObject[] TRtiles; + + [SerializeField] + private GameObject[] LTRtiles; + + public TerrainTile startTile; + + [SerializeField] + private GameObject tileSpawnLocation; + + private int[,] intArray = new int[99, 99]; + + private TerrainTile[,] tileArray = new TerrainTile[99, 99]; + + private void Awake() + { + instance = this; + } + + private void Start() + { + intArray[50, 50] = 1; + tileArray[50, 50] = startTile; + for (int i = 0; i < 99; i++) + { + intArray[0, i] = 1; + intArray[i, 0] = 1; + intArray[98, i] = 1; + intArray[i, 98] = 1; + } + UpdateIntArrayFromTile(startTile, 50, 50); + } + + private void UpdateIntArrayFromTile(TerrainTile tile, int posX, int posY) + { + if (tile.south != null && tile.south != tile.last && intArray[posX, posY - 1] == 0) + { + intArray[posX, posY - 1] = 2; + TileSpawnLocation component = Object.Instantiate(tileSpawnLocation, new Vector3(posX - 50, 0f, posY - 1 - 50) * 7f, Quaternion.identity).GetComponent<TileSpawnLocation>(); + component.eulerAngle = 180; + component.posX = posX; + component.posY = posY - 1; + } + if (tile.west != null && tile.west != tile.last && intArray[posX - 1, posY] == 0) + { + intArray[posX - 1, posY] = 2; + TileSpawnLocation component2 = Object.Instantiate(tileSpawnLocation, new Vector3(posX - 1 - 50, 0f, posY - 50) * 7f, Quaternion.identity).GetComponent<TileSpawnLocation>(); + component2.eulerAngle = 270; + component2.posX = posX - 1; + component2.posY = posY; + } + if (tile.north != null && tile.north != tile.last && intArray[posX, posY + 1] == 0) + { + intArray[posX, posY + 1] = 2; + TileSpawnLocation component3 = Object.Instantiate(tileSpawnLocation, new Vector3(posX - 50, 0f, posY + 1 - 50) * 7f, Quaternion.identity).GetComponent<TileSpawnLocation>(); + component3.eulerAngle = 0; + component3.posX = posX; + component3.posY = posY + 1; + } + if (tile.east != null && tile.east != tile.last && intArray[posX + 1, posY] == 0) + { + intArray[posX + 1, posY] = 2; + TileSpawnLocation component4 = Object.Instantiate(tileSpawnLocation, new Vector3(posX + 1 - 50, 0f, posY - 50) * 7f, Quaternion.identity).GetComponent<TileSpawnLocation>(); + component4.eulerAngle = 90; + component4.posX = posX + 1; + component4.posY = posY; + } + } + + public void SpawnNewTile(int posX, int posY, int eulerAngle) + { + bool flag = false; + bool flag2 = false; + bool flag3 = false; + bool flag4 = false; + if (intArray[posX, posY - 1] == 0) + { + flag = true; + } + if (intArray[posX - 1, posY] == 0) + { + flag2 = true; + } + if (intArray[posX, posY + 1] == 0) + { + flag3 = true; + } + if (intArray[posX + 1, posY] == 0) + { + flag4 = true; + } + bool flag5 = false; + bool flag6 = false; + bool flag7 = false; + switch (eulerAngle) + { + case 0: + flag5 = flag2; + flag6 = flag3; + flag7 = flag4; + break; + case 90: + flag5 = flag3; + flag6 = flag4; + flag7 = flag; + break; + case 180: + flag5 = flag4; + flag6 = flag; + flag7 = flag2; + break; + case 270: + flag5 = flag; + flag6 = flag2; + flag7 = flag3; + break; + default: + Debug.LogError("Trying to spawn a tile at an invalid eulerAngle" + eulerAngle); + break; + } + List<GameObject> list = new List<GameObject>(); + int num = SpawnManager.instance.lastLevel - SpawnManager.instance.level; + int count = SpawnManager.instance.tileSpawnUis.Count; + bool flag8 = false; + bool flag9 = false; + if (count + 3 >= num || SpawnManager.instance.level < 3) + { + flag8 = true; + } + if (count == num) + { + flag9 = true; + } + if (!flag9) + { + if (flag5) + { + list.AddRange(Ltiles); + } + if (flag6) + { + list.AddRange(Ttiles); + } + if (flag7) + { + list.AddRange(Rtiles); + } + if (flag5 && flag6 && !flag8) + { + list.AddRange(LTtiles); + } + if (flag5 && flag7 && !flag8) + { + list.AddRange(LRtiles); + } + if (flag6 && flag7 && !flag8) + { + list.AddRange(TRtiles); + } + if (flag5 && flag6 && flag7 && !flag8) + { + list.AddRange(LTRtiles); + } + } + if (list.Count == 0) + { + list.AddRange(deadEndTiles); + } + GameObject original = list[Random.Range(0, list.Count)]; + Vector3 vector = new Vector3(posX - 50, 0f, posY - 50) * 7f; + GameObject obj = Object.Instantiate(original, vector, Quaternion.identity); + obj.transform.eulerAngles = new Vector3(0f, eulerAngle, 0f); + intArray[posX, posY] = 1; + TerrainTile component = obj.GetComponent<TerrainTile>(); + tileArray[posX, posY] = component; + component.SetCardinalDirections(); + UpdateIntArrayFromTile(component, posX, posY); + TerrainTile terrainTile = null; + switch (eulerAngle) + { + case 0: + terrainTile = tileArray[posX, posY - 1]; + break; + case 90: + terrainTile = tileArray[posX - 1, posY]; + break; + case 180: + terrainTile = tileArray[posX, posY + 1]; + break; + case 270: + terrainTile = tileArray[posX + 1, posY]; + break; + default: + Debug.LogError("Trying to spawn a tile at an invalid eulerAngle" + eulerAngle); + break; + } + if (terrainTile == null) + { + Debug.LogError("Unable to find previous tile"); + } + component.ConnectToTile(terrainTile); + if (tilePlacementFXObject != null) + { + Object.Instantiate(tilePlacementFXObject, vector + Vector3.up, Quaternion.identity).transform.localScale = Vector3.one * 7f; + } + } +} diff --git a/GameCode/TileSpawnLocation.cs b/GameCode/TileSpawnLocation.cs new file mode 100644 index 0000000..e1575b1 --- /dev/null +++ b/GameCode/TileSpawnLocation.cs @@ -0,0 +1,27 @@ +using UnityEngine; + +public class TileSpawnLocation : MonoBehaviour +{ + public int eulerAngle; + + public int posX; + + public int posY; + + private void Start() + { + SpawnManager.instance.tileSpawnUis.Add(base.gameObject); + if (SpawnManager.instance.combat) + { + base.gameObject.SetActive(value: false); + } + } + + public void SpawnTile() + { + TileManager.instance.SpawnNewTile(posX, posY, eulerAngle); + SpawnManager.instance.tileSpawnUis.Remove(base.gameObject); + SpawnManager.instance.StartNextWave(); + Object.Destroy(base.gameObject); + } +} diff --git a/GameCode/Tower.cs b/GameCode/Tower.cs new file mode 100644 index 0000000..4098bd6 --- /dev/null +++ b/GameCode/Tower.cs @@ -0,0 +1,509 @@ +using UnityEngine; + +public class Tower : MonoBehaviour, IBuildable +{ + public enum Priority + { + Progress, + NearDeath, + MostHealth, + MostArmor, + MostShield, + LeastHealth, + LeastArmor, + LeastShield, + Fastest, + Slowest, + Marked + } + + public TowerType towerType; + + public bool squareUI; + + [SerializeField] + protected GameObject towerUI; + + public Priority[] priorities = new Priority[3]; + + [SerializeField] + protected GameObject turret; + + [SerializeField] + protected bool towerVerticalyAims = true; + + [SerializeField] + protected Transform muzzle; + + [SerializeField] + protected GameObject projectile; + + [SerializeField] + protected float projectileSpeed = 10f; + + [SerializeField] + protected GameObject extraProjectileFX; + + [SerializeField] + protected int baseDamage; + + [SerializeField] + protected int baseHealthDamage; + + [SerializeField] + protected int baseArmorDamage; + + [SerializeField] + protected int baseShieldDamage; + + public float rpm; + + protected float rps; + + [SerializeField] + protected float baseRange; + + [SerializeField] + protected float baseSlowPercentage; + + [SerializeField] + protected float baseBleedPercentage; + + [SerializeField] + protected float baseBurnPercentage; + + [SerializeField] + protected float basePoisonPercentage; + + [SerializeField] + protected LayerMask enemyLayerMask; + + [SerializeField] + protected LayerMask buildingLayerMask; + + public bool consumesMana; + + public float manaConsumptionRate; + + public float finalManaConsumption; + + public int upgradeCostMultiplier = 1; + + private int damageUpgrade; + + private int healthDamageUpgrade; + + private int armorDamageUpgrade; + + private int shieldDamageUpgrade; + + private int heightBonus; + + protected float timeSinceLastShot; + + private float lastTargetUpdate = 1f; + + protected GameObject currentTarget; + + [SerializeField] + protected float baseBlastRadius; + + public int level { get; private set; } + + public float healthXP { get; private set; } + + public float armorXP { get; private set; } + + public float shieldXP { get; private set; } + + public int damage { get; private set; } + + public int healthDamage { get; private set; } + + public int armorDamage { get; private set; } + + public int shieldDamage { get; private set; } + + public float range { get; private set; } + + public float slowPercent { get; private set; } + + public float bleedPercent { get; private set; } + + public float burnPercent { get; private set; } + + public float poisonPercent { get; private set; } + + public float critChance { get; private set; } + + public float stunChance { get; private set; } + + public float blastRadius { get; private set; } + + protected virtual void Start() + { + level = 1; + SetStats(); + TowerManager.instance.AddNewTower(this, towerType); + DetectHouses(); + priorities[0] = (priorities[1] = (priorities[2] = Priority.Progress)); + } + + public virtual void SetStats() + { + heightBonus = (int)Mathf.Round(base.transform.position.y * 3f - 1f); + damage = Mathf.Max(baseDamage + heightBonus + damageUpgrade + TowerManager.instance.GetBonusBaseDamage(towerType), 0); + healthDamage = baseHealthDamage + healthDamageUpgrade + TowerManager.instance.GetBonusHealthDamage(towerType); + armorDamage = baseArmorDamage + armorDamageUpgrade + TowerManager.instance.GetBonusArmorDamage(towerType); + shieldDamage = baseShieldDamage + shieldDamageUpgrade + TowerManager.instance.GetBonusShieldDamage(towerType); + rps = 60f / rpm; + range = baseRange + (float)heightBonus / 2f + TowerManager.instance.GetBonusRange(towerType); + slowPercent = baseSlowPercentage + TowerManager.instance.GetBonusSlow(towerType); + bleedPercent = baseBleedPercentage + TowerManager.instance.GetBonusBleed(towerType); + burnPercent = baseBurnPercentage + TowerManager.instance.GetBonusBurn(towerType); + poisonPercent = basePoisonPercentage + TowerManager.instance.GetBonusPoison(towerType); + blastRadius = baseBlastRadius + TowerManager.instance.GetBonusBlast(towerType); + finalManaConsumption = manaConsumptionRate + TowerManager.instance.GetManaConsumptionBonus(towerType); + if (TowerManager.instance.GetManaConsumptionBonus(towerType) > 0f) + { + consumesMana = true; + } + critChance = TowerManager.instance.GetCritChance(towerType) + TowerManager.instance.GetCritChanceLevelMultiplier(towerType) * (float)level / 100f; + stunChance = TowerManager.instance.GetStunChance(towerType); + } + + private void FixedUpdate() + { + if (lastTargetUpdate <= 0f) + { + DetectEnemies(); + } + else + { + lastTargetUpdate -= Time.fixedDeltaTime; + } + } + + protected virtual void Update() + { + if (currentTarget != null) + { + if (turret != null) + { + AimTurret(); + } + GainXP(); + } + timeSinceLastShot += Time.deltaTime; + if (currentTarget != null && timeSinceLastShot > rps) + { + Fire(); + timeSinceLastShot = 0f; + } + } + + private void DetectHouses() + { + if (Physics.Raycast(base.transform.position + new Vector3(1f, 1f, 0f), -base.transform.up, out var hitInfo, 1f, buildingLayerMask, QueryTriggerInteraction.Ignore)) + { + CheckForHouse(hitInfo); + } + if (Physics.Raycast(base.transform.position + new Vector3(-1f, 1f, 0f), -base.transform.up, out hitInfo, 1f, buildingLayerMask, QueryTriggerInteraction.Ignore)) + { + CheckForHouse(hitInfo); + } + if (Physics.Raycast(base.transform.position + new Vector3(0f, 1f, 1f), -base.transform.up, out hitInfo, 1f, buildingLayerMask, QueryTriggerInteraction.Ignore)) + { + CheckForHouse(hitInfo); + } + if (Physics.Raycast(base.transform.position + new Vector3(0f, 1f, -1f), -base.transform.up, out hitInfo, 1f, buildingLayerMask, QueryTriggerInteraction.Ignore)) + { + CheckForHouse(hitInfo); + } + } + + private void CheckForHouse(RaycastHit hit) + { + if (hit.collider.GetComponent<House>() != null && (double)Mathf.Abs(hit.collider.transform.position.y - base.transform.position.y) <= 0.001) + { + hit.collider.GetComponent<House>().AddDefender(this); + } + } + + public void TogglePriority(int index, int direction) + { + priorities[index] = (Priority)(((int)(priorities[index] + direction) % 11 + 11) % 11); + } + + protected virtual void Fire() + { + if (consumesMana) + { + int manaCost = (int)((float)damage * finalManaConsumption); + if (!ResourceManager.instance.CheckMana(manaCost)) + { + return; + } + ResourceManager.instance.SpendMana(manaCost); + } + GameObject gameObject = Object.Instantiate(projectile, muzzle.position, muzzle.rotation); + gameObject.GetComponent<Projectile>().SetStats(towerType, currentTarget, projectileSpeed, damage, healthDamage, armorDamage, shieldDamage, slowPercent, bleedPercent, burnPercent, poisonPercent, critChance, stunChance); + if (extraProjectileFX != null) + { + GameObject gameObject2 = Object.Instantiate(extraProjectileFX, gameObject.transform.position, gameObject.transform.rotation); + gameObject2.transform.SetParent(gameObject.transform); + gameObject2.GetComponent<ProjectileFX>().SetFX(bleedPercent, burnPercent, poisonPercent, slowPercent, consumesMana); + Projectile component = gameObject.GetComponent<Projectile>(); + if (component.detachOnDestruction == null) + { + component.detachOnDestruction = gameObject2; + component.extraFX = gameObject2.GetComponent<ProjectileFX>(); + } + } + } + + protected virtual void AimTurret() + { + Vector3 forward = currentTarget.transform.position - turret.transform.position; + if (!towerVerticalyAims) + { + forward.y = 0f; + } + Quaternion rotation = Quaternion.LookRotation(forward, Vector3.up); + turret.transform.rotation = rotation; + } + + protected void GainXP() + { + Enemy component = currentTarget.GetComponent<Enemy>(); + if (component != null) + { + if (component.shield > 0) + { + shieldXP += Time.deltaTime / (2f * range) + Time.deltaTime / 2f; + } + else if (component.armor > 0) + { + armorXP += Time.deltaTime / (2f * range) + Time.deltaTime / 2f; + } + else + { + healthXP += Time.deltaTime / (2f * range) + Time.deltaTime / 2f; + } + CheckXPAndLevelUp(); + } + } + + private void CheckXPAndLevelUp() + { + if (healthXP >= (float)(10 * level)) + { + healthXP -= 10 * level; + level++; + damageUpgrade++; + healthDamageUpgrade++; + SetStats(); + LevelUpText(); + } + if (armorXP >= (float)(10 * level)) + { + armorXP -= 10 * level; + level++; + damageUpgrade++; + armorDamageUpgrade++; + SetStats(); + LevelUpText(); + } + if (shieldXP >= (float)(10 * level)) + { + shieldXP -= 10 * level; + level++; + damageUpgrade++; + shieldDamageUpgrade++; + SetStats(); + LevelUpText(); + } + } + + private void LevelUpText() + { + Object.Instantiate(BuildingManager.instance.levelUpFX, base.transform.position, Quaternion.identity); + DamageNumber component = ObjectPool.instance.SpawnObject(ObjectPool.ObjectType.DamageNumber, base.transform.position, Quaternion.identity).GetComponent<DamageNumber>(); + component.SetText("LEVEL UP!", "Grey", 1f); + component.SetHoldTime(1f); + AchievementManager.instance.TowerLevel(level); + } + + public void BuyHealthLevel() + { + int num = (10 * level - (int)healthXP) * upgradeCostMultiplier; + if (ResourceManager.instance.CheckMoney(num)) + { + ResourceManager.instance.Spend(num); + DamageTracker.instance.AddCost(towerType, num); + healthXP -= 10 * level - num / upgradeCostMultiplier; + level++; + damageUpgrade++; + healthDamageUpgrade++; + SetStats(); + LevelUpText(); + } + } + + public void BuyArmorLevel() + { + int num = (10 * level - (int)armorXP) * upgradeCostMultiplier; + if (ResourceManager.instance.CheckMoney(num)) + { + ResourceManager.instance.Spend(num); + DamageTracker.instance.AddCost(towerType, num); + armorXP -= 10 * level - num / upgradeCostMultiplier; + level++; + damageUpgrade++; + armorDamageUpgrade++; + SetStats(); + LevelUpText(); + } + } + + public void BuyShieldLevel() + { + int num = (10 * level - (int)shieldXP) * upgradeCostMultiplier; + if (ResourceManager.instance.CheckMoney(num)) + { + ResourceManager.instance.Spend(num); + DamageTracker.instance.AddCost(towerType, num); + shieldXP -= 10 * level - num / upgradeCostMultiplier; + level++; + damageUpgrade++; + shieldDamageUpgrade++; + SetStats(); + LevelUpText(); + } + } + + private void DetectEnemies() + { + Collider[] array = Physics.OverlapSphere(base.transform.position, range, enemyLayerMask, QueryTriggerInteraction.Collide); + if (array.Length != 0) + { + currentTarget = SelectEnemy(array); + } + else + { + currentTarget = null; + } + lastTargetUpdate = Random.Range(0.25f, 1f); + } + + protected bool CheckPriority(Priority check) + { + for (int i = 0; i < priorities.Length; i++) + { + if (check == priorities[i]) + { + return true; + } + } + return false; + } + + protected int PriorityScale(Priority check) + { + for (int i = 0; i < priorities.Length; i++) + { + if (check == priorities[i]) + { + return Mathf.Clamp(3 - i, 1, 3); + } + } + return 1; + } + + protected virtual GameObject SelectEnemy(Collider[] possibleTargets) + { + GameObject result = null; + float num = -1f; + for (int i = 0; i < possibleTargets.Length; i++) + { + float num2 = 1f; + Enemy component = possibleTargets[i].GetComponent<Enemy>(); + if (CheckPriority(Priority.Progress)) + { + float f = Mathf.Max(0.001f, possibleTargets[i].GetComponent<Pathfinder>().distanceFromEnd); + num2 /= Mathf.Pow(f, PriorityScale(Priority.Progress)); + } + if (CheckPriority(Priority.NearDeath)) + { + float f2 = Mathf.Max(0.001f, component.CurrentHealth()); + num2 /= Mathf.Pow(f2, PriorityScale(Priority.NearDeath)); + } + if (CheckPriority(Priority.MostHealth)) + { + float f3 = (float)Mathf.Max(1, component.health) / 1000f; + num2 *= Mathf.Pow(f3, PriorityScale(Priority.MostHealth)); + } + if (CheckPriority(Priority.MostArmor)) + { + float f4 = (float)Mathf.Max(1, component.armor) / 1000f; + num2 *= Mathf.Pow(f4, PriorityScale(Priority.MostArmor)); + } + if (CheckPriority(Priority.MostShield)) + { + float f5 = (float)Mathf.Max(1, component.shield) / 1000f; + num2 *= Mathf.Pow(f5, PriorityScale(Priority.MostShield)); + } + if (CheckPriority(Priority.LeastHealth)) + { + float f6 = Mathf.Max(1, component.health); + num2 /= Mathf.Pow(f6, PriorityScale(Priority.LeastHealth)); + } + if (CheckPriority(Priority.LeastArmor)) + { + float f7 = Mathf.Max(1, component.armor); + num2 /= Mathf.Pow(f7, PriorityScale(Priority.LeastArmor)); + } + if (CheckPriority(Priority.LeastShield)) + { + float f8 = Mathf.Max(1, component.shield); + num2 /= Mathf.Pow(f8, PriorityScale(Priority.LeastShield)); + } + if (CheckPriority(Priority.Fastest)) + { + float f9 = Mathf.Max(0.001f, possibleTargets[i].GetComponent<Pathfinder>().speed); + num2 *= Mathf.Pow(f9, PriorityScale(Priority.Fastest)); + } + if (CheckPriority(Priority.Slowest)) + { + float f10 = Mathf.Max(0.001f, possibleTargets[i].GetComponent<Pathfinder>().speed); + num2 /= Mathf.Pow(f10, PriorityScale(Priority.Slowest)); + } + if (CheckPriority(Priority.Marked)) + { + float f11 = 1f; + if (component.mark != null) + { + f11 = (float)(component.mark.damage * (component.mark.healthDamage + component.mark.armorDamage + component.mark.shieldDamage)) * (1f + component.mark.critChance); + } + num2 *= Mathf.Pow(f11, PriorityScale(Priority.Marked)); + } + if (num2 > num) + { + result = component.gameObject; + num = num2; + } + } + return result; + } + + public void SpawnUI() + { + Object.Instantiate(towerUI, base.transform.position, Quaternion.identity).GetComponent<TowerUI>().SetStats(this); + } + + public virtual void Demolish() + { + TowerManager.instance.RemoveTower(this, towerType); + Object.Destroy(base.gameObject); + } +} diff --git a/GameCode/TowerFlyweight.cs b/GameCode/TowerFlyweight.cs new file mode 100644 index 0000000..b63f8b4 --- /dev/null +++ b/GameCode/TowerFlyweight.cs @@ -0,0 +1,279 @@ +using System.Collections.Generic; +using UnityEngine; + +public class TowerFlyweight : MonoBehaviour +{ + private HashSet<Tower> towers = new HashSet<Tower>(); + + [SerializeField] + private BuildButtonUI myBuildButton; + + [SerializeField] + private int basePrice; + + [SerializeField] + public int priceIncrease; + + [SerializeField] + public int currentPrice; + + [SerializeField] + public int sellPrice; + + [SerializeField] + public float bonusRange; + + [SerializeField] + public int bonusBaseDamage; + + [SerializeField] + public int bonusHealthDamage; + + [SerializeField] + public int bonusArmorDamage; + + [SerializeField] + public int bonusShieldDamage; + + [SerializeField] + public float bonusSlow; + + [SerializeField] + public float bonusBleed; + + [SerializeField] + public float bonusBurn; + + [SerializeField] + public float bonusPoison; + + [SerializeField] + public float bonusBlast; + + [SerializeField] + public float critChance; + + [SerializeField] + public float critChanceLevelMultiplier; + + [SerializeField] + public float stunChance; + + [SerializeField] + public float manaConsumptionAddition; + + [SerializeField] + private TowerType towerTypeForDamageTracker; + + public void AddNewTower(Tower newTower) + { + towers.Add(newTower); + currentPrice = basePrice + towers.Count * priceIncrease; + sellPrice = basePrice + (towers.Count - 1) * priceIncrease; + myBuildButton.UpdatePriceText(); + } + + public void RemoveTower(Tower newTower) + { + towers.Remove(newTower); + currentPrice = basePrice + towers.Count * priceIncrease; + sellPrice = basePrice + (towers.Count - 1) * priceIncrease; + myBuildButton.UpdatePriceText(); + ResourceManager.instance.AddMoney(basePrice + towers.Count * priceIncrease); + DamageTracker.instance.AddCost(towerTypeForDamageTracker, -(basePrice + towers.Count * priceIncrease)); + } + + public void UpdateTowerStats() + { + foreach (Tower tower in towers) + { + tower.SetStats(); + } + if (myBuildButton != null) + { + myBuildButton.UpdateModifiersText(); + } + } + + public void AddManaAddition(float bonus) + { + manaConsumptionAddition += bonus; + foreach (Tower tower in towers) + { + tower.SetStats(); + } + if (myBuildButton != null) + { + myBuildButton.UpdateModifiersText(); + } + } + + public void AddStunChance(float bonus) + { + stunChance += bonus; + foreach (Tower tower in towers) + { + tower.SetStats(); + } + if (myBuildButton != null) + { + myBuildButton.UpdateModifiersText(); + } + } + + public void AddCritChance(float bonus) + { + critChance += bonus; + foreach (Tower tower in towers) + { + tower.SetStats(); + } + if (myBuildButton != null) + { + myBuildButton.UpdateModifiersText(); + } + } + + public void AddCritChanceLevelMultiplier(float bonus) + { + critChanceLevelMultiplier += bonus; + foreach (Tower tower in towers) + { + tower.SetStats(); + } + if (myBuildButton != null) + { + myBuildButton.UpdateModifiersText(); + } + } + + public void AddBonusRange(float bonus) + { + bonusRange += bonus; + foreach (Tower tower in towers) + { + tower.SetStats(); + } + if (myBuildButton != null) + { + myBuildButton.UpdateModifiersText(); + } + } + + public void AddBonusBaseDamage(int bonus) + { + bonusBaseDamage += bonus; + foreach (Tower tower in towers) + { + tower.SetStats(); + } + if (myBuildButton != null) + { + myBuildButton.UpdateModifiersText(); + } + } + + public void AddBonusHealthDamage(int bonus) + { + bonusHealthDamage += bonus; + foreach (Tower tower in towers) + { + tower.SetStats(); + } + if (myBuildButton != null) + { + myBuildButton.UpdateModifiersText(); + } + } + + public void AddBonusArmorDamage(int bonus) + { + bonusArmorDamage += bonus; + foreach (Tower tower in towers) + { + tower.SetStats(); + } + if (myBuildButton != null) + { + myBuildButton.UpdateModifiersText(); + } + } + + public void AddBonusShieldDamage(int bonus) + { + bonusShieldDamage += bonus; + foreach (Tower tower in towers) + { + tower.SetStats(); + } + if (myBuildButton != null) + { + myBuildButton.UpdateModifiersText(); + } + } + + public void AddBonusSlow(float bonus) + { + bonusSlow += bonus; + foreach (Tower tower in towers) + { + tower.SetStats(); + } + if (myBuildButton != null) + { + myBuildButton.UpdateModifiersText(); + } + } + + public void AddBonusBleed(float bonus) + { + bonusBleed += bonus; + foreach (Tower tower in towers) + { + tower.SetStats(); + } + if (myBuildButton != null) + { + myBuildButton.UpdateModifiersText(); + } + } + + public void AddBonusBurn(float bonus) + { + bonusBurn += bonus; + foreach (Tower tower in towers) + { + tower.SetStats(); + } + if (myBuildButton != null) + { + myBuildButton.UpdateModifiersText(); + } + } + + public void AddBonusPoison(float bonus) + { + bonusPoison += bonus; + foreach (Tower tower in towers) + { + tower.SetStats(); + } + if (myBuildButton != null) + { + myBuildButton.UpdateModifiersText(); + } + } + + public void AddBonusBlast(float bonus) + { + bonusBlast += bonus; + foreach (Tower tower in towers) + { + tower.SetStats(); + } + if (myBuildButton != null) + { + myBuildButton.UpdateModifiersText(); + } + } +} diff --git a/GameCode/TowerManager.cs b/GameCode/TowerManager.cs new file mode 100644 index 0000000..abdca52 --- /dev/null +++ b/GameCode/TowerManager.cs @@ -0,0 +1,1386 @@ +using System.Collections.Generic; +using UnityEngine; + +public class TowerManager : MonoBehaviour +{ + public static TowerManager instance; + + [SerializeField] + private TowerFlyweight global; + + [SerializeField] + private TowerFlyweight crossbow; + + [SerializeField] + private TowerFlyweight morter; + + [SerializeField] + private TowerFlyweight teslaCoil; + + [SerializeField] + private TowerFlyweight flameThrower; + + [SerializeField] + private TowerFlyweight poisonSprayer; + + [SerializeField] + private TowerFlyweight frostKeep; + + [SerializeField] + private TowerFlyweight radar; + + [SerializeField] + private TowerFlyweight obelisk; + + [SerializeField] + private TowerFlyweight particleCannon; + + [SerializeField] + private TowerFlyweight shredder; + + [SerializeField] + private TowerFlyweight encampment; + + [SerializeField] + private TowerFlyweight lookout; + + [SerializeField] + private TowerFlyweight siphon; + + public HashSet<TowerType> towersUsed = new HashSet<TowerType>(); + + private bool usedAllTowers; + + public float obeliskTimeOnTargetMultiplier; + + private void Awake() + { + instance = this; + } + + public void AddNewTower(Tower t, TowerType type) + { + if (type != TowerType.Siphon) + { + towersUsed.Add(type); + } + if (!usedAllTowers) + { + usedAllTowers = AchievementManager.instance.CheckAllTowers(); + } + switch (type) + { + case TowerType.Crossbow: + crossbow.AddNewTower(t); + break; + case TowerType.Morter: + morter.AddNewTower(t); + break; + case TowerType.TeslaCoil: + teslaCoil.AddNewTower(t); + break; + case TowerType.FlameThrower: + flameThrower.AddNewTower(t); + break; + case TowerType.PoisonSprayer: + poisonSprayer.AddNewTower(t); + break; + case TowerType.Frost: + frostKeep.AddNewTower(t); + break; + case TowerType.Radar: + radar.AddNewTower(t); + break; + case TowerType.Obelisk: + obelisk.AddNewTower(t); + break; + case TowerType.ParticleCannon: + particleCannon.AddNewTower(t); + break; + case TowerType.Shredder: + shredder.AddNewTower(t); + break; + case TowerType.Encampment: + encampment.AddNewTower(t); + break; + case TowerType.Lookout: + lookout.AddNewTower(t); + break; + default: + Debug.LogError("Failed to add tower to flyweight"); + break; + } + } + + public void RemoveTower(Tower t, TowerType type) + { + switch (type) + { + case TowerType.Crossbow: + crossbow.RemoveTower(t); + break; + case TowerType.Morter: + morter.RemoveTower(t); + break; + case TowerType.TeslaCoil: + teslaCoil.RemoveTower(t); + break; + case TowerType.FlameThrower: + flameThrower.RemoveTower(t); + break; + case TowerType.PoisonSprayer: + poisonSprayer.RemoveTower(t); + break; + case TowerType.Frost: + frostKeep.RemoveTower(t); + break; + case TowerType.Obelisk: + obelisk.RemoveTower(t); + break; + case TowerType.Radar: + radar.RemoveTower(t); + break; + case TowerType.ParticleCannon: + particleCannon.RemoveTower(t); + break; + case TowerType.Shredder: + shredder.RemoveTower(t); + break; + case TowerType.Encampment: + encampment.RemoveTower(t); + break; + case TowerType.Lookout: + lookout.RemoveTower(t); + break; + default: + Debug.LogError("Failed to add tower to flyweight"); + break; + } + } + + public void UpdateAllTowers() + { + crossbow.UpdateTowerStats(); + morter.UpdateTowerStats(); + teslaCoil.UpdateTowerStats(); + flameThrower.UpdateTowerStats(); + poisonSprayer.UpdateTowerStats(); + frostKeep.UpdateTowerStats(); + radar.UpdateTowerStats(); + obelisk.UpdateTowerStats(); + particleCannon.UpdateTowerStats(); + shredder.UpdateTowerStats(); + encampment.UpdateTowerStats(); + lookout.UpdateTowerStats(); + } + + public int GetSellPrice(TowerType type) + { + switch (type) + { + case TowerType.Crossbow: + return crossbow.sellPrice; + case TowerType.Morter: + return morter.sellPrice; + case TowerType.TeslaCoil: + return teslaCoil.sellPrice; + case TowerType.FlameThrower: + return flameThrower.sellPrice; + case TowerType.PoisonSprayer: + return poisonSprayer.sellPrice; + case TowerType.Frost: + return frostKeep.sellPrice; + case TowerType.Obelisk: + return obelisk.sellPrice; + case TowerType.Radar: + return radar.sellPrice; + case TowerType.ParticleCannon: + return particleCannon.sellPrice; + case TowerType.Shredder: + return shredder.sellPrice; + case TowerType.Encampment: + return encampment.sellPrice; + case TowerType.Lookout: + return lookout.sellPrice; + default: + Debug.LogError("Failed to add tower to flyweight"); + return -1; + } + } + + public float GetManaConsumptionBonus(TowerType type) + { + switch (type) + { + case TowerType.Crossbow: + return global.manaConsumptionAddition + crossbow.manaConsumptionAddition; + case TowerType.Morter: + return global.manaConsumptionAddition + morter.manaConsumptionAddition; + case TowerType.TeslaCoil: + return global.manaConsumptionAddition + teslaCoil.manaConsumptionAddition; + case TowerType.FlameThrower: + return global.manaConsumptionAddition + flameThrower.manaConsumptionAddition; + case TowerType.PoisonSprayer: + return global.manaConsumptionAddition + poisonSprayer.manaConsumptionAddition; + case TowerType.Frost: + return global.manaConsumptionAddition + frostKeep.manaConsumptionAddition; + case TowerType.Radar: + return global.manaConsumptionAddition + radar.manaConsumptionAddition; + case TowerType.Obelisk: + return global.manaConsumptionAddition + obelisk.manaConsumptionAddition; + case TowerType.ParticleCannon: + return global.manaConsumptionAddition + particleCannon.manaConsumptionAddition; + case TowerType.Shredder: + return global.manaConsumptionAddition + shredder.manaConsumptionAddition; + case TowerType.Encampment: + return global.manaConsumptionAddition + encampment.manaConsumptionAddition; + case TowerType.Lookout: + return global.manaConsumptionAddition + lookout.manaConsumptionAddition; + default: + Debug.Log("Failed to get global bonus"); + return 0f; + } + } + + public float GetCritChance(TowerType type) + { + switch (type) + { + case TowerType.Crossbow: + return global.critChance + crossbow.critChance; + case TowerType.Morter: + return global.critChance + morter.critChance; + case TowerType.TeslaCoil: + return global.critChance + teslaCoil.critChance; + case TowerType.FlameThrower: + return global.critChance + flameThrower.critChance; + case TowerType.PoisonSprayer: + return global.critChance + poisonSprayer.critChance; + case TowerType.Frost: + return global.critChance + frostKeep.critChance; + case TowerType.Radar: + return global.critChance + radar.critChance; + case TowerType.Obelisk: + return global.critChance + obelisk.critChance; + case TowerType.ParticleCannon: + return global.critChance + particleCannon.critChance; + case TowerType.Shredder: + return global.critChance + shredder.critChance; + case TowerType.Encampment: + return global.critChance + encampment.critChance; + case TowerType.Lookout: + return global.critChance + lookout.critChance; + default: + Debug.Log("Failed to get global bonus"); + return 0f; + } + } + + public float GetStunChance(TowerType type) + { + switch (type) + { + case TowerType.Crossbow: + return global.stunChance + crossbow.stunChance; + case TowerType.Morter: + return global.stunChance + morter.stunChance; + case TowerType.TeslaCoil: + return global.stunChance + teslaCoil.stunChance; + case TowerType.FlameThrower: + return global.stunChance + flameThrower.stunChance; + case TowerType.PoisonSprayer: + return global.stunChance + poisonSprayer.stunChance; + case TowerType.Frost: + return global.stunChance + frostKeep.stunChance; + case TowerType.Radar: + return global.stunChance + radar.stunChance; + case TowerType.Obelisk: + return global.stunChance + obelisk.stunChance; + case TowerType.ParticleCannon: + return global.stunChance + particleCannon.stunChance; + case TowerType.Shredder: + return global.stunChance + shredder.stunChance; + case TowerType.Encampment: + return global.stunChance + encampment.stunChance; + case TowerType.Lookout: + return global.stunChance + lookout.stunChance; + default: + Debug.Log("Failed to get global bonus"); + return 0f; + } + } + + public float GetCritChanceLevelMultiplier(TowerType type) + { + switch (type) + { + case TowerType.Crossbow: + return global.critChanceLevelMultiplier + crossbow.critChanceLevelMultiplier; + case TowerType.Morter: + return global.critChanceLevelMultiplier + morter.critChanceLevelMultiplier; + case TowerType.TeslaCoil: + return global.critChanceLevelMultiplier + teslaCoil.critChanceLevelMultiplier; + case TowerType.FlameThrower: + return global.critChanceLevelMultiplier + flameThrower.critChanceLevelMultiplier; + case TowerType.PoisonSprayer: + return global.critChanceLevelMultiplier + poisonSprayer.critChanceLevelMultiplier; + case TowerType.Frost: + return global.critChanceLevelMultiplier + frostKeep.critChanceLevelMultiplier; + case TowerType.Radar: + return global.critChanceLevelMultiplier + radar.critChanceLevelMultiplier; + case TowerType.Obelisk: + return global.critChanceLevelMultiplier + obelisk.critChanceLevelMultiplier; + case TowerType.ParticleCannon: + return global.critChanceLevelMultiplier + particleCannon.critChanceLevelMultiplier; + case TowerType.Shredder: + return global.critChanceLevelMultiplier + shredder.critChanceLevelMultiplier; + case TowerType.Encampment: + return global.critChanceLevelMultiplier + encampment.critChanceLevelMultiplier; + case TowerType.Lookout: + return global.critChanceLevelMultiplier + lookout.critChanceLevelMultiplier; + default: + Debug.Log("Failed to get global bonus"); + return 0f; + } + } + + public float GetBonusRange(TowerType type) + { + switch (type) + { + case TowerType.Crossbow: + return global.bonusRange + crossbow.bonusRange; + case TowerType.Morter: + return global.bonusRange + morter.bonusRange; + case TowerType.TeslaCoil: + return global.bonusRange + teslaCoil.bonusRange; + case TowerType.FlameThrower: + return global.bonusRange + flameThrower.bonusRange; + case TowerType.PoisonSprayer: + return global.bonusRange + poisonSprayer.bonusRange; + case TowerType.Frost: + return global.bonusRange + frostKeep.bonusRange; + case TowerType.Radar: + return global.bonusRange + radar.bonusRange; + case TowerType.Obelisk: + return global.bonusRange + obelisk.bonusRange; + case TowerType.ParticleCannon: + return global.bonusRange + particleCannon.bonusRange; + case TowerType.Shredder: + return global.bonusRange + shredder.bonusRange; + case TowerType.Encampment: + return global.bonusRange + encampment.bonusRange; + case TowerType.Lookout: + return global.bonusRange + lookout.bonusRange; + default: + Debug.Log("Failed to get global bonus"); + return 0f; + } + } + + public int GetBonusBaseDamage(TowerType type) + { + switch (type) + { + case TowerType.Crossbow: + return global.bonusBaseDamage + crossbow.bonusBaseDamage; + case TowerType.Morter: + return global.bonusBaseDamage + morter.bonusBaseDamage; + case TowerType.TeslaCoil: + return global.bonusBaseDamage + teslaCoil.bonusBaseDamage; + case TowerType.FlameThrower: + return global.bonusBaseDamage + flameThrower.bonusBaseDamage; + case TowerType.PoisonSprayer: + return global.bonusBaseDamage + poisonSprayer.bonusBaseDamage; + case TowerType.Frost: + return global.bonusBaseDamage + frostKeep.bonusBaseDamage; + case TowerType.Radar: + return global.bonusBaseDamage + radar.bonusBaseDamage; + case TowerType.Obelisk: + return global.bonusBaseDamage + obelisk.bonusBaseDamage; + case TowerType.ParticleCannon: + return global.bonusBaseDamage + particleCannon.bonusBaseDamage; + case TowerType.Shredder: + return global.bonusBaseDamage + shredder.bonusBaseDamage; + case TowerType.Encampment: + return global.bonusBaseDamage + encampment.bonusBaseDamage; + case TowerType.Lookout: + return global.bonusBaseDamage + lookout.bonusBaseDamage; + default: + Debug.Log("Failed to get global bonus"); + return 0; + } + } + + public int GetBonusHealthDamage(TowerType type) + { + switch (type) + { + case TowerType.Crossbow: + return global.bonusHealthDamage + crossbow.bonusHealthDamage; + case TowerType.Morter: + return global.bonusHealthDamage + morter.bonusHealthDamage; + case TowerType.TeslaCoil: + return global.bonusHealthDamage + teslaCoil.bonusHealthDamage; + case TowerType.FlameThrower: + return global.bonusHealthDamage + flameThrower.bonusHealthDamage; + case TowerType.PoisonSprayer: + return global.bonusHealthDamage + poisonSprayer.bonusHealthDamage; + case TowerType.Frost: + return global.bonusHealthDamage + frostKeep.bonusHealthDamage; + case TowerType.Radar: + return global.bonusHealthDamage + radar.bonusHealthDamage; + case TowerType.Obelisk: + return global.bonusHealthDamage + obelisk.bonusHealthDamage; + case TowerType.ParticleCannon: + return global.bonusHealthDamage + particleCannon.bonusHealthDamage; + case TowerType.Shredder: + return global.bonusHealthDamage + shredder.bonusHealthDamage; + case TowerType.Encampment: + return global.bonusHealthDamage + encampment.bonusHealthDamage; + case TowerType.Lookout: + return global.bonusHealthDamage + lookout.bonusHealthDamage; + default: + Debug.Log("Failed to get global bonus"); + return 0; + } + } + + public int GetBonusArmorDamage(TowerType type) + { + switch (type) + { + case TowerType.Crossbow: + return global.bonusArmorDamage + crossbow.bonusArmorDamage; + case TowerType.Morter: + return global.bonusArmorDamage + morter.bonusArmorDamage; + case TowerType.TeslaCoil: + return global.bonusArmorDamage + teslaCoil.bonusArmorDamage; + case TowerType.FlameThrower: + return global.bonusArmorDamage + flameThrower.bonusArmorDamage; + case TowerType.PoisonSprayer: + return global.bonusArmorDamage + poisonSprayer.bonusArmorDamage; + case TowerType.Frost: + return global.bonusArmorDamage + frostKeep.bonusArmorDamage; + case TowerType.Radar: + return global.bonusArmorDamage + radar.bonusArmorDamage; + case TowerType.Obelisk: + return global.bonusArmorDamage + obelisk.bonusArmorDamage; + case TowerType.ParticleCannon: + return global.bonusArmorDamage + particleCannon.bonusArmorDamage; + case TowerType.Shredder: + return global.bonusArmorDamage + shredder.bonusArmorDamage; + case TowerType.Encampment: + return global.bonusArmorDamage + encampment.bonusArmorDamage; + case TowerType.Lookout: + return global.bonusArmorDamage + lookout.bonusArmorDamage; + default: + Debug.Log("Failed to get global bonus"); + return 0; + } + } + + public int GetBonusShieldDamage(TowerType type) + { + switch (type) + { + case TowerType.Crossbow: + return global.bonusShieldDamage + crossbow.bonusShieldDamage; + case TowerType.Morter: + return global.bonusShieldDamage + morter.bonusShieldDamage; + case TowerType.TeslaCoil: + return global.bonusShieldDamage + teslaCoil.bonusShieldDamage; + case TowerType.FlameThrower: + return global.bonusShieldDamage + flameThrower.bonusShieldDamage; + case TowerType.PoisonSprayer: + return global.bonusShieldDamage + poisonSprayer.bonusShieldDamage; + case TowerType.Frost: + return global.bonusShieldDamage + frostKeep.bonusShieldDamage; + case TowerType.Radar: + return global.bonusShieldDamage + radar.bonusShieldDamage; + case TowerType.Obelisk: + return global.bonusShieldDamage + obelisk.bonusShieldDamage; + case TowerType.ParticleCannon: + return global.bonusShieldDamage + particleCannon.bonusShieldDamage; + case TowerType.Shredder: + return global.bonusShieldDamage + shredder.bonusShieldDamage; + case TowerType.Encampment: + return global.bonusShieldDamage + encampment.bonusShieldDamage; + case TowerType.Lookout: + return global.bonusShieldDamage + lookout.bonusShieldDamage; + default: + Debug.Log("Failed to get global bonus"); + return 0; + } + } + + public float GetBonusSlow(TowerType type) + { + switch (type) + { + case TowerType.Crossbow: + return global.bonusSlow + crossbow.bonusSlow; + case TowerType.Morter: + return global.bonusSlow + morter.bonusSlow; + case TowerType.TeslaCoil: + return global.bonusSlow + teslaCoil.bonusSlow; + case TowerType.FlameThrower: + return global.bonusSlow + flameThrower.bonusSlow; + case TowerType.PoisonSprayer: + return global.bonusSlow + poisonSprayer.bonusSlow; + case TowerType.Frost: + return global.bonusSlow + frostKeep.bonusSlow; + case TowerType.Radar: + return global.bonusSlow + radar.bonusSlow; + case TowerType.Obelisk: + return global.bonusSlow + obelisk.bonusSlow; + case TowerType.ParticleCannon: + return global.bonusSlow + particleCannon.bonusSlow; + case TowerType.Shredder: + return global.bonusSlow + shredder.bonusSlow; + case TowerType.Encampment: + return global.bonusSlow + encampment.bonusSlow; + case TowerType.Lookout: + return global.bonusSlow + lookout.bonusSlow; + default: + Debug.Log("Failed to get global bonus"); + return 0f; + } + } + + public float GetBonusBleed(TowerType type) + { + switch (type) + { + case TowerType.Crossbow: + return global.bonusBleed + crossbow.bonusBleed; + case TowerType.Morter: + return global.bonusBleed + morter.bonusBleed; + case TowerType.TeslaCoil: + return global.bonusBleed + teslaCoil.bonusBleed; + case TowerType.FlameThrower: + return global.bonusBleed + flameThrower.bonusBleed; + case TowerType.PoisonSprayer: + return global.bonusBleed + poisonSprayer.bonusBleed; + case TowerType.Frost: + return global.bonusBleed + frostKeep.bonusBleed; + case TowerType.Radar: + return global.bonusBleed + radar.bonusBleed; + case TowerType.Obelisk: + return global.bonusBleed + obelisk.bonusBleed; + case TowerType.ParticleCannon: + return global.bonusBleed + particleCannon.bonusBleed; + case TowerType.Shredder: + return global.bonusBleed + shredder.bonusBleed; + case TowerType.Encampment: + return global.bonusBleed + encampment.bonusBleed; + case TowerType.Lookout: + return global.bonusBleed + lookout.bonusBleed; + default: + Debug.Log("Failed to get global bonus"); + return 0f; + } + } + + public float GetBonusBurn(TowerType type) + { + switch (type) + { + case TowerType.Crossbow: + return global.bonusBurn + crossbow.bonusBurn; + case TowerType.Morter: + return global.bonusBurn + morter.bonusBurn; + case TowerType.TeslaCoil: + return global.bonusBurn + teslaCoil.bonusBurn; + case TowerType.FlameThrower: + return global.bonusBurn + flameThrower.bonusBurn; + case TowerType.PoisonSprayer: + return global.bonusBurn + poisonSprayer.bonusBurn; + case TowerType.Frost: + return global.bonusBurn + frostKeep.bonusBurn; + case TowerType.Radar: + return global.bonusBurn + radar.bonusBurn; + case TowerType.Obelisk: + return global.bonusBurn + obelisk.bonusBurn; + case TowerType.ParticleCannon: + return global.bonusBurn + particleCannon.bonusBurn; + case TowerType.Shredder: + return global.bonusBurn + shredder.bonusBurn; + case TowerType.Encampment: + return global.bonusBurn + encampment.bonusBurn; + case TowerType.Lookout: + return global.bonusBurn + lookout.bonusBurn; + default: + Debug.Log("Failed to get global bonus"); + return 0f; + } + } + + public float GetBonusPoison(TowerType type) + { + switch (type) + { + case TowerType.Crossbow: + return global.bonusPoison + crossbow.bonusPoison; + case TowerType.Morter: + return global.bonusPoison + morter.bonusPoison; + case TowerType.TeslaCoil: + return global.bonusPoison + teslaCoil.bonusPoison; + case TowerType.FlameThrower: + return global.bonusPoison + flameThrower.bonusPoison; + case TowerType.PoisonSprayer: + return global.bonusPoison + poisonSprayer.bonusPoison; + case TowerType.Frost: + return global.bonusPoison + frostKeep.bonusPoison; + case TowerType.Radar: + return global.bonusPoison + radar.bonusPoison; + case TowerType.Obelisk: + return global.bonusPoison + obelisk.bonusPoison; + case TowerType.ParticleCannon: + return global.bonusPoison + particleCannon.bonusPoison; + case TowerType.Shredder: + return global.bonusPoison + shredder.bonusPoison; + case TowerType.Encampment: + return global.bonusPoison + encampment.bonusPoison; + case TowerType.Lookout: + return global.bonusPoison + lookout.bonusPoison; + default: + Debug.Log("Failed to get global bonus"); + return 0f; + } + } + + public float GetBonusBlast(TowerType type) + { + switch (type) + { + case TowerType.Crossbow: + return global.bonusBlast + crossbow.bonusBlast; + case TowerType.Morter: + return global.bonusBlast + morter.bonusBlast; + case TowerType.TeslaCoil: + return global.bonusBlast + teslaCoil.bonusBlast; + case TowerType.FlameThrower: + return global.bonusBlast + flameThrower.bonusBlast; + case TowerType.PoisonSprayer: + return global.bonusBlast + poisonSprayer.bonusBlast; + case TowerType.Frost: + return global.bonusBlast + frostKeep.bonusBlast; + case TowerType.Radar: + return global.bonusBlast + radar.bonusBlast; + case TowerType.Obelisk: + return global.bonusBlast + obelisk.bonusBlast; + case TowerType.ParticleCannon: + return global.bonusBlast + particleCannon.bonusBlast; + case TowerType.Shredder: + return global.bonusBlast + shredder.bonusBlast; + case TowerType.Encampment: + return global.bonusBlast + encampment.bonusBlast; + case TowerType.Lookout: + return global.bonusBlast + lookout.bonusBlast; + default: + Debug.Log("Failed to get global bonus"); + return 0f; + } + } + + public void AddManaConsumption(TowerType type, float value) + { + switch (type) + { + case TowerType.Crossbow: + crossbow.AddManaAddition(value); + break; + case TowerType.Morter: + morter.AddManaAddition(value); + break; + case TowerType.TeslaCoil: + teslaCoil.AddManaAddition(value); + break; + case TowerType.FlameThrower: + flameThrower.AddManaAddition(value); + break; + case TowerType.PoisonSprayer: + poisonSprayer.AddManaAddition(value); + break; + case TowerType.Frost: + frostKeep.AddManaAddition(value); + break; + case TowerType.Radar: + radar.AddManaAddition(value); + break; + case TowerType.Obelisk: + obelisk.AddManaAddition(value); + break; + case TowerType.ParticleCannon: + particleCannon.AddManaAddition(value); + break; + case TowerType.Shredder: + shredder.AddManaAddition(value); + break; + case TowerType.Encampment: + encampment.AddManaAddition(value); + break; + case TowerType.Lookout: + lookout.AddManaAddition(value); + break; + case TowerType.Global: + global.AddManaAddition(value); + UpdateAllTowers(); + break; + default: + Debug.Log("Failed to set global bonus"); + break; + } + } + + public void AddCritChance(TowerType type, float value) + { + switch (type) + { + case TowerType.Crossbow: + crossbow.AddCritChance(value); + break; + case TowerType.Morter: + morter.AddCritChance(value); + break; + case TowerType.TeslaCoil: + teslaCoil.AddCritChance(value); + break; + case TowerType.FlameThrower: + flameThrower.AddCritChance(value); + break; + case TowerType.PoisonSprayer: + poisonSprayer.AddCritChance(value); + break; + case TowerType.Frost: + frostKeep.AddCritChance(value); + break; + case TowerType.Radar: + radar.AddCritChance(value); + break; + case TowerType.Obelisk: + obelisk.AddCritChance(value); + break; + case TowerType.ParticleCannon: + particleCannon.AddCritChance(value); + break; + case TowerType.Shredder: + shredder.AddCritChance(value); + break; + case TowerType.Encampment: + encampment.AddCritChance(value); + break; + case TowerType.Lookout: + lookout.AddCritChance(value); + break; + case TowerType.Global: + global.AddCritChance(value); + UpdateAllTowers(); + break; + default: + Debug.Log("Failed to set global bonus"); + break; + } + } + + public void AddStunChance(TowerType type, float value) + { + switch (type) + { + case TowerType.Crossbow: + crossbow.AddStunChance(value); + break; + case TowerType.Morter: + morter.AddStunChance(value); + break; + case TowerType.TeslaCoil: + teslaCoil.AddStunChance(value); + break; + case TowerType.FlameThrower: + flameThrower.AddStunChance(value); + break; + case TowerType.PoisonSprayer: + poisonSprayer.AddStunChance(value); + break; + case TowerType.Frost: + frostKeep.AddStunChance(value); + break; + case TowerType.Radar: + radar.AddStunChance(value); + break; + case TowerType.Obelisk: + obelisk.AddStunChance(value); + break; + case TowerType.ParticleCannon: + particleCannon.AddStunChance(value); + break; + case TowerType.Shredder: + shredder.AddStunChance(value); + break; + case TowerType.Encampment: + encampment.AddStunChance(value); + break; + case TowerType.Lookout: + lookout.AddStunChance(value); + break; + case TowerType.Global: + global.AddStunChance(value); + UpdateAllTowers(); + break; + default: + Debug.Log("Failed to set global bonus"); + break; + } + } + + public void AddCritChanceLevelMultiplier(TowerType type, float value) + { + switch (type) + { + case TowerType.Crossbow: + crossbow.AddCritChanceLevelMultiplier(value); + break; + case TowerType.Morter: + morter.AddCritChanceLevelMultiplier(value); + break; + case TowerType.TeslaCoil: + teslaCoil.AddCritChanceLevelMultiplier(value); + break; + case TowerType.FlameThrower: + flameThrower.AddCritChanceLevelMultiplier(value); + break; + case TowerType.PoisonSprayer: + poisonSprayer.AddCritChanceLevelMultiplier(value); + break; + case TowerType.Frost: + frostKeep.AddCritChanceLevelMultiplier(value); + break; + case TowerType.Radar: + radar.AddCritChanceLevelMultiplier(value); + break; + case TowerType.Obelisk: + obelisk.AddCritChanceLevelMultiplier(value); + break; + case TowerType.ParticleCannon: + particleCannon.AddCritChanceLevelMultiplier(value); + break; + case TowerType.Shredder: + shredder.AddCritChanceLevelMultiplier(value); + break; + case TowerType.Encampment: + encampment.AddCritChanceLevelMultiplier(value); + break; + case TowerType.Lookout: + lookout.AddCritChanceLevelMultiplier(value); + break; + case TowerType.Global: + global.AddCritChanceLevelMultiplier(value); + UpdateAllTowers(); + break; + default: + Debug.Log("Failed to set global bonus"); + break; + } + } + + public void AddBonusRange(TowerType type, float value) + { + switch (type) + { + case TowerType.Crossbow: + crossbow.AddBonusRange(value); + break; + case TowerType.Morter: + morter.AddBonusRange(value); + break; + case TowerType.TeslaCoil: + teslaCoil.AddBonusRange(value); + break; + case TowerType.FlameThrower: + flameThrower.AddBonusRange(value); + break; + case TowerType.PoisonSprayer: + poisonSprayer.AddBonusRange(value); + break; + case TowerType.Frost: + frostKeep.AddBonusRange(value); + break; + case TowerType.Radar: + radar.AddBonusRange(value); + break; + case TowerType.Obelisk: + obelisk.AddBonusRange(value); + break; + case TowerType.ParticleCannon: + particleCannon.AddBonusRange(value); + break; + case TowerType.Shredder: + shredder.AddBonusRange(value); + break; + case TowerType.Encampment: + encampment.AddBonusRange(value); + break; + case TowerType.Lookout: + lookout.AddBonusRange(value); + break; + case TowerType.Global: + global.AddBonusRange(value); + UpdateAllTowers(); + break; + default: + Debug.Log("Failed to set global bonus"); + break; + } + } + + public void AddBonusBaseDamage(TowerType type, int value) + { + switch (type) + { + case TowerType.Crossbow: + crossbow.AddBonusBaseDamage(value); + break; + case TowerType.Morter: + morter.AddBonusBaseDamage(value); + break; + case TowerType.TeslaCoil: + teslaCoil.AddBonusBaseDamage(value); + break; + case TowerType.FlameThrower: + flameThrower.AddBonusBaseDamage(value); + break; + case TowerType.PoisonSprayer: + poisonSprayer.AddBonusBaseDamage(value); + break; + case TowerType.Frost: + frostKeep.AddBonusBaseDamage(value); + break; + case TowerType.Radar: + radar.AddBonusBaseDamage(value); + break; + case TowerType.Obelisk: + obelisk.AddBonusBaseDamage(value); + break; + case TowerType.ParticleCannon: + particleCannon.AddBonusBaseDamage(value); + break; + case TowerType.Shredder: + shredder.AddBonusBaseDamage(value); + break; + case TowerType.Encampment: + encampment.AddBonusBaseDamage(value); + break; + case TowerType.Lookout: + lookout.AddBonusBaseDamage(value); + break; + case TowerType.Global: + global.AddBonusBaseDamage(value); + UpdateAllTowers(); + break; + default: + Debug.Log("Failed to set global bonus"); + break; + } + } + + public void AddBonusHealthDamage(TowerType type, int value) + { + switch (type) + { + case TowerType.Crossbow: + crossbow.AddBonusHealthDamage(value); + break; + case TowerType.Morter: + morter.AddBonusHealthDamage(value); + break; + case TowerType.TeslaCoil: + teslaCoil.AddBonusHealthDamage(value); + break; + case TowerType.FlameThrower: + flameThrower.AddBonusHealthDamage(value); + break; + case TowerType.PoisonSprayer: + poisonSprayer.AddBonusHealthDamage(value); + break; + case TowerType.Frost: + frostKeep.AddBonusHealthDamage(value); + break; + case TowerType.Radar: + radar.AddBonusHealthDamage(value); + break; + case TowerType.Obelisk: + obelisk.AddBonusHealthDamage(value); + break; + case TowerType.ParticleCannon: + particleCannon.AddBonusHealthDamage(value); + break; + case TowerType.Shredder: + shredder.AddBonusHealthDamage(value); + break; + case TowerType.Encampment: + encampment.AddBonusHealthDamage(value); + break; + case TowerType.Lookout: + lookout.AddBonusHealthDamage(value); + break; + case TowerType.Global: + global.AddBonusHealthDamage(value); + UpdateAllTowers(); + break; + default: + Debug.Log("Failed to set global bonus"); + break; + } + } + + public void AddBonusArmorDamage(TowerType type, int value) + { + switch (type) + { + case TowerType.Crossbow: + crossbow.AddBonusArmorDamage(value); + break; + case TowerType.Morter: + morter.AddBonusArmorDamage(value); + break; + case TowerType.TeslaCoil: + teslaCoil.AddBonusArmorDamage(value); + break; + case TowerType.FlameThrower: + flameThrower.AddBonusArmorDamage(value); + break; + case TowerType.PoisonSprayer: + poisonSprayer.AddBonusArmorDamage(value); + break; + case TowerType.Frost: + frostKeep.AddBonusArmorDamage(value); + break; + case TowerType.Radar: + radar.AddBonusArmorDamage(value); + break; + case TowerType.Obelisk: + obelisk.AddBonusArmorDamage(value); + break; + case TowerType.ParticleCannon: + particleCannon.AddBonusArmorDamage(value); + break; + case TowerType.Shredder: + shredder.AddBonusArmorDamage(value); + break; + case TowerType.Encampment: + encampment.AddBonusArmorDamage(value); + break; + case TowerType.Lookout: + lookout.AddBonusArmorDamage(value); + break; + case TowerType.Global: + global.AddBonusArmorDamage(value); + UpdateAllTowers(); + break; + default: + Debug.Log("Failed to set global bonus"); + break; + } + } + + public void AddBonusShieldDamage(TowerType type, int value) + { + switch (type) + { + case TowerType.Crossbow: + crossbow.AddBonusShieldDamage(value); + break; + case TowerType.Morter: + morter.AddBonusShieldDamage(value); + break; + case TowerType.TeslaCoil: + teslaCoil.AddBonusShieldDamage(value); + break; + case TowerType.FlameThrower: + flameThrower.AddBonusShieldDamage(value); + break; + case TowerType.PoisonSprayer: + poisonSprayer.AddBonusShieldDamage(value); + break; + case TowerType.Frost: + frostKeep.AddBonusShieldDamage(value); + break; + case TowerType.Radar: + radar.AddBonusShieldDamage(value); + break; + case TowerType.Obelisk: + obelisk.AddBonusShieldDamage(value); + break; + case TowerType.ParticleCannon: + particleCannon.AddBonusShieldDamage(value); + break; + case TowerType.Shredder: + shredder.AddBonusShieldDamage(value); + break; + case TowerType.Encampment: + encampment.AddBonusShieldDamage(value); + break; + case TowerType.Lookout: + lookout.AddBonusShieldDamage(value); + break; + case TowerType.Global: + global.AddBonusShieldDamage(value); + UpdateAllTowers(); + break; + default: + Debug.Log("Failed to set global bonus"); + break; + } + } + + public void AddBonusSlow(TowerType type, float value) + { + switch (type) + { + case TowerType.Crossbow: + crossbow.AddBonusSlow(value); + break; + case TowerType.Morter: + morter.AddBonusSlow(value); + break; + case TowerType.TeslaCoil: + teslaCoil.AddBonusSlow(value); + break; + case TowerType.FlameThrower: + flameThrower.AddBonusSlow(value); + break; + case TowerType.PoisonSprayer: + poisonSprayer.AddBonusSlow(value); + break; + case TowerType.Frost: + frostKeep.AddBonusSlow(value); + break; + case TowerType.Radar: + radar.AddBonusSlow(value); + break; + case TowerType.Obelisk: + obelisk.AddBonusSlow(value); + break; + case TowerType.ParticleCannon: + particleCannon.AddBonusSlow(value); + break; + case TowerType.Shredder: + shredder.AddBonusSlow(value); + break; + case TowerType.Encampment: + encampment.AddBonusSlow(value); + break; + case TowerType.Lookout: + lookout.AddBonusSlow(value); + break; + case TowerType.Global: + global.AddBonusSlow(value); + UpdateAllTowers(); + break; + default: + Debug.Log("Failed to set global bonus"); + break; + } + } + + public void AddBonusBleed(TowerType type, float value) + { + switch (type) + { + case TowerType.Crossbow: + crossbow.AddBonusBleed(value); + break; + case TowerType.Morter: + morter.AddBonusBleed(value); + break; + case TowerType.TeslaCoil: + teslaCoil.AddBonusBleed(value); + break; + case TowerType.FlameThrower: + flameThrower.AddBonusBleed(value); + break; + case TowerType.PoisonSprayer: + poisonSprayer.AddBonusBleed(value); + break; + case TowerType.Frost: + frostKeep.AddBonusBleed(value); + break; + case TowerType.Radar: + radar.AddBonusBleed(value); + break; + case TowerType.Obelisk: + obelisk.AddBonusBleed(value); + break; + case TowerType.ParticleCannon: + particleCannon.AddBonusBleed(value); + break; + case TowerType.Shredder: + shredder.AddBonusBleed(value); + break; + case TowerType.Encampment: + encampment.AddBonusBleed(value); + break; + case TowerType.Lookout: + lookout.AddBonusBleed(value); + break; + case TowerType.Global: + global.AddBonusBleed(value); + UpdateAllTowers(); + break; + default: + Debug.Log("Failed to set global bonus"); + break; + } + } + + public void AddBonusBurn(TowerType type, float value) + { + switch (type) + { + case TowerType.Crossbow: + crossbow.AddBonusBurn(value); + break; + case TowerType.Morter: + morter.AddBonusBurn(value); + break; + case TowerType.TeslaCoil: + teslaCoil.AddBonusBurn(value); + break; + case TowerType.FlameThrower: + flameThrower.AddBonusBurn(value); + break; + case TowerType.PoisonSprayer: + poisonSprayer.AddBonusBurn(value); + break; + case TowerType.Frost: + frostKeep.AddBonusBurn(value); + break; + case TowerType.Radar: + radar.AddBonusBurn(value); + break; + case TowerType.Obelisk: + obelisk.AddBonusBurn(value); + break; + case TowerType.ParticleCannon: + particleCannon.AddBonusBurn(value); + break; + case TowerType.Shredder: + shredder.AddBonusBurn(value); + break; + case TowerType.Encampment: + encampment.AddBonusBurn(value); + break; + case TowerType.Lookout: + lookout.AddBonusBurn(value); + break; + case TowerType.Global: + global.AddBonusBurn(value); + UpdateAllTowers(); + break; + default: + Debug.Log("Failed to set global bonus"); + break; + } + } + + public void AddBonusPoison(TowerType type, float value) + { + switch (type) + { + case TowerType.Crossbow: + crossbow.AddBonusPoison(value); + break; + case TowerType.Morter: + morter.AddBonusPoison(value); + break; + case TowerType.TeslaCoil: + teslaCoil.AddBonusPoison(value); + break; + case TowerType.FlameThrower: + flameThrower.AddBonusPoison(value); + break; + case TowerType.PoisonSprayer: + poisonSprayer.AddBonusPoison(value); + break; + case TowerType.Frost: + frostKeep.AddBonusPoison(value); + break; + case TowerType.Radar: + radar.AddBonusPoison(value); + break; + case TowerType.Obelisk: + obelisk.AddBonusPoison(value); + break; + case TowerType.ParticleCannon: + particleCannon.AddBonusPoison(value); + break; + case TowerType.Shredder: + shredder.AddBonusPoison(value); + break; + case TowerType.Encampment: + encampment.AddBonusPoison(value); + break; + case TowerType.Lookout: + lookout.AddBonusPoison(value); + break; + case TowerType.Global: + global.AddBonusPoison(value); + UpdateAllTowers(); + break; + default: + Debug.Log("Failed to set global bonus"); + break; + } + } + + public void AddBonusBlast(TowerType type, float value) + { + switch (type) + { + case TowerType.Crossbow: + crossbow.AddBonusBlast(value); + break; + case TowerType.Morter: + morter.AddBonusBlast(value); + break; + case TowerType.TeslaCoil: + teslaCoil.AddBonusBlast(value); + break; + case TowerType.FlameThrower: + flameThrower.AddBonusBlast(value); + break; + case TowerType.PoisonSprayer: + poisonSprayer.AddBonusBlast(value); + break; + case TowerType.Frost: + frostKeep.AddBonusBlast(value); + break; + case TowerType.Radar: + radar.AddBonusBlast(value); + break; + case TowerType.Obelisk: + obelisk.AddBonusBlast(value); + break; + case TowerType.ParticleCannon: + particleCannon.AddBonusBlast(value); + break; + case TowerType.Shredder: + shredder.AddBonusBlast(value); + break; + case TowerType.Encampment: + encampment.AddBonusBlast(value); + break; + case TowerType.Lookout: + lookout.AddBonusBlast(value); + break; + case TowerType.Global: + global.AddBonusBlast(value); + UpdateAllTowers(); + break; + default: + Debug.Log("Failed to set global bonus"); + break; + } + } +} diff --git a/GameCode/TowerType.cs b/GameCode/TowerType.cs new file mode 100644 index 0000000..9bbc242 --- /dev/null +++ b/GameCode/TowerType.cs @@ -0,0 +1,18 @@ +public enum TowerType +{ + Crossbow, + Morter, + TeslaCoil, + Frost, + Obelisk, + FlameThrower, + PoisonSprayer, + Siphon, + Radar, + ParticleCannon, + DOT, + Global, + Shredder, + Encampment, + Lookout +} diff --git a/GameCode/TowerUI.cs b/GameCode/TowerUI.cs new file mode 100644 index 0000000..7b49139 --- /dev/null +++ b/GameCode/TowerUI.cs @@ -0,0 +1,289 @@ +using System; +using UnityEngine; +using UnityEngine.UI; + +public class TowerUI : MonoBehaviour +{ + private Tower myTower; + + private int level; + + private int baseDamage; + + private int healthDamage; + + private int armorDamage; + + private int shieldDamage; + + private float healthXP; + + private float armorXP; + + private float shieldXP; + + private bool usesMana; + + private float range; + + private float manaUseMultiplier; + + private int rpm; + + [SerializeField] + private Image healthXPImg; + + [SerializeField] + private Image armorXPImg; + + [SerializeField] + private Image shieldXPImg; + + [SerializeField] + private Text levelText; + + [SerializeField] + private Text baseDamageText; + + [SerializeField] + private Text healthDamageText; + + [SerializeField] + private Text armorDamageText; + + [SerializeField] + private Text shieldDamageText; + + [SerializeField] + private Text healthXPText; + + [SerializeField] + private Text armorXPText; + + [SerializeField] + private Text shieldXPText; + + [SerializeField] + private Text[] priorityTexts; + + [SerializeField] + private Text slowText; + + [SerializeField] + private Text bleedText; + + [SerializeField] + private Text burnText; + + [SerializeField] + private Text poisonText; + + [SerializeField] + private Text critText; + + [SerializeField] + private Text rangeText; + + [SerializeField] + private Text rpmText; + + [SerializeField] + private Text manaUseText; + + [SerializeField] + private Text demolishText; + + private float timer = 0.5f; + + [SerializeField] + private LineRenderer line; + + private void Start() + { + UIManager.instance.SetNewUI(base.gameObject); + } + + private void Update() + { + if (timer < 0f) + { + SetStats(myTower); + timer = 0.5f; + } + timer -= Time.deltaTime; + if (Input.GetKeyDown(KeyCode.Alpha1) || Input.GetKeyDown(KeyCode.Keypad1)) + { + BuyHealthLevel(); + } + if (Input.GetKeyDown(KeyCode.Alpha2) || Input.GetKeyDown(KeyCode.Keypad2)) + { + BuyArmorLevel(); + } + if (Input.GetKeyDown(KeyCode.Alpha3) || Input.GetKeyDown(KeyCode.Keypad3)) + { + BuyShieldLevel(); + } + } + + public void SetStats(Tower _myTower) + { + myTower = _myTower; + level = myTower.level; + baseDamage = myTower.damage; + healthDamage = myTower.healthDamage; + armorDamage = myTower.armorDamage; + shieldDamage = myTower.shieldDamage; + healthXP = myTower.healthXP; + armorXP = myTower.armorXP; + shieldXP = myTower.shieldXP; + slowText.text = (int)(myTower.slowPercent * 100f) + "%"; + bleedText.text = (int)(myTower.bleedPercent * 100f) + "%"; + burnText.text = (int)(myTower.burnPercent * 100f) + "%"; + poisonText.text = (int)(myTower.poisonPercent * 100f) + "%"; + critText.text = CritText(); + if (myTower.range != range) + { + DrawCircle(); + } + range = myTower.range; + rpm = (int)myTower.rpm; + usesMana = myTower.consumesMana; + manaUseMultiplier = myTower.finalManaConsumption; + UpdateText(); + for (int i = 0; i < priorityTexts.Length; i++) + { + priorityTexts[i].text = myTower.priorities[i].ToString(); + } + } + + private void DrawCircle() + { + float num = myTower.range; + if (myTower.squareUI) + { + num += 0.5f; + line.SetVertexCount(5); + line.useWorldSpace = true; + Vector3 position = base.transform.position; + position.y = 0.4f; + line.SetPosition(0, new Vector3(num, 0f, num) + position); + line.SetPosition(1, new Vector3(num, 0f, 0f - num) + position); + line.SetPosition(2, new Vector3(0f - num, 0f, 0f - num) + position); + line.SetPosition(3, new Vector3(0f - num, 0f, num) + position); + line.SetPosition(4, new Vector3(num, 0f, num) + position); + return; + } + line.SetVertexCount(61); + line.useWorldSpace = true; + Vector3 vector = new Vector3(0f, 0f, 0f); + Vector3 position2 = base.transform.position; + position2.y = 0.4f; + float num2 = 0f; + for (int i = 0; i < 61; i++) + { + vector.x = Mathf.Cos((float)Math.PI / 180f * num2) * num; + vector.z = Mathf.Sin((float)Math.PI / 180f * num2) * num; + line.SetPosition(i, vector + position2); + num2 += 6f; + } + } + + private string CritText() + { + string text = "x2! "; + text = text + (int)Mathf.Clamp(myTower.critChance * 100f, 0f, 50f) + "%"; + if (myTower.critChance > 0.5f) + { + text = text + "\nx3!! " + (int)Mathf.Clamp(myTower.critChance * 100f - 50f, 0f, 50f) + "%"; + } + if (myTower.critChance > 1f) + { + text = text + "\nx4!! " + (int)Mathf.Clamp(myTower.critChance * 100f - 100f, 0f, 50f) + "%"; + } + return text; + } + + private void UpdateText() + { + levelText.text = "Level: " + level; + baseDamageText.text = "Base Damage: " + baseDamage; + healthDamageText.text = "Health Multiplier: " + healthDamage + " (" + baseDamage * healthDamage + ")"; + armorDamageText.text = "Armor Multiplier: " + armorDamage + " (" + baseDamage * armorDamage + ")"; + shieldDamageText.text = "Shield Multiplier: " + shieldDamage + " (" + baseDamage * shieldDamage + ")"; + healthXPText.text = ((10 * level - (int)healthXP) * myTower.upgradeCostMultiplier).ToString(); + armorXPText.text = ((10 * level - (int)armorXP) * myTower.upgradeCostMultiplier).ToString(); + shieldXPText.text = ((10 * level - (int)shieldXP) * myTower.upgradeCostMultiplier).ToString(); + healthXPImg.rectTransform.sizeDelta = new Vector2(healthXP / (float)level, 0.25f); + armorXPImg.rectTransform.sizeDelta = new Vector2(armorXP / (float)level, 0.25f); + shieldXPImg.rectTransform.sizeDelta = new Vector2(shieldXP / (float)level, 0.25f); + rangeText.text = "Range: " + range; + if (myTower.GetComponent<Dropper>() != null) + { + rpmText.text = "Fire Rate: " + (int)myTower.GetComponent<Dropper>().dropperRPMdisplay + " RPM"; + } + else + { + rpmText.text = "Fire Rate: " + rpm + " RPM"; + } + if (usesMana) + { + manaUseText.text = "Mana Use: " + (int)((float)baseDamage * manaUseMultiplier) + "/shot"; + } + else if (!usesMana && manaUseMultiplier > 0f) + { + manaUseText.text = "Mana Use: " + manaUseMultiplier + "/sec"; + } + else + { + manaUseText.text = ""; + } + demolishText.text = "Demolish (" + TowerManager.instance.GetSellPrice(myTower.towerType) + "g)"; + } + + public void BuyHealthLevel() + { + SFXManager.instance.ButtonClick(); + myTower.BuyHealthLevel(); + SetStats(myTower); + } + + public void BuyArmorLevel() + { + SFXManager.instance.ButtonClick(); + myTower.BuyArmorLevel(); + SetStats(myTower); + } + + public void BuyShieldLevel() + { + SFXManager.instance.ButtonClick(); + myTower.BuyShieldLevel(); + SetStats(myTower); + } + + public void TogglePriorityUp(int index) + { + SFXManager.instance.ButtonClick(); + myTower.TogglePriority(index, 1); + priorityTexts[index].text = myTower.priorities[index].ToString(); + } + + public void TogglePriorityDown(int index) + { + SFXManager.instance.ButtonClick(); + myTower.TogglePriority(index, -1); + priorityTexts[index].text = myTower.priorities[index].ToString(); + } + + public void DemolishTower() + { + SFXManager.instance.ButtonClick(); + myTower.Demolish(); + CloseUI(); + } + + public void CloseUI() + { + UIManager.instance.CloseUI(base.gameObject); + } +} diff --git a/GameCode/TowerUnlockCard.cs b/GameCode/TowerUnlockCard.cs new file mode 100644 index 0000000..0f14ed3 --- /dev/null +++ b/GameCode/TowerUnlockCard.cs @@ -0,0 +1,16 @@ +using UnityEngine; + +public class TowerUnlockCard : UpgradeCard +{ + [SerializeField] + private GameObject towerUIObject; + + [SerializeField] + private bool isTower = true; + + public override void Upgrade() + { + base.Upgrade(); + TowerUnlockManager.instance.UnlockTower(towerUIObject, isTower); + } +} diff --git a/GameCode/TowerUnlockManager.cs b/GameCode/TowerUnlockManager.cs new file mode 100644 index 0000000..d96b9d5 --- /dev/null +++ b/GameCode/TowerUnlockManager.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using UnityEngine; + +public class TowerUnlockManager : MonoBehaviour +{ + public static TowerUnlockManager instance; + + [SerializeField] + private List<GameObject> unlockedTowers = new List<GameObject>(); + + [SerializeField] + private List<GameObject> unlockedBuildings = new List<GameObject>(); + + private void Awake() + { + instance = this; + } + + private void Start() + { + DisplayButtons(); + } + + public void UnlockTower(GameObject towerUIObject, bool isTower) + { + towerUIObject.SetActive(value: true); + if (isTower) + { + unlockedTowers.Add(towerUIObject); + } + else + { + unlockedBuildings.Add(towerUIObject); + } + DisplayButtons(); + } + + private void DisplayButtons() + { + int num = 0; + int num2 = ((unlockedBuildings.Count > 0) ? 1 : 0); + foreach (GameObject unlockedTower in unlockedTowers) + { + unlockedTower.transform.localPosition = new Vector3(num * 100 - unlockedTowers.Count * 50 + 50, 100 * num2, 0f); + num++; + } + num = 0; + foreach (GameObject unlockedBuilding in unlockedBuildings) + { + unlockedBuilding.transform.localPosition = new Vector3(num * 100 - unlockedBuildings.Count * 50 + 50, 0f, 0f); + num++; + } + } +} diff --git a/GameCode/TowerUpgradeCard.cs b/GameCode/TowerUpgradeCard.cs new file mode 100644 index 0000000..c37da5e --- /dev/null +++ b/GameCode/TowerUpgradeCard.cs @@ -0,0 +1,117 @@ +using UnityEngine; + +public class TowerUpgradeCard : UpgradeCard +{ + [SerializeField] + private TowerType towerType; + + [SerializeField] + private float range; + + [SerializeField] + private int damage; + + [SerializeField] + private int healthDmg; + + [SerializeField] + private int armorDmg; + + [SerializeField] + private int shieldDmg; + + [SerializeField] + private float slowPercent; + + [SerializeField] + private float bleedPercent; + + [SerializeField] + private float burnPercent; + + [SerializeField] + private float poisonPercent; + + [SerializeField] + private float blast; + + [SerializeField] + private float critChance; + + [SerializeField] + private float critChanceLevelMultiplier; + + [SerializeField] + private float stunChance; + + [SerializeField] + private float manaConsumptionAddition; + + [SerializeField] + private float obeliskTimeOnTargetMultiplier; + + public override void Upgrade() + { + if (range != 0f) + { + TowerManager.instance.AddBonusRange(towerType, range); + } + if (damage != 0) + { + TowerManager.instance.AddBonusBaseDamage(towerType, damage); + } + if (healthDmg != 0) + { + TowerManager.instance.AddBonusHealthDamage(towerType, healthDmg); + } + if (armorDmg != 0) + { + TowerManager.instance.AddBonusArmorDamage(towerType, armorDmg); + } + if (shieldDmg != 0) + { + TowerManager.instance.AddBonusShieldDamage(towerType, shieldDmg); + } + if (slowPercent != 0f) + { + TowerManager.instance.AddBonusSlow(towerType, slowPercent); + } + if (bleedPercent != 0f) + { + TowerManager.instance.AddBonusBleed(towerType, bleedPercent); + } + if (burnPercent != 0f) + { + TowerManager.instance.AddBonusBurn(towerType, burnPercent); + } + if (poisonPercent != 0f) + { + TowerManager.instance.AddBonusPoison(towerType, poisonPercent); + } + if (blast != 0f) + { + TowerManager.instance.AddBonusBlast(towerType, blast); + } + if (critChance != 0f) + { + TowerManager.instance.AddCritChance(towerType, critChance); + } + if (critChanceLevelMultiplier != 0f) + { + TowerManager.instance.AddCritChanceLevelMultiplier(towerType, critChanceLevelMultiplier); + } + if (stunChance != 0f) + { + TowerManager.instance.AddStunChance(towerType, stunChance); + } + if (manaConsumptionAddition != 0f) + { + TowerManager.instance.AddManaConsumption(towerType, manaConsumptionAddition); + } + if (obeliskTimeOnTargetMultiplier != 0f) + { + TowerManager.instance.obeliskTimeOnTargetMultiplier += obeliskTimeOnTargetMultiplier; + } + base.Upgrade(); + } +} diff --git a/GameCode/TreasureChest.cs b/GameCode/TreasureChest.cs new file mode 100644 index 0000000..cf18502 --- /dev/null +++ b/GameCode/TreasureChest.cs @@ -0,0 +1,26 @@ +using UnityEngine; + +public class TreasureChest : MonoBehaviour, IBuildable +{ + [SerializeField] + private GameObject uiObject; + + public int numberOfDrops = 1; + + private void Start() + { + } + + public void SpawnUI() + { + Object.Instantiate(uiObject, base.transform.position, Quaternion.identity).GetComponent<TreasureUI>().myChest = base.gameObject; + } + + public void Demolish() + { + } + + public void SetStats() + { + } +} diff --git a/GameCode/TreasureUI.cs b/GameCode/TreasureUI.cs new file mode 100644 index 0000000..c0e297f --- /dev/null +++ b/GameCode/TreasureUI.cs @@ -0,0 +1,30 @@ +using UnityEngine; + +public class TreasureUI : MonoBehaviour +{ + public GameObject myChest; + + private int cardDraw = 2; + + private void Start() + { + UIManager.instance.SetNewUI(base.gameObject); + cardDraw = 2 + PlayerPrefs.GetInt("TreasureDraw1", 0); + } + + public void Open() + { + SFXManager.instance.PlaySound(Sound.CritBig, myChest.transform.position); + for (int i = 0; i < myChest.GetComponent<TreasureChest>().numberOfDrops; i++) + { + CardManager.instance.DrawCards(cardDraw); + } + Die(); + } + + public void Die() + { + Object.Destroy(myChest); + UIManager.instance.CloseUI(base.gameObject); + } +} diff --git a/GameCode/UICameraController.cs b/GameCode/UICameraController.cs new file mode 100644 index 0000000..c309492 --- /dev/null +++ b/GameCode/UICameraController.cs @@ -0,0 +1,67 @@ +using UnityEngine; + +public class UICameraController : MonoBehaviour +{ + [SerializeField] + private float cameraSpeed = 10f; + + [SerializeField] + private float cameraZoom = 1f; + + private Vector3 oldPos; + + private void Start() + { + } + + private void Update() + { + UpdateMovement(); + UpdateZoom(); + } + + public void ResetPosition() + { + base.transform.localPosition = Vector3.zero; + cameraZoom = 1f; + base.transform.localScale = Vector3.one * cameraZoom; + } + + private Vector3 ViewPointToPixels(Vector3 view) + { + return new Vector3(view.x * (float)Camera.main.scaledPixelWidth, view.y * (float)Camera.main.scaledPixelHeight, 0f); + } + + private void UpdateMovement() + { + if (Input.GetMouseButtonDown(1)) + { + oldPos = ViewPointToPixels(Camera.main.ScreenToViewportPoint(Input.mousePosition)); + } + if (Input.GetMouseButton(1)) + { + Vector3 vector = ViewPointToPixels(Camera.main.ScreenToViewportPoint(Input.mousePosition)); + Vector3 translation = vector - oldPos; + translation.z = 0f; + base.transform.Translate(translation); + oldPos = vector; + } + else + { + Vector3 vector2 = new Vector3(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"), 0f); + if (vector2.sqrMagnitude > 0.1f) + { + base.transform.Translate(-vector2.normalized * Time.deltaTime * cameraSpeed * (6f / (5f + cameraZoom))); + } + } + } + + private void UpdateZoom() + { + float num = cameraZoom; + cameraZoom = Mathf.Clamp(cameraZoom + Input.mouseScrollDelta.y / 10f, 0.5f, 2f); + base.transform.localScale = Vector3.one * cameraZoom; + base.transform.localPosition *= cameraZoom / num; + base.transform.localPosition += new Vector3(0f, 0.5f * (float)Camera.main.scaledPixelHeight * (cameraZoom - num), 0f); + } +} diff --git a/GameCode/UIManager.cs b/GameCode/UIManager.cs new file mode 100644 index 0000000..2a7081f --- /dev/null +++ b/GameCode/UIManager.cs @@ -0,0 +1,47 @@ +using UnityEngine; + +public class UIManager : MonoBehaviour +{ + public static UIManager instance; + + [SerializeField] + private LayerMask clickableMask; + + private GameObject currentUI; + + private void Awake() + { + instance = this; + } + + public void SetNewUI(GameObject newUI) + { + if (currentUI != null) + { + Object.Destroy(currentUI); + } + currentUI = newUI; + } + + public void CloseUI(GameObject oldUI) + { + currentUI = null; + Object.Destroy(oldUI); + } + + private void Update() + { + if (Input.GetKeyDown(KeyCode.Escape) && currentUI != null) + { + CloseUI(currentUI); + } + if (!BuildingManager.instance.buildMode && Input.GetMouseButtonDown(0) && Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out var hitInfo, 2000f, clickableMask, QueryTriggerInteraction.Collide)) + { + hitInfo.collider.GetComponent<IBuildable>()?.SpawnUI(); + } + if (Input.GetMouseButtonDown(1)) + { + CloseUI(currentUI); + } + } +} diff --git a/GameCode/UniBonusUI.cs b/GameCode/UniBonusUI.cs new file mode 100644 index 0000000..8d29a9b --- /dev/null +++ b/GameCode/UniBonusUI.cs @@ -0,0 +1,46 @@ +using UnityEngine; +using UnityEngine.UI; + +public class UniBonusUI : MonoBehaviour +{ + public static UniBonusUI instance; + + [SerializeField] + private GameObject uniUI; + + [SerializeField] + private Text uniUIText; + + private int healthTotal; + + private int armorTotal; + + private int shieldTotal; + + private void Awake() + { + instance = this; + } + + public void UniBonus(int health, int armor, int shield) + { + healthTotal += health; + armorTotal += armor; + shieldTotal += shield; + uniUI.SetActive(value: true); + string text = ""; + if (healthTotal > 0) + { + text = text + "+" + healthTotal + "HD"; + } + if (armorTotal > 0) + { + text = text + "\n+" + armorTotal + "AD"; + } + if (shieldTotal > 0) + { + text = text + "\n+" + shieldTotal + "SD"; + } + uniUIText.text = text; + } +} diff --git a/GameCode/University.cs b/GameCode/University.cs new file mode 100644 index 0000000..5115f50 --- /dev/null +++ b/GameCode/University.cs @@ -0,0 +1,150 @@ +using UnityEngine; + +public class University : MonoBehaviour, IBuildable +{ + [SerializeField] + private GameObject UIObject; + + [SerializeField] + private GameObject mainUIObject; + + public int goldBackOnDemolish; + + [SerializeField] + private LayerMask layermask; + + private bool active; + + public int healthPercent { get; private set; } + + public int armorPercent { get; private set; } + + public int shieldPercent { get; private set; } + + public int healthGained { get; private set; } + + public int armorGained { get; private set; } + + public int shieldGained { get; private set; } + + private void Start() + { + SpawnManager.instance.universities.Add(this); + DetectShrines(); + } + + public void SetStats() + { + } + + public void Research() + { + if (active) + { + if (Random.Range(0f, 100f) <= (float)(healthPercent + GameManager.instance.universityBonus)) + { + healthGained++; + TowerManager.instance.AddBonusHealthDamage(TowerType.Global, 1); + UniBonusUI.instance.UniBonus(1, 0, 0); + DamageNumber component = ObjectPool.instance.SpawnObject(ObjectPool.ObjectType.DamageNumber, base.transform.position, Quaternion.identity).GetComponent<DamageNumber>(); + component.SetText("New Discoveries!", "Grey", 1f); + component.SetHoldTime(2f); + AchievementManager.instance.NewDiscoveriesAchievement(); + } + if (Random.Range(0f, 100f) <= (float)(armorPercent + GameManager.instance.universityBonus)) + { + armorGained++; + UniBonusUI.instance.UniBonus(0, 1, 0); + TowerManager.instance.AddBonusArmorDamage(TowerType.Global, 1); + DamageNumber component2 = ObjectPool.instance.SpawnObject(ObjectPool.ObjectType.DamageNumber, base.transform.position, Quaternion.identity).GetComponent<DamageNumber>(); + component2.SetText("New Discoveries!", "Grey", 1f); + component2.SetHoldTime(2f); + AchievementManager.instance.NewDiscoveriesAchievement(); + } + if (Random.Range(0f, 100f) <= (float)(shieldPercent + GameManager.instance.universityBonus)) + { + shieldGained++; + UniBonusUI.instance.UniBonus(0, 0, 1); + TowerManager.instance.AddBonusShieldDamage(TowerType.Global, 1); + DamageNumber component3 = ObjectPool.instance.SpawnObject(ObjectPool.ObjectType.DamageNumber, base.transform.position, Quaternion.identity).GetComponent<DamageNumber>(); + component3.SetText("New Discoveries!", "Grey", 1f); + component3.SetHoldTime(2f); + AchievementManager.instance.NewDiscoveriesAchievement(); + } + } + } + + public void FundHealthStudies() + { + int num = (healthPercent + armorPercent + shieldPercent + 1) * 20; + if (ResourceManager.instance.CheckMoney(num)) + { + healthPercent++; + ResourceManager.instance.Spend(num); + AchievementManager.instance.FundResearchAchievement(num); + } + } + + public void FundArmorStudies() + { + int num = (healthPercent + armorPercent + shieldPercent + 1) * 20; + if (ResourceManager.instance.CheckMoney(num)) + { + armorPercent++; + ResourceManager.instance.Spend(num); + AchievementManager.instance.FundResearchAchievement(num); + } + } + + public void FundShieldStudies() + { + int num = (healthPercent + armorPercent + shieldPercent + 1) * 20; + if (ResourceManager.instance.CheckMoney(num)) + { + shieldPercent++; + ResourceManager.instance.Spend(num); + AchievementManager.instance.FundResearchAchievement(num); + } + } + + public void SpawnUI() + { + if (!active) + { + Object.Instantiate(UIObject, base.transform.position, Quaternion.identity).GetComponent<SimpleUI>().SetDemolishable(base.gameObject, goldBackOnDemolish); + } + else + { + Object.Instantiate(mainUIObject, base.transform.position, Quaternion.identity).GetComponent<UniversityUI>().SetStats(this); + } + } + + public void Demolish() + { + SpawnManager.instance.universities.Remove(this); + } + + private void DetectShrines() + { + if ((!Physics.Raycast(base.transform.position + new Vector3(1f, 1f, 0f), -base.transform.up, out var hitInfo, 1f, layermask, QueryTriggerInteraction.Ignore) || !Rotate(hitInfo)) && (!Physics.Raycast(base.transform.position + new Vector3(-1f, 1f, 0f), -base.transform.up, out hitInfo, 1f, layermask, QueryTriggerInteraction.Ignore) || !Rotate(hitInfo)) && (!Physics.Raycast(base.transform.position + new Vector3(0f, 1f, 1f), -base.transform.up, out hitInfo, 1f, layermask, QueryTriggerInteraction.Ignore) || !Rotate(hitInfo)) && Physics.Raycast(base.transform.position + new Vector3(0f, 1f, -1f), -base.transform.up, out hitInfo, 1f, layermask, QueryTriggerInteraction.Ignore)) + { + Rotate(hitInfo); + } + } + + private bool Rotate(RaycastHit hit) + { + if (hit.collider.GetComponent<Shrine>() == null) + { + return false; + } + if ((double)(hit.collider.transform.position.y - base.transform.position.y) > 0.001) + { + return false; + } + base.transform.LookAt(hit.collider.transform.position, Vector3.up); + active = true; + SetStats(); + return true; + } +} diff --git a/GameCode/UniversityUI.cs b/GameCode/UniversityUI.cs new file mode 100644 index 0000000..bf7b8bd --- /dev/null +++ b/GameCode/UniversityUI.cs @@ -0,0 +1,135 @@ +using UnityEngine; +using UnityEngine.UI; + +public class UniversityUI : MonoBehaviour +{ + private University myUniversity; + + [SerializeField] + private Text healthCostText; + + [SerializeField] + private Text armorCostText; + + [SerializeField] + private Text shieldCostText; + + [SerializeField] + private Text healthDiscoveresText; + + [SerializeField] + private Text armorDiscoveriesText; + + [SerializeField] + private Text shieldDiscoveriesText; + + [SerializeField] + private Text healthBonusText; + + [SerializeField] + private Text armorBonusText; + + [SerializeField] + private Text shieldBonusText; + + [SerializeField] + private Text healthPercentageText; + + [SerializeField] + private Text armorPercentageText; + + [SerializeField] + private Text shieldPercentageText; + + [SerializeField] + private Image healthPercentageImg; + + [SerializeField] + private Image armorPercentageImg; + + [SerializeField] + private Image shieldPercentageImg; + + [SerializeField] + private Text demolishText; + + private void Start() + { + UIManager.instance.SetNewUI(base.gameObject); + if (demolishText != null) + { + demolishText.text = "Demolish (" + myUniversity.goldBackOnDemolish + "g)"; + } + } + + public void SetStats(University myUni) + { + myUniversity = myUni; + int num = (myUniversity.healthPercent + myUniversity.armorPercent + myUniversity.shieldPercent + 1) * 20; + healthCostText.text = num.ToString(); + armorCostText.text = num.ToString(); + shieldCostText.text = num.ToString(); + healthDiscoveresText.text = "Health Studies: " + myUniversity.healthGained; + armorDiscoveriesText.text = "Armor Studies: " + myUniversity.armorGained; + shieldDiscoveriesText.text = "Magic Studies: " + myUniversity.shieldGained; + healthBonusText.text = "Global Health Damage: +" + myUniversity.healthGained; + armorBonusText.text = "Global Armor Damage: +" + myUniversity.armorGained; + shieldBonusText.text = "Global Shield Damage: +" + myUniversity.shieldGained; + healthPercentageText.text = "Health Studies: " + (myUniversity.healthPercent + GameManager.instance.universityBonus) + "%"; + armorPercentageText.text = "Armor Studies: " + (myUniversity.armorPercent + GameManager.instance.universityBonus) + "%"; + shieldPercentageText.text = "Magic Studies: " + (myUniversity.shieldPercent + GameManager.instance.universityBonus) + "%"; + healthPercentageImg.rectTransform.sizeDelta = new Vector2((float)(myUniversity.healthPercent + GameManager.instance.universityBonus) / 10f, 0.25f); + armorPercentageImg.rectTransform.sizeDelta = new Vector2((float)(myUniversity.armorPercent + GameManager.instance.universityBonus) / 10f, 0.25f); + shieldPercentageImg.rectTransform.sizeDelta = new Vector2((float)(myUniversity.shieldPercent + GameManager.instance.universityBonus) / 10f, 0.25f); + if (demolishText != null) + { + demolishText.text = "Demolish (" + myUniversity.goldBackOnDemolish + "g)"; + } + } + + private void Update() + { + if (Input.GetKeyDown(KeyCode.Alpha1) || Input.GetKeyDown(KeyCode.Keypad1)) + { + FundHealthResearch(); + } + if (Input.GetKeyDown(KeyCode.Alpha2) || Input.GetKeyDown(KeyCode.Keypad2)) + { + FundArmorResearch(); + } + if (Input.GetKeyDown(KeyCode.Alpha3) || Input.GetKeyDown(KeyCode.Keypad3)) + { + FundShieldResearch(); + } + } + + public void FundHealthResearch() + { + SFXManager.instance.ButtonClick(); + myUniversity.FundHealthStudies(); + SetStats(myUniversity); + } + + public void FundArmorResearch() + { + SFXManager.instance.ButtonClick(); + myUniversity.FundArmorStudies(); + SetStats(myUniversity); + } + + public void FundShieldResearch() + { + SFXManager.instance.ButtonClick(); + myUniversity.FundShieldStudies(); + SetStats(myUniversity); + } + + public void Demolish() + { + SFXManager.instance.ButtonClick(); + myUniversity.Demolish(); + Object.Destroy(myUniversity.gameObject); + ResourceManager.instance.AddMoney(myUniversity.goldBackOnDemolish); + UIManager.instance.CloseUI(base.gameObject); + } +} diff --git a/GameCode/UniversityUpgrade.cs b/GameCode/UniversityUpgrade.cs new file mode 100644 index 0000000..391c336 --- /dev/null +++ b/GameCode/UniversityUpgrade.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +public class UniversityUpgrade : UpgradeCard +{ + [SerializeField] + private int bonus = 1; + + public override void Upgrade() + { + base.Upgrade(); + GameManager.instance.universityBonus += bonus; + } +} diff --git a/GameCode/UpgradeButton.cs b/GameCode/UpgradeButton.cs new file mode 100644 index 0000000..271976b --- /dev/null +++ b/GameCode/UpgradeButton.cs @@ -0,0 +1,167 @@ +using System.Collections; +using UnityEngine; +using UnityEngine.UI; + +public class UpgradeButton : MonoBehaviour +{ + [SerializeField] + private string unlockString; + + [SerializeField] + public int xpCost; + + public int cardCountRequirement; + + [SerializeField] + private bool countsAsCardUnlock = true; + + [SerializeField] + private bool countAsDevelopment; + + [SerializeField] + private Sprite unlockedSprite; + + [SerializeField] + private bool checkAchievements; + + [SerializeField] + private GameObject priceTag; + + private GameObject currentPriceTag; + + private Image img; + + private Button btn; + + [SerializeField] + private UpgradeButton previous; + + [SerializeField] + private UpgradeButton[] next; + + public bool unlocked; + + private void Start() + { + img = GetComponent<Image>(); + btn = GetComponent<Button>(); + CheckUnlock(); + StartCoroutine(LateStart()); + } + + public void Unlock() + { + if (UpgradeManager.instance.xp >= xpCost) + { + SFXManager.instance.ButtonClick(); + UpgradeManager.instance.AddXP(-xpCost); + PlayerPrefs.SetInt(unlockString, 1); + if (checkAchievements) + { + AchievementManager.instance.CheckTowerUnlocks(); + } + UpgradeManager.instance.CountCard(countsAsCardUnlock); + UpgradeManager.instance.CountDevelopment(countAsDevelopment); + btn.enabled = false; + img.sprite = unlockedSprite; + unlocked = true; + UpdateTitleText(); + UpgradeButton[] array = next; + for (int i = 0; i < array.Length; i++) + { + array[i].CheckEnabled(); + } + } + } + + public void ResetUnlock() + { + PlayerPrefs.SetInt(unlockString, 0); + unlocked = false; + } + + private void CheckUnlock() + { + if (PlayerPrefs.GetInt(unlockString, 0) == 1) + { + btn.enabled = false; + img.sprite = unlockedSprite; + unlocked = true; + } + } + + public void CheckEnabled() + { + if (previous == null) + { + if (cardCountRequirement <= UpgradeManager.instance.unlockedCardCount) + { + btn.interactable = true; + } + else + { + btn.interactable = false; + } + UpdateTitleText(); + } + else + { + if (previous.unlocked && cardCountRequirement <= UpgradeManager.instance.unlockedCardCount) + { + btn.interactable = true; + } + else + { + btn.interactable = false; + } + UpdateTitleText(); + } + } + + private void UpdateTitleText() + { + if (!unlocked) + { + if (currentPriceTag == null) + { + currentPriceTag = Object.Instantiate(priceTag, base.transform); + currentPriceTag.transform.localPosition = new Vector3(-63.7f, 0f, 0f); + int num = cardCountRequirement - UpgradeManager.instance.unlockedCardCount; + if (num > 0) + { + currentPriceTag.GetComponent<RectTransform>().sizeDelta = new Vector2(75f, 50f); + currentPriceTag.GetComponentInChildren<Text>().text = " Unlock " + num + "\n more cards"; + } + else + { + currentPriceTag.GetComponent<RectTransform>().sizeDelta = new Vector2(50f, 25f); + currentPriceTag.GetComponentInChildren<Text>().text = xpCost + " xp"; + } + } + else + { + int num2 = cardCountRequirement - UpgradeManager.instance.unlockedCardCount; + if (num2 > 0) + { + currentPriceTag.GetComponent<RectTransform>().sizeDelta = new Vector2(75f, 50f); + currentPriceTag.GetComponentInChildren<Text>().text = " Unlock " + num2 + "\n more cards"; + } + else + { + currentPriceTag.GetComponent<RectTransform>().sizeDelta = new Vector2(50f, 25f); + currentPriceTag.GetComponentInChildren<Text>().text = xpCost + " xp"; + } + } + } + else if (currentPriceTag != null) + { + currentPriceTag.SetActive(value: false); + } + } + + private IEnumerator LateStart() + { + yield return new WaitForSeconds(0.1f); + CheckEnabled(); + } +} diff --git a/GameCode/UpgradeCard.cs b/GameCode/UpgradeCard.cs new file mode 100644 index 0000000..45b6ce8 --- /dev/null +++ b/GameCode/UpgradeCard.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using UnityEngine; + +public class UpgradeCard : MonoBehaviour +{ + [SerializeField] + private string unlockName; + + [SerializeField] + private bool unlockedByDefault; + + public bool unlocked; + + public string title; + + public Sprite image; + + public string description; + + public List<UpgradeCard> unlocks = new List<UpgradeCard>(); + + private void Awake() + { + if (unlockedByDefault || PlayerPrefs.GetInt(unlockName, 0) == 1) + { + unlocked = true; + } + else + { + unlocked = false; + } + } + + public virtual void Upgrade() + { + } +} diff --git a/GameCode/UpgradeManager.cs b/GameCode/UpgradeManager.cs new file mode 100644 index 0000000..685308e --- /dev/null +++ b/GameCode/UpgradeManager.cs @@ -0,0 +1,120 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +public class UpgradeManager : MonoBehaviour +{ + public static UpgradeManager instance; + + public int xp; + + public int prestige; + + [SerializeField] + private Text xpText; + + [SerializeField] + private GameObject prestigeDisplay; + + [SerializeField] + private Text prestigeText; + + public int unlockedCardCount; + + [SerializeField] + private UpgradeButton[] allButtons; + + [SerializeField] + private List<UpgradeButton> cardsWhichRequireCardCount = new List<UpgradeButton>(); + + private void Awake() + { + instance = this; + } + + private void Start() + { + allButtons = Object.FindObjectsOfType<UpgradeButton>(); + UpgradeButton[] array = allButtons; + foreach (UpgradeButton upgradeButton in array) + { + if (upgradeButton.cardCountRequirement > 0) + { + cardsWhichRequireCardCount.Add(upgradeButton); + } + } + unlockedCardCount = PlayerPrefs.GetInt("UnlockedCardCount", 0); + xp = PlayerPrefs.GetInt("XP", 0); + xpText.text = "XP: " + xp; + prestige = PlayerPrefs.GetInt("Prestige", 0); + if (prestige > 0) + { + prestigeDisplay.SetActive(value: true); + prestigeText.text = "Prestige: " + prestige; + } + } + + public void AddXP(int change) + { + xp += change; + PlayerPrefs.SetInt("XP", xp); + xpText.text = "XP: " + xp; + } + + public void ResetUpgrades() + { + int num = 0; + UpgradeButton[] array = allButtons; + foreach (UpgradeButton upgradeButton in array) + { + if (upgradeButton.enabled) + { + if (upgradeButton.unlocked) + { + num += upgradeButton.xpCost; + } + upgradeButton.ResetUnlock(); + } + } + num += xp / 2; + Debug.Log("Refunded xp: " + num); + PlayerPrefs.SetInt("Prestige", prestige + num / 1000); + xp = 0; + PlayerPrefs.SetInt("XP", 0); + PlayerPrefs.SetInt("UnlockedCardCount", 0); + PlayerPrefs.SetInt("Development", 0); + PlayerPrefs.SetInt("Record1", 0); + PlayerPrefs.SetInt("Record2", 0); + PlayerPrefs.SetInt("Record3", 0); + LevelLoader.instance.LoadLevel("MainMenu"); + } + + public void CountCard(bool countsAsCardUnlock) + { + if (countsAsCardUnlock) + { + unlockedCardCount++; + Debug.Log("Number of unlocked cards: " + unlockedCardCount); + PlayerPrefs.SetInt("UnlockedCardCount", unlockedCardCount); + CheckCardCount(); + } + } + + public void CountDevelopment(bool value) + { + if (value) + { + int @int = PlayerPrefs.GetInt("Development", 0); + PlayerPrefs.SetInt("Development", @int + 1); + Debug.Log("Development: " + (@int + 1)); + } + } + + public void CheckCardCount() + { + foreach (UpgradeButton item in cardsWhichRequireCardCount) + { + item.CheckEnabled(); + } + } +} diff --git a/GameCode/WalkAnimator.cs b/GameCode/WalkAnimator.cs new file mode 100644 index 0000000..4f2b997 --- /dev/null +++ b/GameCode/WalkAnimator.cs @@ -0,0 +1,55 @@ +using System; +using UnityEngine; + +public class WalkAnimator : MonoBehaviour +{ + private Pathfinder p; + + [SerializeField] + private Transform directionalTransform; + + [SerializeField] + private Transform rotationalOffsetTransform; + + [SerializeField] + private Transform artTransform; + + [SerializeField] + private float strideLength = 1f; + + [SerializeField] + private float strideHeight = 1f; + + [SerializeField] + private float sideAngles = 20f; + + [SerializeField] + private float strideVariationPercentage = 0.1f; + + private float step; + + private Vector3 preiviousPosition; + + private Vector3 direction; + + private void Start() + { + strideLength = UnityEngine.Random.Range(strideLength * (1f - strideVariationPercentage), strideLength * (1f + strideVariationPercentage)); + strideHeight = UnityEngine.Random.Range(strideHeight * (1f - strideVariationPercentage), strideHeight * (1f + strideVariationPercentage)); + p = GetComponent<Pathfinder>(); + preiviousPosition = base.transform.position; + } + + private void FixedUpdate() + { + direction = base.transform.position - preiviousPosition; + preiviousPosition = base.transform.position; + if (direction.sqrMagnitude != 0f) + { + directionalTransform.rotation = Quaternion.LookRotation(direction, Vector3.up); + } + step = (step + p.speed * Time.fixedDeltaTime / strideLength) % 2f; + artTransform.localPosition = strideHeight * Vector3.up * Mathf.Abs(Mathf.Cos(step * (float)Math.PI)); + artTransform.localEulerAngles = new Vector3(sideAngles * Mathf.Sin(step * (float)Math.PI), 0f, 0f); + } +} diff --git a/GameCode/Waypoint.cs b/GameCode/Waypoint.cs new file mode 100644 index 0000000..b250079 --- /dev/null +++ b/GameCode/Waypoint.cs @@ -0,0 +1,62 @@ +using System.Collections.Generic; +using UnityEngine; + +public class Waypoint : MonoBehaviour +{ + [SerializeField] + private Waypoint next; + + [SerializeField] + private List<Waypoint> previous = new List<Waypoint>(); + + public float distanceFromEnd; + + public bool trueDistance; + + private void Start() + { + UpdateDistance(); + } + + public Waypoint GetNextWaypoint() + { + if (next != null) + { + return next; + } + return this; + } + + public void SetNextWaypoint(Waypoint newNext) + { + next = newNext; + } + + public void AddPreviousWaypoint(Waypoint previousWaypoint) + { + previous.Add(previousWaypoint); + } + + public Waypoint[] GetPreviousWaypoints() + { + return previous.ToArray(); + } + + public void UpdateDistance() + { + if (next == null) + { + trueDistance = true; + return; + } + if (!next.trueDistance) + { + next.UpdateDistance(); + } + if (!trueDistance) + { + distanceFromEnd = next.distanceFromEnd + Vector3.Magnitude(next.transform.position - base.transform.position); + trueDistance = true; + } + } +} |