chenxin
2020-12-03 0bc89b87a59c3f1f394a54c0901868084463cf28
Assets/Scripts/TowerDefense/Towers/Tower.cs
@@ -1,5 +1,6 @@
using KTGMGemClient;
using System.Collections;
using UnityEngine.UI;
using DG.Tweening;
using KTGMGemClient;
using System;
using ActionGameFramework.Health;
using Core.Utilities;
@@ -8,6 +9,7 @@
using TowerDefense.Towers.Placement;
using TowerDefense.UI.HUD;
using UnityEngine;
using TowerDefense.Agents;
namespace TowerDefense.Towers
{
@@ -27,6 +29,7 @@
        NULL,
        BULLET,   // 子弹塔
        ENERGY,   // 能量充能.
        FREEZE, // 水精灵充能
        END
    }
@@ -35,9 +38,6 @@
    /// </summary>
    public class Tower : Targetable
    {
        public readonly float INSCENE_TU_DAMAGE = 30f;
        public static readonly int MAX_LEVEL = 4;
        /// <summary>
        /// A generalised name common to a levels
        /// </summary>
@@ -54,45 +54,31 @@
        public EFeatureTower towerFeature = EFeatureTower.NULL;
        /// <summary>
        /// 当前塔防对应的MonsterMaterial,自身和对方显示不同的Mat.
        /// </summary>
        public Material materialMonsterSelf;
        public Material materialMonsterOppo;
        /// <summary>
        /// 当前塔防对应的攻击和等待Mat.
        /// </summary>
        public Material materialTowerAttackSelf;
        public Material materialTowerWaitSelf;
        public Material materialTowerAttackOppo;
        public Material materialTowerWaitOppo;
        /// <summary>
        /// 0 空状态  1 等待状态  2 攻击状态.
        /// </summary>
        protected int curActionState = 0;
        /// <summary>
        /// 塔防对应的充能状态.
        /// </summary>
        public ETowerFuntion eTowerFuntion = ETowerFuntion.NULL;
        [HideInInspector]
        public BulletUICtl bulletCtl = null;
        [HideInInspector]
        public EnergyUICtl energyCtl = null;
        [HideInInspector]
        public FreezeBreath FreezeBreathCtrl = null;
        /// <summary>
        /// The tower levels associated with this tower
        /// </summary>
        public TowerLevel[] levels;
        [SerializeField]
        private TowerLevel towerLevel;
        public TowerLevel CurrentTowerLevel { get; private set; }
        /// <summary>
        /// 当前塔防对应的AttributeID.
        /// 精灵id,一一对应 elf_info表中的id,唯一的区分每一种精灵塔
        /// </summary>
        public int attributeId;
        /// <summary>
        /// 当前的Tower在游戏内UI界面上用到的Image数据,再以后应该是直接在表格内配置才合适
        /// </summary>
        public Sprite uiImage;
        public int ElfId;
        /// <summary>
        /// The physics mask the tower searches on
@@ -107,16 +93,6 @@
        protected bool m_bInAttackMode = false;
        /// <summary>
        /// 精英怪和Boss双倍伤害.
        /// </summary>
        public bool bDoubleHitElit = false;
        /// <summary>
        /// Reference to the data of the current level
        /// </summary>
        public TowerLevel currentTowerLevel { get; protected set; }
        /// <summary>
        /// 攻击增加
        /// </summary>
        public float attackRise { get; set; }
@@ -126,64 +102,70 @@
        /// </summary>
        protected int progressOffset = 0;
        public int FreezeBreathProgressOffset { get; set; }
        public bool PlayWaveLineFlash { get; set; } = true;
        private bool isBondage;
        /// <summary>
        /// 塔防数据的局内升级
        /// 是否是泡泡禁锢状态
        /// </summary>
        public int inSceneTowerLevel
        /// <value></value>
        public bool IsBondage
        {
            get; set;
            get { return isBondage; }
            set
            {
                isBondage = value;
                CanAttack = !value;
            }
        }
        /// <summary>
        /// 禁锢时间
        /// </summary>
        public float BondageTime { get; set; }
        /// <summary>
        /// 禁锢警告时间
        /// </summary>
        /// <value></value>
        public float BondageWarningTime { get; set; }
        /// <summary>
        /// 泡泡禁锢期间,点击一次减少的时间
        /// </summary>
        public float BondageClickDecreaseTime { get; set; } = 1f;
        /// <summary>
        /// 是否是木属性蓄力状态
        /// </summary>
        public bool IsWoodCharge { get; set; }
        /// <summary>
        /// 木属性蓄力瞄准的目标
        /// </summary>
        public Agent WoodAimAgent;
        public int uiProOffset
        {
            get { return this.progressOffset; }
            set { this.progressOffset = value; }
            get { return progressOffset; }
            set { progressOffset = value; }
        }
        /// <summary>
        /// Gets whether the tower can level up anymore
        /// </summary>
        public bool isAtMaxLevel
        public bool IsMaxLevel
        {
            get { return currentLevel == levels.Length - 1; }
            get { return currentLevel == ElfUpgradeData.MaxTowerLevel - 1; }
        }
        public void setTowerState(bool attack)
        {
            if (!materialTowerAttackSelf) return;
            if (opponentSide)
            {
                if (attack && (this.curActionState != 2))
                {
                    currentTowerLevel.SetTowerMonsterMat(materialTowerAttackOppo, true);
                    this.curActionState = 2;
                }
                if ((!attack) && (this.curActionState != 1))
                {
                    currentTowerLevel.SetTowerMonsterMat(materialTowerWaitOppo, false);
                    this.curActionState = 1;
                }
            }
            else
            {
                if (attack && (this.curActionState != 2))
                {
                    currentTowerLevel.SetTowerMonsterMat(materialTowerAttackSelf, true);
                    this.curActionState = 2;
                }
                if ((!attack) && (this.curActionState != 1))
                {
                    currentTowerLevel.SetTowerMonsterMat(materialTowerWaitSelf, false);
                    this.curActionState = 1;
                }
            }
        }
        /// <summary>
        /// 是否可以攻击
        /// </summary>
        public bool CanAttack = true;
        /// <summary>
        /// 是否是对手塔防
@@ -191,12 +173,153 @@
        public bool opponentSide { get; set; }
        /// <summary>
        /// 禁锢警告
        /// </summary>
        protected GameObject bondageWarningObj;
        /// <summary>
        /// 禁锢泡泡
        /// </summary>
        protected GameObject bondageObj;
        private GameObject tapObj;
        /// <summary>
        /// 精灵被禁锢时点击次数
        /// </summary>
        public int BondageTapCount { get; private set; }
        private void Update()
        {
            HandleBondageBubble();
        }
        /// <summary>
        /// 处理禁锢泡泡技能
        /// </summary>
        private void HandleBondageBubble()
        {
            if (!IsBondage) return;
            if (BondageWarningTime > 0)
            {
                BondageWarningTime -= Time.deltaTime;
                if (BondageWarningTime <= 0)
                {
                    Destroy(bondageWarningObj);
                    bondageWarningObj = null;
                    StartBondage();
                    ShowTapPrompt();
                }
            }
            else
            {
                BondageTime -= Time.deltaTime;
                if (BondageTime <= 0)
                {
                    IsBondage = false;
                    Destroy(bondageObj);
                    bondageObj = null;
                    BondageBubbleBomb();
                }
            }
        }
        /// <summary>
        /// 展示连续点击提示
        /// </summary>
        private void ShowTapPrompt()
        {
            GameObject prefab = Resources.Load<GameObject>("Prefabs/Endless/BondageBubbleTap");
            tapObj = Instantiate(prefab);
            tapObj.transform.SetParent(GameObject.Find("MainUI/CoinPanel").transform, false);
            Vector3 worldPos = TowerPlacementGridEndless.instance.GetGridWorldPos(gridPosition.x, gridPosition.y);
            Camera camera = GameObject.Find("SceneCamera3D").GetComponent<Camera>();
            Vector3 screenPos = camera.WorldToScreenPoint(worldPos);
            screenPos.z = 0;
            screenPos.x += 100;
            screenPos.y += 85;
            tapObj.transform.position = screenPos;
            tapObj.transform.localScale = new Vector3(0.6f, 0.6f, 0.6f);
            DOTween.To(() => tapObj.transform.localScale, (Vector3 v) => tapObj.transform.localScale = v, new Vector3(1f, 1f, 1f), 0.3f).SetEase(Ease.OutBack);
        }
        private void HideTapPrompt()
        {
            if (tapObj != null)
            {
                Image img = tapObj.GetComponent<Image>();
                DOTween.To(() => img.color, (Color v) => img.color = v, new Color(1f, 1f, 1f, 0f), 0.3f).OnComplete(() =>
                {
                    if (tapObj != null)
                    {
                        Destroy(tapObj);
                        tapObj = null;
                    }
                });
            }
        }
        public void OnPressed()
        {
            if (!IsBondage || BondageWarningTime > 0) return;
            ++BondageTapCount;
            if (BondageTapCount == 1)
                HideTapPrompt();
            BondageTime -= BondageClickDecreaseTime;
        }
        /// <summary>
        /// 禁锢泡泡爆炸
        /// </summary>
        private void BondageBubbleBomb()
        {
            GameObject prefab = Resources.Load<GameObject>("Prefabs/Endless/BondageBubbleBomb");
            GameObject obj = Instantiate(prefab);
            obj.transform.SetParent(TowerPlacementGridEndless.instance.GridContainer.transform, false);
            obj.transform.position = TowerPlacementGridEndless.instance.GetGridWorldPos(gridPosition.x, gridPosition.y);
            obj.transform.GetChild(0).GetComponent<ParticleSystem>().Play();
            Destroy(obj, 1.2f);
        }
        /// <summary>
        /// 开始泡泡禁锢
        /// </summary>
        private void StartBondage()
        {
            BondageTapCount = 0;
            GameObject prefab = Resources.Load<GameObject>("Prefabs/Endless/BondageBubble");
            bondageObj = Instantiate(prefab);
            bondageObj.transform.SetParent(TowerPlacementGridEndless.instance.GridContainer.transform, false);
            bondageObj.transform.position = TowerPlacementGridEndless.instance.GetGridWorldPos(gridPosition.x, gridPosition.y);
            bondageObj.transform.GetChild(0).GetComponent<ParticleSystem>().Play();
        }
        /// <summary>
        /// 禁锢警告
        /// </summary>
        /// <param name="tower"></param>
        public void BondageWarning()
        {
            GameObject prefab = Resources.Load<GameObject>("Prefabs/Endless/BondageBubbleWarning");
            bondageWarningObj = Instantiate(prefab);
            bondageWarningObj.transform.SetParent(TowerPlacementGridEndless.instance.GridContainer.transform, false);
            bondageWarningObj.transform.position = TowerPlacementGridEndless.instance.GetGridWorldPos(gridPosition.x, gridPosition.y);
            bondageWarningObj.transform.GetChild(0).GetComponent<ParticleSystem>().Play();
        }
        /// <summary>
        /// 播放充能状态特效.
        /// </summary>
        /// <param name="play"></param>
        public void PlayEnergyEffect(bool play, bool isClose = true)
        {
            if (this.energyCtl && isClose)
            if (energyCtl && isClose)
                energyCtl.gameObject.SetActive(!play);
            else if (!isClose)
            {
@@ -215,35 +338,52 @@
        }
        /// <summary>
        /// 播放水精灵充能满了特效
        /// </summary>
        /// <param name="play"></param>
        /// <param name="isClose"></param>
        public void PlayFreezeBreathEffect(bool play, bool isClose = true)
        {
            if (FreezeBreathCtrl && isClose)
                FreezeBreathCtrl.gameObject.SetActive(!play);
            if (!opponentSide)
            {
                if (EndlessGameUI.instanceExists)
                    ((TowerPlacementGridEndless)EndlessGameUI.instance.selfTowerPlaceArea).PlayFreezeBreathEffect(gridPosition.x, gridPosition.y, play);
            }
        }
        /// <summary>
        /// 当前是否处于攻击模式
        /// </summary>
        public bool bInAttackMode
        {
            get { return this.m_bInAttackMode; }
            get { return m_bInAttackMode; }
            // 设置是否处于攻击状态:
            set
            {
                m_bInAttackMode = value;
                currentTowerLevel.SetAffectorState(m_bInAttackMode, gridPosition.x);
                currentTowerLevel.SetAttackState(value);
                CurrentTowerLevel.SetAffectorState(m_bInAttackMode, gridPosition.x);
                CurrentTowerLevel.SetAttackState(value);
                if (value)
                {
                    if (opponentSide)
                    {
                        OpponentMgr.instance.SetTowerAttID(gridPosition.x, attributeId, this.currentLevel);
                        OpponentMgr.instance.SetTowerAttID(gridPosition.x, ElfId, currentLevel);
                    }
                    else
                    {
                        if (LevelManager.instanceExists)
                        {
                            LevelManager.instance.SetTowerAttID(gridPosition.x, attributeId, this.currentLevel);
                            LevelManager.instance.SetTowerAttID(gridPosition.x, ElfId, currentLevel);
                            WaveLineSelMgr.instance.attackTowerFixed(gridPosition.x);
                        }
                        else if (EndlessLevelManager.instanceExists)
                        {
                            EndlessLevelManager.instance.SetTowerAttID(gridPosition.x, attributeId, this.currentLevel);
                            EndlessLevelManager.instance.SetTowerAttID(gridPosition.x, ElfId, currentLevel);
                            EndlessWaveLineManager.instance.AttackTowerFixed(gridPosition.x, PlayWaveLineFlash);
                        }
                    }
@@ -260,12 +400,12 @@
        public void DisableTowerUICtrl()
        {
            // 根据是否是子弹塔防来决定是否显示相应的界面
            BulletUICtl buc = this.placementArea.GetBulletUICtl(gridPosition.x, gridPosition.y);
            BulletUICtl buc = placementArea.GetBulletUICtl(gridPosition.x, gridPosition.y);
            if ((this.eTowerFuntion == ETowerFuntion.BULLET) && (buc != null))
            if ((eTowerFuntion == ETowerFuntion.BULLET) && (buc != null))
            {
                buc.gameObject.SetActive(false);
                this.bulletCtl = null;
                bulletCtl = null;
            }
            EnergyUICtl euc = placementArea.GetEnergyUICtl(gridPosition.x, gridPosition.y);
@@ -273,23 +413,33 @@
            {
                // 设置数据
                euc.gameObject.SetActive(false);
                this.energyCtl = null;
                energyCtl = null;
            }
            return;
            FreezeBreath ctrl = placementArea.GetFreezeBreath(gridPosition.x, gridPosition.y);
            if (eTowerFuntion == ETowerFuntion.FREEZE && ctrl != null)
            {
                ctrl.gameObject.SetActive(false);
                ctrl = null;
            }
        }
        public int GetTowerUICtrlProgress()
        {
            // 根据是否是子弹塔防来决定是否显示相应的界面
            BulletUICtl buc = this.placementArea.GetBulletUICtl(gridPosition.x, gridPosition.y);
            BulletUICtl buc = placementArea.GetBulletUICtl(gridPosition.x, gridPosition.y);
            if ((this.eTowerFuntion == ETowerFuntion.BULLET) && (buc != null))
            if ((eTowerFuntion == ETowerFuntion.BULLET) && (buc != null))
                return buc.GetCtlProgress();
            EnergyUICtl euc = placementArea.GetEnergyUICtl(gridPosition.x, gridPosition.y);
            if ((eTowerFuntion == ETowerFuntion.ENERGY) && (euc != null))
                return euc.GetCtlProgress();
            FreezeBreath ctrl = placementArea.GetFreezeBreath(gridPosition.x, gridPosition.y);
            if (eTowerFuntion == ETowerFuntion.FREEZE && ctrl != null)
                return ctrl.CurrentProgress;
            return 0;
        }
@@ -297,12 +447,13 @@
        public void SetTowerUICtlProcess(int pro)
        {
            // 根据是否是子弹塔防来决定是否显示相应的界面
            BulletUICtl buc = this.placementArea.GetBulletUICtl(gridPosition.x, gridPosition.y);
            BulletUICtl buc = placementArea.GetBulletUICtl(gridPosition.x, gridPosition.y);
            if ((this.eTowerFuntion == ETowerFuntion.BULLET) && (buc != null))
            if ((eTowerFuntion == ETowerFuntion.BULLET) && (buc != null))
            {
                buc.SetCtlProcess(pro);
                progressOffset = pro;
                return;
            }
            EnergyUICtl euc = placementArea.GetEnergyUICtl(gridPosition.x, gridPosition.y);
@@ -312,74 +463,102 @@
                progressOffset = pro;
                if (progressOffset == 10)
                    progressOffset = 0;
                return;
            }
            FreezeBreath ctrl = placementArea.GetFreezeBreath(gridPosition.x, gridPosition.y);
            return;
            if (eTowerFuntion == ETowerFuntion.FREEZE && ctrl != null)
            {
                ctrl.SetCtrlProgress(pro);
                FreezeBreathProgressOffset = pro;
                if (FreezeBreathProgressOffset == 10)
                    FreezeBreathProgressOffset = 0;
            }
        }
        /// <summary>
        /// 充能技能相关的代码开关。包括子弹充能和时间充能
        /// </summary>
        protected void OnTowerUICtrl()
        {
            HandleBulletUICtrl();
            HandleEnergyUICtrl();
            HandleFreezeBreathCtrl();
        }
        private void HandleBulletUICtrl()
        {
            // 根据是否是子弹塔防来决定是否显示相应的界面
            BulletUICtl buc = this.placementArea.GetBulletUICtl(gridPosition.x, gridPosition.y);
            BulletUICtl buc = placementArea.GetBulletUICtl(gridPosition.x, gridPosition.y);
            if (buc == null) return;
            if ((this.eTowerFuntion == ETowerFuntion.BULLET) && (buc != null))
            if ((eTowerFuntion == ETowerFuntion.BULLET) && (buc != null))
            {
                // 设置数据
                buc.gameObject.SetActive(true);
                this.bulletCtl = buc;
                buc.resetToMaxBullet();
                bulletCtl = buc;
                buc.ResetToMaxBullet();
            }
            else
            {
                // 清空数据
                buc.gameObject.SetActive(false);
                this.bulletCtl = null;
                bulletCtl = null;
            }
        }
        private void HandleEnergyUICtrl()
        {
            // 根据是否是能量充能来决定是否显示相应的界面.
            EnergyUICtl euc = placementArea.GetEnergyUICtl(gridPosition.x, gridPosition.y);
            if ((eTowerFuntion == ETowerFuntion.ENERGY) && (euc != null))
            {
                // 设置数据
                euc.gameObject.SetActive(true);
                this.energyCtl = euc;
                energyCtl = euc;
                euc.SetEnergyProgress(0);
            }
            else
            {
                // 清空数据
                euc.gameObject.SetActive(false);
                this.energyCtl = null;
                energyCtl = null;
            }
        }
        /// <summary>
        /// This function is called when the object becomes enabled and active.
        /// </summary>
        void OnEnable()
        private void HandleFreezeBreathCtrl()
        {
            FreezeBreath ctrl = placementArea.GetFreezeBreath(gridPosition.x, gridPosition.y);
            // if (bulletCtl != null)
            // {
            //     Debug.Log("打开了bulletCtl");
            //     bulletCtl.gameObject.SetActive(true);
            // }
            if (eTowerFuntion == ETowerFuntion.FREEZE && ctrl != null)
            {
                ctrl.gameObject.SetActive(true);
                FreezeBreathCtrl = ctrl;
                ctrl.SetProgress(0);
            }
            else
            {
                ctrl.gameObject.SetActive(false);
                FreezeBreathCtrl = null;
            }
        }
        public void CheckCtrl()
        {
            if (bulletCtl != null)
            {
                bulletCtl.gameObject.SetActive(true);
            }
            // if (energyCtl != null)
            // {
            //     Debug.Log("打开了energyCtl");
            //     energyCtl.gameObject.SetActive(true);
            // }
            if (energyCtl != null)
            {
                energyCtl.gameObject.SetActive(true);
            }
            if (FreezeBreathCtrl != null)
                FreezeBreathCtrl.gameObject.SetActive(true);
        }
        /// <summary>
@@ -396,44 +575,9 @@
            {
                energyCtl.gameObject.SetActive(false);
            }
        }
        /// <summary>
        /// 初始化当前塔防的局内升级,lvl从1开始.
        /// </summary>
        /// <param name="lvl"></param>
        public void initInSceneTowerLevel(int lvl)
        {
            inSceneTowerLevel = lvl;
            if (lvl <= 1)
            {
                ResetInSceneTowerLevel();
                return;
            }
            // 设置攻击数据的加强,暂时是测试数据,后面需要读取表格数据处理:
            float damageAdd = 0;
            // float damageAdd = (inSceneTowerLevel - 1) * this.INSCENE_TU_DAMAGE;
            for (int ti = 0; ti < this.levels.Length; ti++)
            {
                if (levels[ti].levelDamager)
                {
                    levels[ti].levelDamager.doubleHit = bDoubleHitElit;
                    levels[ti].levelDamager.inSceneUpGradeDamage = damageAdd;
                }
            }
        }
        protected void ResetInSceneTowerLevel()
        {
            for (int ti = 0; ti < this.levels.Length; ti++)
            {
                if (levels[ti].levelDamager)
                {
                    levels[ti].levelDamager.inSceneUpGradeDamage = 0;
                    levels[ti].levelDamager.doubleHit = bDoubleHitElit;
                }
            }
            return;
            if (FreezeBreathCtrl != null)
                FreezeBreathCtrl.gameObject.SetActive(false);
        }
        /// <summary>
@@ -441,25 +585,10 @@
        /// </summary>
        public void upGradeInSceneTL()
        {
            inSceneTowerLevel++;
            // 设置攻击数据的加强,暂时是测试数据,后面需要读取表格数据处理:
            float damageAdd = inSceneTowerLevel * this.INSCENE_TU_DAMAGE;
            for (int ti = 0; ti < this.levels.Length; ti++)
            {
                if (levels[ti].levelDamager)
                {
                    levels[ti].levelDamager.inSceneUpGradeDamage = damageAdd;
                    levels[ti].levelDamager.towerName = name;
                    levels[ti].levelDamager.bSet = true;
                }
            }
            Debug.Log("Upgrade Tower name is:" + name);
            // 播放相关的特效
            currentTowerLevel.PlayUpGradeEffect();
            CurrentTowerLevel.PlayUpGradeEffect();
        }
        /// <summary>
@@ -467,7 +596,7 @@
        /// </summary>
        public TowerPlacementGhost towerGhostPrefab
        {
            get { return levels[currentLevel].towerGhostPrefab; }
            get { return towerLevel.towerGhostPrefab; }
        }
        /// <summary>
@@ -481,14 +610,6 @@
        public IPlacementArea placementArea { get; private set; }
        /// <summary>
        /// The purchase cost of the tower
        /// </summary>
        public int purchaseCost
        {
            get { return levels[0].cost; }
        }
        /// <summary>
        /// The event that fires off when a player deletes a tower
        /// </summary>
        public Action towerDeleted;
@@ -497,16 +618,6 @@
        /// The event that fires off when a tower has been destroyed
        /// </summary>
        public Action towerDestroyed;
        /// <summary>
        /// 放置到目标位置
        /// </summary>
        /// <param name="destination"></param>
        public virtual void SetToDestination(IntVector2 destination)
        {
            gridPosition = destination;
            transform.position = placementArea.GridToWorld(destination, dimensions);
        }
        /// <summary>
        /// Provide the tower with data to initialize with
@@ -526,53 +637,18 @@
            }
            SetLevel(lvl);
            if (LevelManager.instanceExists)
            {
                LevelManager.instance.levelStateChanged += OnLevelStateChanged;
            }
            else if (EndlessLevelManager.instanceExists)
                EndlessLevelManager.instance.LevelStateChanged += OnLevelStateChanged;
            // 查找Targetter:
            Targetter target = this.GetComponentInChildren<Targetter>();
            Targetter target = GetComponentInChildren<Targetter>();
            if (target)
            {
                target.bOpponent = this.opponentSide;
            }
                target.bOpponent = opponentSide;
            else
                Debug.Log("在当前的Tower中找不到Targetter.");
            //
            // 初始化当前的局内Tower等级数据
            this.initInSceneTowerLevel(SceneTowerLvl.getInSceneTowerLvl(this.towerName));
            StartCoroutine(ResetScale());
        }
        IEnumerator ResetScale()
        {
            yield return new WaitForSeconds(0.2f);
            if (gridPosition.y > 1)
            {
                currentTowerLevel.ResetScale();
            }
            else
            {
                currentTowerLevel.NormalScale();
            }
        }
        /// <summary>
        /// Provides information on the cost to upgrade
        /// </summary>
        /// <returns>Returns -1 if the towers is already at max level, other returns the cost to upgrade</returns>
        public int GetCostForNextLevel()
        {
            if (isAtMaxLevel)
            {
                return -1;
            }
            return levels[currentLevel + 1].cost;
        }
        /// <summary>
@@ -583,11 +659,11 @@
        {
            if (vis)
            {
                this.gameObject.SetActive(true);
                gameObject.SetActive(true);
            }
            else
            {
                this.gameObject.SetActive(false);
                gameObject.SetActive(false);
            }
        }
@@ -601,42 +677,11 @@
        }
        /// <summary>
        /// Provides the value recived for selling this tower
        /// </summary>
        /// <returns>A sell value of the tower</returns>
        public int GetSellLevel()
        {
            return GetSellLevel(currentLevel);
        }
        /// <summary>
        /// Provides the value recived for selling this tower of a particular level
        /// </summary>
        /// <param name="level">Level of tower</param>
        /// <returns>A sell value of the tower</returns>
        public int GetSellLevel(int level)
        {
            // sell for full price if waves haven't started yet
            if (LevelManager.instanceExists && LevelManager.instance.levelState == LevelState.Building
                || EndlessLevelManager.instanceExists && EndlessLevelManager.instance.EndlessLeveltate == LevelState.Building)
            {
                int cost = 0;
                for (int i = 0; i <= level; i++)
                {
                    cost += levels[i].cost;
                }
                return cost;
            }
            return levels[currentLevel].sell;
        }
        /// <summary>
        /// Used to (try to) upgrade the tower data
        /// </summary>
        public virtual bool UpgradeTower()
        {
            if (isAtMaxLevel)
            if (IsMaxLevel)
            {
                return false;
            }
@@ -671,10 +716,8 @@
        /// </returns>
        public virtual bool UpgradeTowerToLevel(int level)
        {
            if (level < 0 || isAtMaxLevel || level >= levels.Length)
            {
                return false;
            }
            if (level < 0 || IsMaxLevel || level >= ElfUpgradeData.MaxTowerLevel) return false;
            SetLevel(level);
            return true;
        }
@@ -690,9 +733,6 @@
        public override void Remove()
        {
            base.Remove();
            // 清空局内升级数据:
            ResetInSceneTowerLevel();
            attackRise = 0.0f;
            placementArea.Clear(gridPosition, dimensions);
            Destroy(gameObject);
@@ -714,28 +754,19 @@
        /// <summary>
        /// Cache and update oftenly used data
        /// </summary>
        public void SetLevel(int level)
        protected void SetLevel(int level)
        {
            if (level < 0 || level >= levels.Length)
            {
                return;
            }
            if (level < 0 || level >= ElfUpgradeData.MaxTowerLevel) return;
            currentLevel = level;
            if (currentTowerLevel != null)
            {
                Destroy(currentTowerLevel.gameObject);
            }
            // instantiate the visual representation
            currentTowerLevel = Instantiate(levels[currentLevel], transform);
            if (CurrentTowerLevel != null)
                Destroy(CurrentTowerLevel.gameObject);
            // initialize TowerLevel
            currentTowerLevel.Initialize(this, enemyLayerMask, configuration.alignmentProvider);
            CurrentTowerLevel = Instantiate(towerLevel, transform);
            CurrentTowerLevel.Initialize(this, enemyLayerMask, configuration.alignmentProvider);
            CurrentTowerLevel.SetShowLevel(level + 1);
            // health data
            ScaleHealth();
            //
            // disable affectors
            LevelState levelState = LevelState.Intro;
            if (LevelManager.instanceExists)
@@ -744,26 +775,7 @@
                levelState = EndlessLevelManager.instance.EndlessLeveltate;
            bool initialise = levelState == LevelState.AllEnemiesSpawned || levelState == LevelState.SpawningEnemies;
            initialise = false;
            currentTowerLevel.SetAffectorState(initialise, gridPosition.x);
        }
        /// <summary>
        /// Scales the health based on the previous health
        /// Requires override when the rules for scaling health on upgrade changes
        /// </summary>
        protected virtual void ScaleHealth()
        {
            configuration.SetMaxHealth(currentTowerLevel.maxHealth);
            if (currentLevel == 0)
            {
                configuration.SetHealth(currentTowerLevel.maxHealth);
            }
            else
            {
                int currentHealth = Mathf.FloorToInt(configuration.normalisedHealth * currentTowerLevel.maxHealth);
                configuration.SetHealth(currentHealth);
            }
            CurrentTowerLevel.SetAffectorState(initialise, gridPosition.x);
        }
        /// <summary>
@@ -773,8 +785,7 @@
        {
            bool initialise = current == LevelState.AllEnemiesSpawned || current == LevelState.SpawningEnemies;
            initialise = false;
            //currentTowerLevel.SetAffectorState(initialise);
            currentTowerLevel.SetAffectorState(bInAttackMode, gridPosition.x);
            CurrentTowerLevel.SetAffectorState(bInAttackMode, gridPosition.x);
        }
    }
}