summaryrefslogtreecommitdiff
path: root/Assembly_CSharp/_Tower/Tower.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Assembly_CSharp/_Tower/Tower.cs')
-rw-r--r--Assembly_CSharp/_Tower/Tower.cs509
1 files changed, 509 insertions, 0 deletions
diff --git a/Assembly_CSharp/_Tower/Tower.cs b/Assembly_CSharp/_Tower/Tower.cs
new file mode 100644
index 0000000..4098bd6
--- /dev/null
+++ b/Assembly_CSharp/_Tower/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);
+ }
+}