summaryrefslogtreecommitdiff
path: root/Assembly_CSharp/GamePlay
diff options
context:
space:
mode:
authorchai <215380520@qq.com>2023-11-26 23:52:30 +0800
committerchai <215380520@qq.com>2023-11-26 23:52:30 +0800
commit626381f061cde0c78564f6336e3131835cf20a5b (patch)
treed9991d6eda6ae5d7649ac91ecaa3b4dc833cd4c3 /Assembly_CSharp/GamePlay
parent0e63c4a2c6dec8dfa260501fb7d73750261ea7b7 (diff)
* move
Diffstat (limited to 'Assembly_CSharp/GamePlay')
-rw-r--r--Assembly_CSharp/GamePlay/BattleCry.cs84
-rw-r--r--Assembly_CSharp/GamePlay/BiPlane.cs161
-rw-r--r--Assembly_CSharp/GamePlay/CameraController.cs96
-rw-r--r--Assembly_CSharp/GamePlay/Dropper.cs126
-rw-r--r--Assembly_CSharp/GamePlay/Encampment.cs26
-rw-r--r--Assembly_CSharp/GamePlay/Enemy.cs669
-rw-r--r--Assembly_CSharp/GamePlay/Explosion.cs27
-rw-r--r--Assembly_CSharp/GamePlay/FlameThrower.cs68
-rw-r--r--Assembly_CSharp/GamePlay/GameManager.cs476
-rw-r--r--Assembly_CSharp/GamePlay/HauntedHouseUpgrade.cs8
-rw-r--r--Assembly_CSharp/GamePlay/IDamageable.cs4
-rw-r--r--Assembly_CSharp/GamePlay/IncomeGenerator.cs39
-rw-r--r--Assembly_CSharp/GamePlay/Lookout.cs97
-rw-r--r--Assembly_CSharp/GamePlay/MonsterManager.cs43
-rw-r--r--Assembly_CSharp/GamePlay/Morter.cs39
-rw-r--r--Assembly_CSharp/GamePlay/MorterShell.cs81
-rw-r--r--Assembly_CSharp/GamePlay/Obelisk.cs99
-rw-r--r--Assembly_CSharp/GamePlay/ParticleBeam.cs19
-rw-r--r--Assembly_CSharp/GamePlay/Pathfinder.cs91
-rw-r--r--Assembly_CSharp/GamePlay/Projectile.cs141
-rw-r--r--Assembly_CSharp/GamePlay/ProjectileFX.cs47
-rw-r--r--Assembly_CSharp/GamePlay/RadarTower.cs71
-rw-r--r--Assembly_CSharp/GamePlay/Sawblade.cs87
-rw-r--r--Assembly_CSharp/GamePlay/SlowRotate.cs12
-rw-r--r--Assembly_CSharp/GamePlay/SnowFlake.cs23
-rw-r--r--Assembly_CSharp/GamePlay/SpawnManager.cs495
-rw-r--r--Assembly_CSharp/GamePlay/SpawnableObject.cs54
-rw-r--r--Assembly_CSharp/GamePlay/TerrainTile.cs87
-rw-r--r--Assembly_CSharp/GamePlay/TileManager.cs236
-rw-r--r--Assembly_CSharp/GamePlay/TileSpawnLocation.cs27
-rw-r--r--Assembly_CSharp/GamePlay/Tower.cs509
-rw-r--r--Assembly_CSharp/GamePlay/TowerFlyweight.cs279
-rw-r--r--Assembly_CSharp/GamePlay/TowerManager.cs1386
-rw-r--r--Assembly_CSharp/GamePlay/TowerType.cs18
-rw-r--r--Assembly_CSharp/GamePlay/TowerUnlockManager.cs54
-rw-r--r--Assembly_CSharp/GamePlay/UpgradeManager.cs120
-rw-r--r--Assembly_CSharp/GamePlay/WalkAnimator.cs55
-rw-r--r--Assembly_CSharp/GamePlay/Waypoint.cs62
38 files changed, 6016 insertions, 0 deletions
diff --git a/Assembly_CSharp/GamePlay/BattleCry.cs b/Assembly_CSharp/GamePlay/BattleCry.cs
new file mode 100644
index 0000000..f76a756
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/BiPlane.cs b/Assembly_CSharp/GamePlay/BiPlane.cs
new file mode 100644
index 0000000..bcf32e5
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/CameraController.cs b/Assembly_CSharp/GamePlay/CameraController.cs
new file mode 100644
index 0000000..2b91184
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/Dropper.cs b/Assembly_CSharp/GamePlay/Dropper.cs
new file mode 100644
index 0000000..0dc7a10
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/Encampment.cs b/Assembly_CSharp/GamePlay/Encampment.cs
new file mode 100644
index 0000000..eaa8ab7
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/Enemy.cs b/Assembly_CSharp/GamePlay/Enemy.cs
new file mode 100644
index 0000000..2e7ce7d
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/Explosion.cs b/Assembly_CSharp/GamePlay/Explosion.cs
new file mode 100644
index 0000000..a01aa17
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/FlameThrower.cs b/Assembly_CSharp/GamePlay/FlameThrower.cs
new file mode 100644
index 0000000..d415d88
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/GameManager.cs b/Assembly_CSharp/GamePlay/GameManager.cs
new file mode 100644
index 0000000..bfa59e1
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/HauntedHouseUpgrade.cs b/Assembly_CSharp/GamePlay/HauntedHouseUpgrade.cs
new file mode 100644
index 0000000..47d4c8a
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/HauntedHouseUpgrade.cs
@@ -0,0 +1,8 @@
+public class HauntedHouseUpgrade : UpgradeCard
+{
+ public override void Upgrade()
+ {
+ base.Upgrade();
+ GameManager.instance.hauntedHouseEfficiency++;
+ }
+}
diff --git a/Assembly_CSharp/GamePlay/IDamageable.cs b/Assembly_CSharp/GamePlay/IDamageable.cs
new file mode 100644
index 0000000..d010ef5
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/IncomeGenerator.cs b/Assembly_CSharp/GamePlay/IncomeGenerator.cs
new file mode 100644
index 0000000..9afd8f5
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/Lookout.cs b/Assembly_CSharp/GamePlay/Lookout.cs
new file mode 100644
index 0000000..3abd55b
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/MonsterManager.cs b/Assembly_CSharp/GamePlay/MonsterManager.cs
new file mode 100644
index 0000000..40a7a35
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/Morter.cs b/Assembly_CSharp/GamePlay/Morter.cs
new file mode 100644
index 0000000..2170da3
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/MorterShell.cs b/Assembly_CSharp/GamePlay/MorterShell.cs
new file mode 100644
index 0000000..ce93441
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/Obelisk.cs b/Assembly_CSharp/GamePlay/Obelisk.cs
new file mode 100644
index 0000000..549f3b4
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/ParticleBeam.cs b/Assembly_CSharp/GamePlay/ParticleBeam.cs
new file mode 100644
index 0000000..6a7bf2a
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/Pathfinder.cs b/Assembly_CSharp/GamePlay/Pathfinder.cs
new file mode 100644
index 0000000..5426574
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/Projectile.cs b/Assembly_CSharp/GamePlay/Projectile.cs
new file mode 100644
index 0000000..3c15fe4
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/ProjectileFX.cs b/Assembly_CSharp/GamePlay/ProjectileFX.cs
new file mode 100644
index 0000000..df82c3d
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/RadarTower.cs b/Assembly_CSharp/GamePlay/RadarTower.cs
new file mode 100644
index 0000000..e0d8d1d
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/Sawblade.cs b/Assembly_CSharp/GamePlay/Sawblade.cs
new file mode 100644
index 0000000..19038df
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/SlowRotate.cs b/Assembly_CSharp/GamePlay/SlowRotate.cs
new file mode 100644
index 0000000..7a0306a
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/SnowFlake.cs b/Assembly_CSharp/GamePlay/SnowFlake.cs
new file mode 100644
index 0000000..238b829
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/SpawnManager.cs b/Assembly_CSharp/GamePlay/SpawnManager.cs
new file mode 100644
index 0000000..4e66c04
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/SpawnableObject.cs b/Assembly_CSharp/GamePlay/SpawnableObject.cs
new file mode 100644
index 0000000..fd7b169
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/TerrainTile.cs b/Assembly_CSharp/GamePlay/TerrainTile.cs
new file mode 100644
index 0000000..932ff37
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/TileManager.cs b/Assembly_CSharp/GamePlay/TileManager.cs
new file mode 100644
index 0000000..592d861
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/TileSpawnLocation.cs b/Assembly_CSharp/GamePlay/TileSpawnLocation.cs
new file mode 100644
index 0000000..e1575b1
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/Tower.cs b/Assembly_CSharp/GamePlay/Tower.cs
new file mode 100644
index 0000000..4098bd6
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/TowerFlyweight.cs b/Assembly_CSharp/GamePlay/TowerFlyweight.cs
new file mode 100644
index 0000000..b63f8b4
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/TowerManager.cs b/Assembly_CSharp/GamePlay/TowerManager.cs
new file mode 100644
index 0000000..abdca52
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/TowerType.cs b/Assembly_CSharp/GamePlay/TowerType.cs
new file mode 100644
index 0000000..9bbc242
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/TowerUnlockManager.cs b/Assembly_CSharp/GamePlay/TowerUnlockManager.cs
new file mode 100644
index 0000000..d96b9d5
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/UpgradeManager.cs b/Assembly_CSharp/GamePlay/UpgradeManager.cs
new file mode 100644
index 0000000..685308e
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/WalkAnimator.cs b/Assembly_CSharp/GamePlay/WalkAnimator.cs
new file mode 100644
index 0000000..4f2b997
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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/Assembly_CSharp/GamePlay/Waypoint.cs b/Assembly_CSharp/GamePlay/Waypoint.cs
new file mode 100644
index 0000000..b250079
--- /dev/null
+++ b/Assembly_CSharp/GamePlay/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;
+ }
+ }
+}