using System;
using System.Collections.Generic;
using ActionGameFramework.Audio;
using ActionGameFramework.Health;
using Core.Health;
using TowerDefense.Targetting;
using TowerDefense.Towers;
using TowerDefense.Towers.Projectiles;
using UnityEngine;
using KTGMGemClient;
using TowerDefense.Agents;
using TowerDefense.Level;
namespace TowerDefense.Affectors
{
///
/// 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
///
[RequireComponent(typeof(ILauncher))]
public class AttackAffector : Affector, ITowerRadiusProvider
{
///
/// The projectile used to attack
///
public GameObject projectile;
///
/// 木塔最后一击是特殊攻击,需要替换projectile
///
public GameObject woodProjectile_SP;
///
/// The list of points to launch the projectiles from
///
public Transform[] projectilePoints;
///
/// The reference to the center point where the tower will search from
///
public Transform epicenter;
///
/// 如果是多目标攻击,最多攻击目标
///
public int maxAttackNum = 1;
///
/// 是否木属性数据
///
public bool bWoodAffector = false;
///
/// The audio source to play when firing
///
public RandomAudioSource randomAudioSource;
///
/// Gets the targetter
///
public Targetter towerTargetter;
///
/// Color of effect radius visualization
///
public Color radiusEffectColor;
///
/// Search condition
///
public Filter searchCondition;
///
/// Fire condition
///
public Filter fireCondition;
///
/// The reference to the attached launcher
///
protected ILauncher m_Launcher;
///
/// The time before firing is possible
///
protected float m_FireTimer;
protected float freezeBreathTimer;
///
/// Reference to the current tracked enemy
///
protected Targetable m_TrackingEnemy;
public TowerLevel towerLevel;
///
/// 处理装弹时间.
///
protected float fillBulletTime = 0.0f;
///
/// 火精灵充能时间
///
protected float energyCalTime = 0;
protected float fInEnergy = 0;
protected float fBackupTimer = 0.0f;
///
/// 水精灵的充能时间
///
protected float freezeBreathCallTime = 0;
protected float inFreezeBreath;
protected float freezeBreathBackTimer = 0;
private int towerAttributeId;
///
/// 火精灵技能固定攻击倍速
///
///
protected float fireSpeed { get; set; } = 5f;
///
/// 木属性精灵蓄力时间
///
protected float woodChargeTime { get; set; } = 1.5f;
protected float woodRemainChargeTime { get; set; }
///
/// 蓄力特效时间
///
protected float woodChargeEffectTime { get; set; }
///
/// 木属性精灵蓄力特效
///
public ParticleSystem WoodChargeEffect;
public Transform WoodChargeTransform;
///
/// 木属性正在瞄准的Agent
///
protected Agent woodAimAgent;
///
/// 火精灵攻击最终攻击倍速,里面计算了buff增加的倍速
///
///
public float finalFireSpeed
{
get
{
FireRateAdd fireRateAdd = (FireRateAdd)EndlessBuffManager.instance.GetBuffInstanceByType(EndlessBuffEffectType.FireRateAdd);
float rateAdd = 0;
if (fireRateAdd != null)
rateAdd = fireRateAdd.GetFireSpeedAdd(towerPtr.ElfId);
return rateAdd > 1 ? rateAdd : fireSpeed;
}
}
///
/// Gets the search rate from the targetter
///
public float searchRate
{
get { return towerTargetter.searchRate; }
set { towerTargetter.searchRate = value; }
}
///
/// Gets the targetable
///
public Targetable trackingEnemy
{
get { return m_TrackingEnemy; }
}
///
/// Gets or sets the attack radius
///
public float effectRadius
{
get { return towerTargetter.effectRadius; }
}
public Color effectColor
{
get { return radiusEffectColor; }
}
public Targetter targetter
{
get { return towerTargetter; }
}
///
/// Initializes the attack affector
///
public override void Initialize(IAlignmentProvider affectorAlignment)
{
Initialize(affectorAlignment, -1);
}
///
/// 返回可能存在的Targetter.
///
///
public override TowerDefense.Targetting.Targetter GetTargetter()
{
return targetter;
}
///
/// Initialises the attack affector with a layer mask
///
public override void Initialize(IAlignmentProvider affectorAlignment, LayerMask mask)
{
base.Initialize(affectorAlignment, mask);
SetUpTimers();
towerTargetter.ResetTargetter();
towerTargetter.alignment = affectorAlignment;
towerTargetter.acquiredTarget += OnAcquiredTarget;
// towerTargetter.lostTarget += OnLostTarget;
myTower = transform.parent.GetComponent();
GetAudioEnum();
}
private AudioEnum audioEnum;//当前音乐的种类
void GetAudioEnum()
{
//小怪身上也有这个脚本,塔的名字做了更改,所以判断条件需要变成transform.parent.parent
if (transform.parent.parent != null)
{
if (transform.parent.parent.name.StartsWith("GrowUpTower"))
{
//火元素
audioEnum = AudioEnum.FireTAttack;
}
else if (transform.parent.parent.name.StartsWith("BlinkTower"))
{
//木元素
audioEnum = AudioEnum.WoodTAttack;
}
else if (transform.parent.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(); }
}
public Damager damagerProjectile1
{
get { return projectile == null ? null : projectile.GetComponent(); }
}
public Damager damagerProjectile2
{
get { return projectile == null ? null : projectile.GetComponent(); }
}
///
/// Initialise the RepeatingTimer
///
protected virtual void SetUpTimers()
{
m_Launcher = GetComponent();
}
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)
{
towerPtr.IsWoodCharge = false;
CancelWoodAim();
WoodChargeEffect.Stop();
}
}
// 预留出来装填子弹的时间.
if (fillBulletTime > 0)
{
fillBulletTime -= Time.deltaTime;
if (fillBulletTime <= 0.3f)
{
if (towerPtr && towerPtr.bulletCtl)
towerPtr.bulletCtl.ResetToMaxBullet();
}
if (fillBulletTime <= 0)
{
fillBulletTime = 0;
}
}
}
///
/// 更新木属性瞄准
///
private void UpdateWoodAim()
{
// 离得最近的 Agent
Agent agent = AgentInsManager.instance.GetMinDisAgent(waveLineID, false);
if (agent != null)
{
// 还没有瞄准目标,直接分配
if (woodAimAgent == null)
{
woodAimAgent = agent;
towerPtr.WoodAimAgent = agent;
if (agent.WoodAimCount == 0)
agent.PlayWoodAimEffect();
++agent.WoodAimCount;
}
// 有小怪走到之前瞄准目标的前面 或者 之前瞄准的目标死亡,切换瞄准目标
else if (woodAimAgent.Id != agent.Id)
{
if (woodAimAgent.WoodAimCount > 0)
{
--woodAimAgent.WoodAimCount;
if (woodAimAgent.WoodAimCount == 0)
woodAimAgent.StopWoodAimEffect();
}
woodAimAgent = agent;
towerPtr.WoodAimAgent = agent;
if (agent.WoodAimCount == 0)
agent.PlayWoodAimEffect();
++agent.WoodAimCount;
}
}
}
///
/// 取消木属性瞄准
///
private void CancelWoodAim()
{
if (woodAimAgent != null)
{
if (woodAimAgent.WoodAimCount > 0)
{
--woodAimAgent.WoodAimCount;
if (woodAimAgent.WoodAimCount == 0)
woodAimAgent.StopWoodAimEffect();
}
}
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;
// 设置多倍攻击速度
fBackupTimer = m_FireTimer;
m_FireTimer = m_FireTimer / finalFireSpeed;
towerPtr.uiProOffset = 0;
towerPtr.PlayEnergyEffect(true);
}
}
else
{
fInEnergy -= Time.deltaTime;
if (fInEnergy <= 0)
{
fireState = false;
//EventCenter.Ins.BroadCast((int)KTGMGemClient.EventType.FireTowerChargeEnd);
fInEnergy = 0.0f;
energyCalTime = 0.0f;
towerPtr.energyCtl.SetEnergyProgress(0);
// 恢复正常攻击速度
m_FireTimer = fBackupTimer;
towerPtr.PlayEnergyEffect(false);
}
}
}
}
// 处理水精灵的充能
private void HandleFreezeBreath()
{
if (towerPtr && towerPtr.FreezeBreathCtrl)
{
Damager damager = projectile.gameObject.GetComponent();
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, towerPtr, 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, towerPtr, damager.alignmentProvider);
}
if (inFreezeBreath <= 0)
{
inFreezeBreath = 0;
freezeBreathCallTime = 0;
towerPtr.FreezeBreathCtrl.SetProgress(0);
towerPtr.PlayFreezeBreathEffect(false);
}
}
}
}
///
/// This function is called when the object becomes enabled and active.
///
void OnEnable()
{
if (towerPtr && towerPtr.energyCtl)
{
if (fireState)
{
towerPtr.PlayEnergyEffect(true);
}
}
// 如果在木属性蓄力期间,让瞄准动画播放
if (towerPtr && towerPtr.IsWoodCharge && woodAimAgent != null)
woodAimAgent.PlayWoodAimEffect();
}
///
/// This function is called when the behaviour becomes disabled or inactive.
///
void OnDisable()
{
if (towerPtr && towerPtr.energyCtl)
{
towerPtr.PlayEnergyEffect(false, false);
}
if (towerPtr && towerPtr.FreezeBreathCtrl)
towerPtr.PlayFreezeBreathEffect(false, false);
}
///
/// Update the timers
///
protected virtual void Update()
{
if (m_Launcher == null || towerPtr != null && !towerPtr.CanAttack) return;
// 处理当前Affector所在Tower对应的技能
updateTowerSkillData();
m_FireTimer -= Time.deltaTime;
m_TrackingEnemy = targetter.GetTarget(waveLineID, bWoodAffector);
if (m_TrackingEnemy != null && m_FireTimer < 0)
{
m_FireTimer = towerLevel.GetFireRate();
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);
}
}
///
/// Common logic when attacking
/// 调用攻击的核心函数,由这个函数发起真正的攻击,多目标或者单目标
///
public virtual void FireProjectile()
{
m_TrackingEnemy = targetter.GetTarget(waveLineID, bWoodAffector);
GameObject go = damagerProjectile.gameObject;
if (m_TrackingEnemy == null || fillBulletTime > 0) return;
Damager goDamager = go.GetComponent();
goDamager.IsEnhancedBullet = false;
goDamager.TowerPtr = towerPtr;
// 处理子弹充能相关的内容
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(woodProjectile_SP);
go = poolable.gameObject;
Damager tmpDamager = go.GetComponent();
tmpDamager.damageMulti = 10.0f;
tmpDamager.damage = damagerProjectile.damage;
tmpDamager.IsEnhancedBullet = true;
tmpDamager.TowerPtr = towerPtr;
}
// 下一颗子弹是强化子弹,然后直接蓄力
if (bnum - 1 >= 0 && bnum - 1 < critBulletNum)
{
woodRemainChargeTime = woodChargeTime;
towerPtr.IsWoodCharge = true;
DecreaseWoodChargeTime decreaseWoodChargeTime = (DecreaseWoodChargeTime)EndlessBuffManager.instance.GetBuffInstanceByType(EndlessBuffEffectType.DecreaseWoodChargeTime);
if (decreaseWoodChargeTime != null)
woodRemainChargeTime = decreaseWoodChargeTime.GetWoodChargeTime(woodChargeTime);
woodChargeEffectTime = woodRemainChargeTime + 0.5f / towerLevel.ActionAnimator.speed;
WoodChargeEffect.Play();
}
}
if (Targetter.bSearchTarget)
{
m_Launcher.Launch(m_TrackingEnemy, go, projectilePoints);
if (AudioSourceManager.Ins)
AudioSourceManager.Ins.Play(audioEnum);
}
}
///
/// A delegate to compare distances of components
///
///
///
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
///
/// Draws the search area
///
void OnDrawGizmosSelected()
{
Gizmos.DrawWireSphere(epicenter.position, towerTargetter.effectRadius);
}
#endif
}
///
/// A delegate for boolean calculation logic
///
public delegate bool Filter();
}