Assets/Scripts/TowerDefense/Affectors/AttackAffector.cs
@@ -3,410 +3,762 @@
using ActionGameFramework.Audio;
using ActionGameFramework.Health;
using Core.Health;
using TowerDefense.Agents;
using TowerDefense.Targetting;
using TowerDefense.Towers;
using TowerDefense.Towers.Projectiles;
using UnityEngine;
using KTGMGemClient;
using TowerDefense.Agents;
using TowerDefense.Level;
namespace TowerDefense.Affectors
{
   /// <summary>
   /// The common effect for handling firing projectiles to attack
   ///
   /// Requires an ILauncher but it is not automatically added
   /// Add an ILauncher implementation to this GameObject before you add this script
   /// </summary>
   [RequireComponent(typeof(ILauncher))]
   public class AttackAffector : Affector, ITowerRadiusProvider
   {
      /// <summary>
      /// The projectile used to attack
      /// </summary>
      public GameObject projectile;
    /// <summary>
    /// The common effect for handling firing projectiles to attack
    ///
    /// Requires an ILauncher but it is not automatically added
    /// Add an ILauncher implementation to this GameObject before you add this script
    /// </summary>
    [RequireComponent(typeof(ILauncher))]
    public class AttackAffector : Affector, ITowerRadiusProvider
    {
        /// <summary>
        /// The projectile used to attack
        /// </summary>
        public GameObject projectile;
      //
      protected GameObject projectile1;
      protected GameObject projectile2;
        /// <summary>
        /// 木塔最后一击是特殊攻击,需要替换projectile
        /// </summary>
        public GameObject woodProjectile_SP;
        //
        protected GameObject projectile1;
        protected GameObject projectile2;
      /// <summary>
      /// The list of points to launch the projectiles from
      /// </summary>
      public Transform[] projectilePoints;
        /// <summary>
        /// The list of points to launch the projectiles from
        /// </summary>
        public Transform[] projectilePoints;
      /// <summary>
      /// The reference to the center point where the tower will search from
      /// </summary>
      public Transform epicenter;
        /// <summary>
        /// The reference to the center point where the tower will search from
        /// </summary>
        public Transform epicenter;
      /// <summary>
      /// Configuration for when the tower does splash damage
      /// </summary>
      public bool isMultiAttack;
        /// <summary>
        /// Configuration for when the tower does splash damage
        /// </summary>
        public bool isMultiAttack;
      /// <summary>
      /// 如果是多目标攻击,最多攻击目标
      /// </summary>
      public int maxAttackNum = 1;
        /// <summary>
        /// 如果是多目标攻击,最多攻击目标
        /// </summary>
        public int maxAttackNum = 1;
        /// <summary>
        /// The fire rate in fires-per-second
        /// </summary>
        public float fireRate;
        [SerializeField]
        private float projectileFireRate = 1;
      /// <summary>
      /// 是否木属性数据
      /// </summary>
      public bool bWoodAffector = false;
      /// <summary>
      /// The audio source to play when firing
      /// </summary>
      public RandomAudioSource randomAudioSource;
      /// <summary>
      /// Gets the targetter
      /// </summary>
      public Targetter towerTargetter;
      /// <summary>
      /// Color of effect radius visualization
      /// </summary>
      public Color radiusEffectColor;
      /// <summary>
      /// Search condition
      /// </summary>
      public Filter searchCondition;
      /// <summary>
      /// Fire condition
      /// </summary>
      public Filter fireCondition;
      /// <summary>
      /// The reference to the attached launcher
      /// </summary>
      protected ILauncher m_Launcher;
      /// <summary>
      /// The time before firing is possible
      /// </summary>
      protected float m_FireTimer;
      /// <summary>
      /// Reference to the current tracked enemy
      /// </summary>
      protected Targetable m_TrackingEnemy;
      /// <summary>
      /// 处理装弹时间.
      /// </summary>
      protected float fillBulletTime = 0.0f;
        public float FireRate
        {
            get { return 1 / GetFireDuration(); }
        }
        /// <summary>
        /// 充能时间
        /// 是否木属性数据
        /// </summary>
        public bool bWoodAffector = false;
        /// <summary>
        /// The audio source to play when firing
        /// </summary>
        public RandomAudioSource randomAudioSource;
        /// <summary>
        /// Gets the targetter
        /// </summary>
        public Targetter towerTargetter;
        /// <summary>
        /// Color of effect radius visualization
        /// </summary>
        public Color radiusEffectColor;
        /// <summary>
        /// Search condition
        /// </summary>
        public Filter searchCondition;
        /// <summary>
        /// Fire condition
        /// </summary>
        public Filter fireCondition;
        /// <summary>
        /// The reference to the attached launcher
        /// </summary>
        protected ILauncher m_Launcher;
        /// <summary>
        /// The time before firing is possible
        /// </summary>
        protected float m_FireTimer;
        protected float freezeBreathTimer;
        /// <summary>
        /// Reference to the current tracked enemy
        /// </summary>
        protected Targetable m_TrackingEnemy;
        public TowerLevel towerLevel;
        /// <summary>
        /// 处理装弹时间.
        /// </summary>
        protected float fillBulletTime = 0.0f;
        /// <summary>
        /// 火精灵充能时间
        /// </summary>
        protected float energyCalTime = 0;
      protected float fInEnergy = 0;
      protected float fBackupTimer = 0.0f;
      /// <summary>
      /// Gets the search rate from the targetter
      /// </summary>
      public float searchRate
      {
         get { return towerTargetter.searchRate; }
         set { towerTargetter.searchRate = value; }
      }
      /// <summary>
      /// Gets the targetable
      /// </summary>
      public Targetable trackingEnemy
      {
         get { return m_TrackingEnemy; }
      }
        protected float fInEnergy = 0;
      /// <summary>
      /// Gets or sets the attack radius
      /// </summary>
      public float effectRadius
      {
         get { return towerTargetter.effectRadius; }
      }
        protected float fBackupTimer = 0.0f;
      public Color effectColor
      {
         get { return radiusEffectColor; }
      }
        /// <summary>
        /// 水精灵的充能时间
        /// </summary>
        protected float freezeBreathCallTime = 0;
      public Targetter targetter
      {
         get { return towerTargetter; }
      }
        protected float inFreezeBreath;
      /// <summary>
      /// Initializes the attack affector
      /// </summary>
      public override void Initialize(IAlignmentProvider affectorAlignment)
      {
         Initialize(affectorAlignment, -1);
      }
        protected float freezeBreathBackTimer = 0;
      /// <summary>
      /// 返回可能存在的Targetter.
      /// </summary>
      /// <returns></returns>
      public override TowerDefense.Targetting.Targetter GetTargetter()
      {
         return targetter;
      }
        private int towerAttributeId;
      /// <summary>
      /// Initialises the  attack affector with a layer mask
      /// </summary>
      public override void Initialize(IAlignmentProvider affectorAlignment, LayerMask mask)
      {
         base.Initialize(affectorAlignment, mask);
         SetUpTimers();
        /// <summary>
        /// 火精灵技能固定攻击倍速
        /// </summary>
        /// <value></value>
        protected float fireSpeed { get; set; } = 5f;
         towerTargetter.ResetTargetter();
         towerTargetter.alignment = affectorAlignment;
         towerTargetter.acquiredTarget += OnAcquiredTarget;
         towerTargetter.lostTarget += OnLostTarget;
      }
        /// <summary>
        /// 木属性精灵蓄力时间
        /// </summary>
        protected float woodChargeTime { get; set; } = 1.5f;
      void OnDestroy()
      {
         towerTargetter.acquiredTarget -= OnAcquiredTarget;
         towerTargetter.lostTarget -= OnLostTarget;
      }
        protected float woodRemainChargeTime { get; set; }
      void OnLostTarget()
      {
         m_TrackingEnemy = null;
      }
        /// <summary>
        /// 蓄力特效时间
        /// </summary>
        protected float woodChargeEffectTime { get; set; }
      void OnAcquiredTarget(Targetable acquiredTarget)
      {
         m_TrackingEnemy = acquiredTarget;
      }
        /// <summary>
        /// 木属性精灵蓄力特效
        /// </summary>
        public GameObject WoodChargeEffect;
      public Damager damagerProjectile
      {
         get { return projectile == null ? null : projectile.GetComponent<Damager>(); }
      }
        private GameObject woodChargeEffect;
      public Damager damagerProjectile1
      {
         get { return projectile == null ? null : projectile.GetComponent<Damager>(); }
      }
        public Transform WoodChargeTransform;
      public Damager damagerProjectile2
      {
         get { return projectile == null ? null : projectile.GetComponent<Damager>(); }
      }
        /// <summary>
        /// 木属性正在瞄准的Agent
        /// </summary>
        protected Agent woodAimAgent;
      /// <summary>
      /// Returns the total projectile damage
      /// </summary>
      public float GetProjectileDamage()
      {
         var splash = projectile.GetComponent<SplashDamager>();
         float splashDamage = splash != null ? splash.damage : 0;
         return damagerProjectile.finalDamage + splashDamage;
      }
      /// <summary>
      /// Initialise the RepeatingTimer
      /// </summary>
      protected virtual void SetUpTimers()
      {
         m_FireTimer = 1 / fireRate;
         m_Launcher = GetComponent<ILauncher>();
      }
      protected void updateTowerSkillData()
        /// <summary>
        /// 火精灵攻击最终攻击倍速,里面计算了buff增加的倍速
        /// </summary>
        /// <value></value>
        public float finalFireSpeed
        {
         //
         // 预留出来装填子弹的时间.
         if (fillBulletTime > 0)
         {
            fillBulletTime -= Time.deltaTime;
            if (fillBulletTime <= 0.3f)
            {
               if (towerPtr && towerPtr.bulletCtl)
                  towerPtr.bulletCtl.resetToMaxBullet();
            }
            if (fillBulletTime <= 0)
            {
               fillBulletTime = 0;
            }
         }
         //
         // 充能时间的处理
         if( towerPtr && towerPtr.energyCtl)
            get
            {
            if( this.fInEnergy <= 0)
                FireRateAdd fireRateAdd = (FireRateAdd)EndlessBuffManager.instance.GetBuffInstanceByType(EndlessBuffEffectType.FireRateAdd);
                float rateAdd = 0;
                if (fireRateAdd != null)
                    rateAdd = fireRateAdd.GetFireSpeedAdd(towerPtr.attributeId);
                return rateAdd > 1 ? rateAdd : fireSpeed;
            }
        }
        /// <summary>
        /// Gets the search rate from the targetter
        /// </summary>
        public float searchRate
        {
            get { return towerTargetter.searchRate; }
            set { towerTargetter.searchRate = value; }
        }
        /// <summary>
        /// Gets the targetable
        /// </summary>
        public Targetable trackingEnemy
        {
            get { return m_TrackingEnemy; }
        }
        /// <summary>
        /// Gets or sets the attack radius
        /// </summary>
        public float effectRadius
        {
            get { return towerTargetter.effectRadius; }
        }
        public Color effectColor
        {
            get { return radiusEffectColor; }
        }
        public Targetter targetter
        {
            get { return towerTargetter; }
        }
        /// <summary>
        /// Initializes the attack affector
        /// </summary>
        public override void Initialize(IAlignmentProvider affectorAlignment)
        {
            Initialize(affectorAlignment, -1);
        }
        /// <summary>
        /// 返回可能存在的Targetter.
        /// </summary>
        /// <returns></returns>
        public override TowerDefense.Targetting.Targetter GetTargetter()
        {
            return targetter;
        }
        /// <summary>
        /// Initialises the  attack affector with a layer mask
        /// </summary>
        public override void Initialize(IAlignmentProvider affectorAlignment, LayerMask mask)
        {
            base.Initialize(affectorAlignment, mask);
            SetUpTimers();
            towerTargetter.ResetTargetter();
            towerTargetter.alignment = affectorAlignment;
            towerTargetter.acquiredTarget += OnAcquiredTarget;
            // towerTargetter.lostTarget += OnLostTarget;
            GetAudioEnum();
            myTower = transform.parent.GetComponent<TowerLevel>();
        }
        private AudioEnum audioEnum;//当前音乐的种类
        void GetAudioEnum()
        {
            if (transform.parent.name.StartsWith("GrowUpTower"))
            {
                //火元素
                audioEnum = AudioEnum.FireTAttack;
            }
            else if (transform.parent.name.StartsWith("BlinkTower"))
            {
                //木元素
                audioEnum = AudioEnum.WoodTAttack;
            }
            else if (transform.parent.name.StartsWith("CopyCatTower"))
            {
                //水元素
                audioEnum = AudioEnum.WaterTAttack;
            }
        }
        void OnDestroy()
        {
            towerTargetter.acquiredTarget -= OnAcquiredTarget;
            // towerTargetter.lostTarget -= OnLostTarget;
        }
        void OnAcquiredTarget(Targetable acquiredTarget)
        {
            // m_TrackingEnemy = acquiredTarget;
        }
        public Damager damagerProjectile
        {
            get { return projectile == null ? null : projectile.GetComponent<Damager>(); }
        }
        public Damager damagerProjectile1
        {
            get { return projectile == null ? null : projectile.GetComponent<Damager>(); }
        }
        public Damager damagerProjectile2
        {
            get { return projectile == null ? null : projectile.GetComponent<Damager>(); }
        }
        /// <summary>
        /// Returns the total projectile damage
        /// </summary>
        public float GetProjectileDamage()
        {
            var splash = projectile.GetComponent<SplashDamager>();
            float splashDamage = splash != null ? splash.damage : 0;
            return damagerProjectile.finalDamage + splashDamage;
        }
        /// <summary>
        /// Initialise the RepeatingTimer
        /// </summary>
        protected virtual void SetUpTimers()
        {
            m_Launcher = GetComponent<ILauncher>();
        }
        TowerLevel myTower;
        bool fireState = false;
        protected void updateTowerSkillData()
        {
            HandleBullet();
            HandleEnergy();
            HandleFreezeBreath();
        }
        // 处理木精灵装填子弹
        private void HandleBullet()
        {
            if (woodRemainChargeTime > 0f)
                woodRemainChargeTime -= Time.deltaTime;
            if (woodChargeEffectTime > 0f)
            {
                woodChargeEffectTime -= Time.deltaTime;
                UpdateWoodAim();
                if (woodChargeEffectTime <= 0 && woodChargeEffect != null)
                {
               this.energyCalTime += Time.deltaTime;
               float process = energyCalTime % 11.0f;
               int proint = (int)Math.Floor(process);
               proint += towerPtr.uiProOffset;
               towerPtr.energyCtl.SetEnergyProcessFloat( process );
               if (proint == 10)
               {
                  fInEnergy = 5.0f;
                    CancelWoodAim();
                    Destroy(woodChargeEffect);
                    woodChargeEffect = null;
                }
            }
                  // 设置多倍攻击速度
                  fBackupTimer = m_FireTimer;
                  m_FireTimer = m_FireTimer / 3.0f;
            // 预留出来装填子弹的时间.
            if (fillBulletTime > 0)
            {
                fillBulletTime -= Time.deltaTime;
                if (fillBulletTime <= 0.3f)
                {
                    if (towerPtr && towerPtr.bulletCtl)
                        towerPtr.bulletCtl.ResetToMaxBullet();
                }
                  towerPtr.uiProOffset = 0;
                  towerPtr.PlayEnergyEffect(true);
               }
                if (fillBulletTime <= 0)
                {
                    fillBulletTime = 0;
                }
            }
        }
        /// <summary>
        /// 更新木属性瞄准
        /// </summary>
        private void UpdateWoodAim()
        {
            // 离得最近的 Agent
            Agent agent = GetMinDistanceAgent();
            if (agent != null)
            {
                // 还没有瞄准目标,直接分配
                if (woodAimAgent == null)
                {
                    woodAimAgent = agent;
                    if (agent.WoodAimCount == 0)
                        agent.WoodAimEffect.Play();
                    ++agent.WoodAimCount;
                }
                // 有小怪走到之前瞄准目标的前面 或者 之前瞄准的目标死亡,切换瞄准目标
                else if (woodAimAgent.Id != agent.Id)
                {
                    if (woodAimAgent.WoodAimCount > 0)
                    {
                        --woodAimAgent.WoodAimCount;
                        if (woodAimAgent.WoodAimCount == 0)
                        {
                            woodAimAgent.WoodAimEffect.Stop();
                            woodAimAgent.WoodAimEffect.Clear();
                        }
                    }
                    if (agent.WoodAimCount == 0)
                        agent.WoodAimEffect.Play();
                    ++agent.WoodAimCount;
                }
            }
        }
        /// <summary>
        /// 获取距离终点最近的Agent
        /// </summary>
        /// <returns></returns>
        private Agent GetMinDistanceAgent()
        {
            Agent ret = null;
            float minDistance = -1f;
            WaveLineAgentInsMgr[] waveLineAgentIns = AgentInsManager.instance.GetWaveLineList();
            WaveLineAgentInsMgr waveLineAgentInsMgr = waveLineAgentIns[waveLineID];
            List<Agent> agents = waveLineAgentInsMgr.listAgent;
            Vector3 endPos = EndlessLevelManager.instance.GetHomeBasePosition(waveLineID + 1);
            for (int i = 0; i < agents.Count; ++i)
            {
                float distance = Mathf.Abs(agents[i].transform.position.z - endPos.z);
                if (minDistance < 0 || distance < minDistance)
                {
                    minDistance = distance;
                    ret = agents[i];
                }
            }
            return ret;
        }
        /// <summary>
        /// 取消木属性瞄准
        /// </summary>
        private void CancelWoodAim()
        {
            if (woodAimAgent != null && woodAimAgent.WoodAimCount > 0)
            {
                --woodAimAgent.WoodAimCount;
                if (woodAimAgent.WoodAimCount == 0)
                {
                    woodAimAgent.WoodAimEffect.Stop();
                    woodAimAgent.WoodAimEffect.Clear();
                }
            }
            woodAimAgent = null;
        }
        // 处理火精灵充能
        private void HandleEnergy()
        {
            // 充能时间的处理
            if (towerPtr && towerPtr.energyCtl)
            {
                if (fInEnergy <= 0)
                {
                    energyCalTime += Time.deltaTime;
                    float process = energyCalTime % 11.0f;
                    int proint = (int)Math.Floor(process);
                    proint += towerPtr.uiProOffset;
                    towerPtr.energyCtl.SetEnergyProcessFloat(process);
                    if (proint == 10)
                    {
                        fireState = true;
                        fInEnergy = finalFireSpeed;
                        myTower.SetFireMatSpeed(true);//设置了火宝石快速攻击
                        // 设置多倍攻击速度
                        fBackupTimer = m_FireTimer;
                        m_FireTimer = m_FireTimer / finalFireSpeed;
                        towerPtr.uiProOffset = 0;
                        towerPtr.PlayEnergyEffect(true);
                    }
                }
                else
                {
               fInEnergy -= Time.deltaTime;
               if( fInEnergy <= 0)
                    fInEnergy -= Time.deltaTime;
                    if (fInEnergy <= 0)
                    {
                        myTower.SetFireMatSpeed(false);//恢复了火宝石攻击速度
                        fireState = false;
                        EventCenter.Ins.BroadCast((int)KTGMGemClient.EventType.FireTowerChargeEnd);
                  fInEnergy = 0.0f;
                  this.energyCalTime = 0.0f;
                  towerPtr.energyCtl.SetEnergyProgress(0);
                        fInEnergy = 0.0f;
                        energyCalTime = 0.0f;
                        towerPtr.energyCtl.SetEnergyProgress(0);
                  // 恢复正常攻击速度
                  m_FireTimer = fBackupTimer;
                        // 恢复正常攻击速度
                        m_FireTimer = fBackupTimer;
                  towerPtr.PlayEnergyEffect(false);
                        towerPtr.PlayEnergyEffect(false);
               }
            }
                    }
                }
            }
        }
         }
      }
      /// <summary>
      /// Update the timers
      /// </summary>
      protected virtual void Update()
      {
         // 处理当前Affector所在Tower对应的技能
         updateTowerSkillData();
         m_FireTimer -= Time.deltaTime;
         if( trackingEnemy == null )
            m_TrackingEnemy = targetter.GetTarget(waveLineID, bWoodAffector);
         if (trackingEnemy != null && m_FireTimer <= 0.0f)
         {
            OnFireTimer();
            m_FireTimer = 1 / fireRate;
            // 多倍攻速:
            if (fInEnergy > 0.0f)
               m_FireTimer = m_FireTimer / 3.0f;
         }
      }
      /// <summary>
      /// Fired at every poll of the fire rate timer
      /// </summary>
      protected virtual void OnFireTimer()
      {
         if (fireCondition != null)
         {
            if (!fireCondition())
            {
               return;
            }
         }
         FireProjectile();
      }
      /// <summary>
      /// Common logic when attacking
      /// 调用攻击的核心函数,由这个函数发起真正的攻击,多目标或者单目标
      /// </summary>
      protected virtual void FireProjectile()
      {
         // 不再处理多子弹攻击,确保只有一个弹道
         isMultiAttack = false;
         m_TrackingEnemy = targetter.GetTarget( waveLineID, bWoodAffector );
         if ( (m_TrackingEnemy == null) || (fillBulletTime>0) )
         {
            if (this.towerPtr)
               towerPtr.setTowerState(false);
            return;
         }else
        // 处理水精灵的充能
        private void HandleFreezeBreath()
        {
            if (towerPtr && towerPtr.FreezeBreathCtrl)
            {
            if (this.towerPtr)
               towerPtr.setTowerState(true);
                Damager damager = projectile.gameObject.GetComponent<Damager>();
                float finalDamage = damager.damage;
                List<EndlessBuffConfig> list = EndlessBuffManager.instance.GetBuffListByEffectType(EndlessBuffEffectType.AttackAdd, towerPtr.attributeId);
                float ratio = 0;
                float add = 0;
                if (list.Count > 0)
                {
                    for (int i = 0; i < list.Count; ++i)
                    {
                        ratio += list[i].Config.buff_effect[1];
                        add += list[i].Config.buff_effect[2];
                    }
                }
                finalDamage += (ratio / 100f) * finalDamage + add;
                if (inFreezeBreath <= 0)
                {
                    freezeBreathCallTime += Time.deltaTime;
                    float process = freezeBreathCallTime % (FreezeBreath.ChargeTime + 1);
                    int processInt = (int)Mathf.Floor(process);
                    processInt += towerPtr.FreezeBreathProgressOffset;
                    towerPtr.FreezeBreathCtrl.SetProgress(process);
                    if (processInt == (int)Mathf.Floor(FreezeBreath.ChargeTime))
                    {
                        inFreezeBreath = towerPtr.FreezeBreathCtrl.SkillTime;
                        towerPtr.FreezeBreathProgressOffset = 0;
                        towerPtr.PlayFreezeBreathEffect(true);
                        towerPtr.FreezeBreathCtrl.ReleaseCount = 1;
                        towerPtr.FreezeBreathCtrl.PlayFreezeEffect(waveLineID);
                        towerPtr.FreezeBreathCtrl.ReleaseFreeze(waveLineID, finalDamage, damager.alignmentProvider);
                    }
                }
                else
                {
                    inFreezeBreath -= Time.deltaTime;
                    int time = Mathf.FloorToInt(towerPtr.FreezeBreathCtrl.EffectTime / (towerPtr.FreezeBreathCtrl.DamageCount - 1) * 10);
                    int interval = Mathf.FloorToInt(inFreezeBreath * 10);
                    int offset = Mathf.FloorToInt(towerPtr.FreezeBreathCtrl.SkillTime * 10) - Mathf.FloorToInt(towerPtr.FreezeBreathCtrl.EffectTime * 10);
                    if (interval == time * (towerPtr.FreezeBreathCtrl.DamageCount - towerPtr.FreezeBreathCtrl.ReleaseCount - 1) + offset && towerPtr.FreezeBreathCtrl.ReleaseCount < towerPtr.FreezeBreathCtrl.DamageCount)
                    {
                        ++towerPtr.FreezeBreathCtrl.ReleaseCount;
                        towerPtr.FreezeBreathCtrl.ReleaseFreeze(waveLineID, finalDamage, damager.alignmentProvider);
                    }
                    if (inFreezeBreath <= 0)
                    {
                        inFreezeBreath = 0;
                        freezeBreathCallTime = 0;
                        towerPtr.FreezeBreathCtrl.SetProgress(0);
                        towerPtr.PlayFreezeBreathEffect(false);
                    }
                }
            }
        }
        /// <summary>
        /// This function is called when the object becomes enabled and active.
        /// </summary>
        void OnEnable()
        {
            if (towerPtr && towerPtr.energyCtl)
            {
                if (fireState)
                {
                    myTower.SetFireMatSpeed(true);//设置了火宝石快速攻击
                    towerPtr.PlayEnergyEffect(true);
                }
            }
        }
        /// <summary>
        /// This function is called when the behaviour becomes disabled or inactive.
        /// </summary>
        void OnDisable()
        {
            if (towerPtr && towerPtr.energyCtl)
            {
                towerPtr.PlayEnergyEffect(false, false);
            }
         //
         // 处理子弹充能相关的内容
         if( towerPtr && (towerPtr.bulletCtl != null))
            if (towerPtr && towerPtr.FreezeBreathCtrl)
                towerPtr.PlayFreezeBreathEffect(false, false);
        }
        /// <summary>
        /// 获取子弹发射时间间隔
        /// </summary>
        public float GetFireDuration()
        {
            DecreaseTowerAttackCD endlessBuff = (DecreaseTowerAttackCD)EndlessBuffManager.instance.GetBuffInstanceByType(EndlessBuffEffectType.DecreaseTowerAttackCD);
            return endlessBuff != null ? endlessBuff.GetDecreaseCD(towerPtr.attributeId, 1 / projectileFireRate) : 1 / projectileFireRate;
        }
        /// <summary>
        /// Update the timers
        /// </summary>
        protected virtual void Update()
        {
            if (m_Launcher == null) return;
            // 处理当前Affector所在Tower对应的技能
            updateTowerSkillData();
            m_FireTimer -= Time.deltaTime;
            m_TrackingEnemy = targetter.GetTarget(waveLineID, bWoodAffector);
            if (m_TrackingEnemy != null && m_FireTimer < 0)
            {
            int bnum = towerPtr.bulletCtl.decBullet();
            //
            if (bnum == 0)
            {
               damagerProjectile.damageMulti = 5.0f;
               fillBulletTime = 2.0f;
            }
                m_FireTimer = GetFireDuration();
                if (fInEnergy > 0)
                    m_FireTimer /= finalFireSpeed;
                towerLevel.FireSpeed = fInEnergy > 0 ? finalFireSpeed : 1f;
                if (towerPtr && towerPtr.bulletCtl != null)
                {
                    int bnum = towerPtr.bulletCtl.GetCtlProgress();
                    // 蓄力时间内不攻击
                    if (bnum == 0 || woodRemainChargeTime > 0f) return;
                }
                if (towerPtr && towerPtr.FreezeBreathCtrl != null)
                {
                    // 冷冻气息期间不攻击
                    if (inFreezeBreath > 0.0001f) return;
                }
                towerLevel.ChangeState(TowerActionState.Attack);
            }
        }
        /// <summary>
        /// Common logic when attacking
        /// 调用攻击的核心函数,由这个函数发起真正的攻击,多目标或者单目标
        /// </summary>
        public virtual void FireProjectile()
        {
            // 不再处理多子弹攻击,确保只有一个弹道
            isMultiAttack = false;
            m_TrackingEnemy = targetter.GetTarget(waveLineID, bWoodAffector);
            GameObject go = damagerProjectile.gameObject;
            if (m_TrackingEnemy == null || fillBulletTime > 0) return;
            go.GetComponent<Damager>().IsEnhancedBullet = false;
            // 处理子弹充能相关的内容
            if (towerPtr && towerPtr.bulletCtl != null)
            {
                int bnum = towerPtr.bulletCtl.decBullet();
                // 暴击子弹的数量,如果获得相应buff可能会修改暴击子弹数量
                int critBulletNum = towerPtr.bulletCtl.CritBulletNum;
                if (bnum < critBulletNum)
                {
                    if (bnum == 0)
                        // 不需要装填时间
                        fillBulletTime = 0.1f;
                    //这里需要替换特效
                    var poolable = Core.Utilities.Poolable.TryGetPoolable<Core.Utilities.Poolable>(woodProjectile_SP);
                    go = poolable.gameObject;
                    Damager tmpDamager = go.GetComponent<Damager>();
                    tmpDamager.damageMulti = 10.0f;
                    tmpDamager.damage = damagerProjectile.damage;
                    tmpDamager.IsEnhancedBullet = true;
                }
                // 下一颗子弹是强化子弹,然后直接蓄力
                if (bnum - 1 >= 0 && bnum - 1 < critBulletNum)
                {
                    woodRemainChargeTime = woodChargeTime;
                    DecreaseWoodChargeTime decreaseWoodChargeTime = (DecreaseWoodChargeTime)EndlessBuffManager.instance.GetBuffInstanceByType(EndlessBuffEffectType.DecreaseWoodChargeTime);
                    if (decreaseWoodChargeTime != null)
                        woodRemainChargeTime = decreaseWoodChargeTime.GetWoodChargeTime(woodChargeTime);
                    woodChargeEffectTime = woodRemainChargeTime + 0.5f / towerLevel.ActionAnimator.speed;
                    woodChargeEffect = Instantiate(WoodChargeEffect);
                    woodChargeEffect.transform.SetPositionAndRotation(WoodChargeTransform.position, WoodChargeTransform.rotation);
                    ParticleSystem ps = woodChargeEffect.transform.GetChild(0).GetComponent<ParticleSystem>();
                    ps.Play();
                }
            }
            else
            {
                if (towerPtr)
                    towerPtr.setTowerState(true);
            }
         if (isMultiAttack)
         {
            List<Targetable> enemies = towerTargetter.GetAllTargets();
            if( (enemies != null)&&(Targetter.bSearchTarget) )
               m_Launcher.Launch(enemies, projectile, projectilePoints,this.maxAttackNum);
         }
         else
         {
            if(Targetter.bSearchTarget )
               m_Launcher.Launch(m_TrackingEnemy, damagerProjectile.gameObject, projectilePoints);
         }
         if (randomAudioSource != null)
         {
            if( Targetter.bSearchTarget )
               randomAudioSource.PlayRandomClip();
         }
      }
            if (isMultiAttack)
            {
                List<Targetable> enemies = towerTargetter.GetAllTargets();
                if ((enemies != null) && (Targetter.bSearchTarget))
                    m_Launcher.Launch(enemies, projectile, projectilePoints, maxAttackNum);
            }
            else
            {
                if (Targetter.bSearchTarget)
                {
                    m_Launcher.Launch(m_TrackingEnemy, go, projectilePoints);
                    if (AudioSourceManager.Ins)
                        AudioSourceManager.Ins.Play(audioEnum);
                }
            }
            if (randomAudioSource != null)
            {
                if (Targetter.bSearchTarget)
                    randomAudioSource.PlayRandomClip();
            }
        }
      /// <summary>
      /// A delegate to compare distances of components
      /// </summary>
      /// <param name="first"></param>
      /// <param name="second"></param>
      protected virtual int ByDistance(Targetable first, Targetable second)
      {
         float firstSqrMagnitude = Vector3.SqrMagnitude(first.position - epicenter.position);
         float secondSqrMagnitude = Vector3.SqrMagnitude(second.position - epicenter.position);
         return firstSqrMagnitude.CompareTo(secondSqrMagnitude);
      }
        /// <summary>
        /// A delegate to compare distances of components
        /// </summary>
        /// <param name="first"></param>
        /// <param name="second"></param>
        protected virtual int ByDistance(Targetable first, Targetable second)
        {
            float firstSqrMagnitude = Vector3.SqrMagnitude(first.position - epicenter.position);
            float secondSqrMagnitude = Vector3.SqrMagnitude(second.position - epicenter.position);
            return firstSqrMagnitude.CompareTo(secondSqrMagnitude);
        }
#if UNITY_EDITOR
      /// <summary>
      /// Draws the search area
      /// </summary>
      void OnDrawGizmosSelected()
      {
         Gizmos.DrawWireSphere(epicenter.position, towerTargetter.effectRadius);
      }
        /// <summary>
        /// Draws the search area
        /// </summary>
        void OnDrawGizmosSelected()
        {
            Gizmos.DrawWireSphere(epicenter.position, towerTargetter.effectRadius);
        }
#endif
   }
    }
   /// <summary>
   /// A delegate for boolean calculation logic
   /// </summary>
   public delegate bool Filter();
    /// <summary>
    /// A delegate for boolean calculation logic
    /// </summary>
    public delegate bool Filter();
}