using KTGMGemClient; using System.Collections; using System; using ActionGameFramework.Health; using Core.Utilities; using TowerDefense.Level; using TowerDefense.Targetting; using TowerDefense.Towers.Placement; using TowerDefense.UI.HUD; using UnityEngine; namespace TowerDefense.Towers { public enum EFeatureTower { NULL, GrowUp, CopyCat, LightTower, Skill_Fire, Skill_Bomb, END } public enum ETowerFuntion { NULL, BULLET, // 子弹塔 ENERGY, // 能量充能. FREEZE, // 水精灵充能 END } /// /// Common functionality for all types of towers /// public class Tower : Targetable { public readonly float INSCENE_TU_DAMAGE = 30f; public static readonly int MAX_LEVEL = 4; /// /// A generalised name common to a levels /// public string towerName; /// /// The size of the tower's footprint /// public IntVector2 dimensions; /// /// 是否是特色骰子,如果是,则选择一个Enum类型。 /// public EFeatureTower towerFeature = EFeatureTower.NULL; /// /// 当前塔防对应的MonsterMaterial,自身和对方显示不同的Mat. /// public Material materialMonsterSelf; public Material materialMonsterOppo; /// /// 当前塔防对应的攻击和等待Mat. /// public Material materialTowerAttackSelf; public Material materialTowerWaitSelf; public Material materialTowerAttackOppo; public Material materialTowerWaitOppo; /// /// 0 空状态 1 等待状态 2 攻击状态. /// protected int curActionState = 0; /// /// 塔防对应的充能状态. /// public ETowerFuntion eTowerFuntion = ETowerFuntion.NULL; public BulletUICtl bulletCtl = null; public EnergyUICtl energyCtl = null; public FreezeBreath FreezeBreathCtrl = null; /// /// The tower levels associated with this tower /// public TowerLevel[] levels; /// /// 当前塔防对应的AttributeID. /// public int attributeId; /// /// 当前的Tower在游戏内UI界面上用到的Image数据,再以后应该是直接在表格内配置才合适 /// public Sprite uiImage; /// /// The physics mask the tower searches on /// public LayerMask enemyLayerMask; /// /// The current level of the tower /// public int currentLevel { get; protected set; } protected bool m_bInAttackMode = false; /// /// 精英怪和Boss双倍伤害. /// public bool bDoubleHitElit = false; /// /// Reference to the data of the current level /// public TowerLevel currentTowerLevel { get; protected set; } /// /// 攻击增加 /// public float attackRise { get; set; } /// /// 用于界面部分的数据位移 /// protected int progressOffset = 0; public int FreezeBreathProgressOffset { get; set; } public bool PlayWaveLineFlash { get; set; } = true; /// /// 塔防数据的局内升级 /// public int inSceneTowerLevel { get; set; } public int uiProOffset { get { return progressOffset; } set { progressOffset = value; } } /// /// Gets whether the tower can level up anymore /// public bool isAtMaxLevel { get { return currentLevel == levels.Length - 1; } } public void setTowerState(bool attack) { if (!materialTowerAttackSelf) return; if (opponentSide) { if (attack && (curActionState != 2)) { currentTowerLevel.SetTowerMonsterMat(materialTowerAttackOppo, true); curActionState = 2; } if ((!attack) && (curActionState != 1)) { currentTowerLevel.SetTowerMonsterMat(materialTowerWaitOppo, false); curActionState = 1; } } else { if (attack && (curActionState != 2)) { currentTowerLevel.SetTowerMonsterMat(materialTowerAttackSelf, true); curActionState = 2; } if ((!attack) && (curActionState != 1)) { currentTowerLevel.SetTowerMonsterMat(materialTowerWaitSelf, false); curActionState = 1; } } } /// /// 是否是对手塔防 /// public bool opponentSide { get; set; } /// /// 播放充能状态特效. /// /// public void PlayEnergyEffect(bool play, bool isClose = true) { if (energyCtl && isClose) energyCtl.gameObject.SetActive(!play); else if (!isClose) { } if (!opponentSide) { if (GameUI.instanceExists) ((TowerPlacementGrid)GameUI.instance.selfTowerPlaceArea).PlayEnergyEffect(gridPosition.x, play); else if (EndlessGameUI.instanceExists) ((TowerPlacementGridEndless)EndlessGameUI.instance.selfTowerPlaceArea).PlayEnergyEffect(gridPosition.x, gridPosition.y, play); } else ((TowerPlacementGrid)OpponentMgr.instance.m_CurrentArea).PlayEnergyEffect(gridPosition.x, play); } /// /// 播放水精灵充能满了特效 /// /// /// 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); } } /// /// 当前是否处于攻击模式 /// public bool bInAttackMode { get { return m_bInAttackMode; } // 设置是否处于攻击状态: set { m_bInAttackMode = value; currentTowerLevel.SetAffectorState(m_bInAttackMode, gridPosition.x); currentTowerLevel.SetAttackState(value); if (value) { if (opponentSide) { OpponentMgr.instance.SetTowerAttID(gridPosition.x, attributeId, currentLevel); } else { if (LevelManager.instanceExists) { LevelManager.instance.SetTowerAttID(gridPosition.x, attributeId, currentLevel); WaveLineSelMgr.instance.attackTowerFixed(gridPosition.x); } else if (EndlessLevelManager.instanceExists) { EndlessLevelManager.instance.SetTowerAttID(gridPosition.x, attributeId, currentLevel); EndlessWaveLineManager.instance.AttackTowerFixed(gridPosition.x, PlayWaveLineFlash); } } // 处理塔位边上的界面. OnTowerUICtrl(); } } } /// /// 去掉当前Tower对应的界面数据. /// public void DisableTowerUICtrl() { // 根据是否是子弹塔防来决定是否显示相应的界面 BulletUICtl buc = placementArea.GetBulletUICtl(gridPosition.x, gridPosition.y); if ((eTowerFuntion == ETowerFuntion.BULLET) && (buc != null)) { buc.gameObject.SetActive(false); bulletCtl = null; } EnergyUICtl euc = placementArea.GetEnergyUICtl(gridPosition.x, gridPosition.y); if ((eTowerFuntion == ETowerFuntion.ENERGY) && (euc != null)) { // 设置数据 euc.gameObject.SetActive(false); energyCtl = null; } 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 = placementArea.GetBulletUICtl(gridPosition.x, gridPosition.y); 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; } public void SetTowerUICtlProcess(int pro) { // 根据是否是子弹塔防来决定是否显示相应的界面 BulletUICtl buc = placementArea.GetBulletUICtl(gridPosition.x, gridPosition.y); if ((eTowerFuntion == ETowerFuntion.BULLET) && (buc != null)) { buc.SetCtlProcess(pro); progressOffset = pro; return; } EnergyUICtl euc = placementArea.GetEnergyUICtl(gridPosition.x, gridPosition.y); if ((eTowerFuntion == ETowerFuntion.ENERGY) && (euc != null)) { euc.SetCtlProcess(pro); progressOffset = pro; if (progressOffset == 10) progressOffset = 0; return; } FreezeBreath ctrl = placementArea.GetFreezeBreath(gridPosition.x, gridPosition.y); if (eTowerFuntion == ETowerFuntion.FREEZE && ctrl != null) { ctrl.SetCtrlProgress(pro); FreezeBreathProgressOffset = pro; if (FreezeBreathProgressOffset == 10) FreezeBreathProgressOffset = 0; } } /// /// 充能技能相关的代码开关。包括子弹充能和时间充能 /// protected void OnTowerUICtrl() { HandleBulletUICtrl(); HandleEnergyUICtrl(); HandleFreezeBreathCtrl(); } private void HandleBulletUICtrl() { // 根据是否是子弹塔防来决定是否显示相应的界面 BulletUICtl buc = placementArea.GetBulletUICtl(gridPosition.x, gridPosition.y); if (buc == null) return; if ((eTowerFuntion == ETowerFuntion.BULLET) && (buc != null)) { // 设置数据 buc.gameObject.SetActive(true); bulletCtl = buc; buc.ResetToMaxBullet(); } else { // 清空数据 buc.gameObject.SetActive(false); bulletCtl = null; } } private void HandleEnergyUICtrl() { // 根据是否是能量充能来决定是否显示相应的界面. EnergyUICtl euc = placementArea.GetEnergyUICtl(gridPosition.x, gridPosition.y); if ((eTowerFuntion == ETowerFuntion.ENERGY) && (euc != null)) { // 设置数据 euc.gameObject.SetActive(true); energyCtl = euc; euc.SetEnergyProgress(0); } else { // 清空数据 euc.gameObject.SetActive(false); energyCtl = null; } } private void HandleFreezeBreathCtrl() { FreezeBreath ctrl = placementArea.GetFreezeBreath(gridPosition.x, gridPosition.y); if (eTowerFuntion == ETowerFuntion.FREEZE && ctrl != null) { ctrl.gameObject.SetActive(true); FreezeBreathCtrl = ctrl; ctrl.SetProgress(0); } else { ctrl.gameObject.SetActive(false); FreezeBreathCtrl = null; } } /// /// This function is called when the object becomes enabled and active. /// void OnEnable() { // if (bulletCtl != null) // { // Debug.Log("打开了bulletCtl"); // bulletCtl.gameObject.SetActive(true); // } // if (energyCtl != null) // { // Debug.Log("打开了energyCtl"); // energyCtl.gameObject.SetActive(true); // } } /// /// This function is called when the behaviour becomes disabled or inactive. /// void OnDisable() { if (bulletCtl != null) { bulletCtl.gameObject.SetActive(false); } if (energyCtl != null) { energyCtl.gameObject.SetActive(false); } if (FreezeBreathCtrl != null) FreezeBreathCtrl.gameObject.SetActive(false); } /// /// 初始化当前塔防的局内升级,lvl从1开始. /// /// public void initInSceneTowerLevel(int lvl) { inSceneTowerLevel = lvl; if (lvl <= 1) { ResetInSceneTowerLevel(); return; } // 设置攻击数据的加强,暂时是测试数据,后面需要读取表格数据处理: float damageAdd = 0; // float damageAdd = (inSceneTowerLevel - 1) * INSCENE_TU_DAMAGE; for (int ti = 0; ti < 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 < levels.Length; ti++) { if (levels[ti].levelDamager) { levels[ti].levelDamager.inSceneUpGradeDamage = 0; levels[ti].levelDamager.doubleHit = bDoubleHitElit; } } return; } /// /// 升级当前塔防的局内等级,需要播放相关的特效 /// public void upGradeInSceneTL() { inSceneTowerLevel++; // 设置攻击数据的加强,暂时是测试数据,后面需要读取表格数据处理: float damageAdd = inSceneTowerLevel * INSCENE_TU_DAMAGE; for (int ti = 0; ti < 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(); } /// /// Gets the first level tower ghost prefab /// public TowerPlacementGhost towerGhostPrefab { get { return levels[currentLevel].towerGhostPrefab; } } /// /// Gets the grid position for this tower on the /// public IntVector2 gridPosition { get; private set; } /// /// The placement area we've been built on /// public IPlacementArea placementArea { get; private set; } /// /// The purchase cost of the tower /// public int purchaseCost { get { return levels[0].cost; } } /// /// The event that fires off when a player deletes a tower /// public Action towerDeleted; /// /// The event that fires off when a tower has been destroyed /// public Action towerDestroyed; /// /// 放置到目标位置 /// /// public virtual void SetToDestination(IntVector2 destination) { gridPosition = destination; transform.position = placementArea.GridToWorld(destination, dimensions); } /// /// Provide the tower with data to initialize with /// /// The placement area configuration /// The destination position public virtual void Initialize(IPlacementArea targetArea, IntVector2 destination, int lvl = 0) { placementArea = targetArea; gridPosition = destination; if (targetArea != null) { transform.position = placementArea.GridToWorld(destination, dimensions); transform.rotation = placementArea.transform.rotation; targetArea.Occupy(destination, dimensions); } SetLevel(lvl); if (LevelManager.instanceExists) { LevelManager.instance.levelStateChanged += OnLevelStateChanged; } else if (EndlessLevelManager.instanceExists) EndlessLevelManager.instance.LevelStateChanged += OnLevelStateChanged; // 查找Targetter: Targetter target = GetComponentInChildren(); if (target) { target.bOpponent = opponentSide; } else Debug.Log("在当前的Tower中找不到Targetter."); // // 初始化当前的局内Tower等级数据 initInSceneTowerLevel(SceneTowerLvl.getInSceneTowerLvl(towerName)); StartCoroutine(ResetScale()); } IEnumerator ResetScale() { yield return new WaitForSeconds(0.2f); if (gridPosition.y > 1) { currentTowerLevel.ResetScale(); } else { currentTowerLevel.NormalScale(); } } /// /// Provides information on the cost to upgrade /// /// Returns -1 if the towers is already at max level, other returns the cost to upgrade public int GetCostForNextLevel() { if (isAtMaxLevel) { return -1; } return levels[currentLevel + 1].cost; } /// /// 当前的Tower是显示还是隐藏,用于减少游戏内Tower创建和删除对应的一系列数据操作 /// /// public void showTower(bool vis) { if (vis) { gameObject.SetActive(true); } else { gameObject.SetActive(false); } } /// /// Kills this tower /// public void KillTower() { // Invoke base kill method Kill(); } /// /// Provides the value recived for selling this tower /// /// A sell value of the tower public int GetSellLevel() { return GetSellLevel(currentLevel); } /// /// Provides the value recived for selling this tower of a particular level /// /// Level of tower /// A sell value of the tower 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; } /// /// Used to (try to) upgrade the tower data /// public virtual bool UpgradeTower() { if (isAtMaxLevel) { return false; } SetLevel(currentLevel + 1); return true; } /// /// A method for downgrading tower /// /// /// false if tower is at lowest level /// public virtual bool DowngradeTower() { if (currentLevel == 0) { return false; } SetLevel(currentLevel - 1); return true; } /// /// Used to set the tower to any valid level /// /// /// The level to upgrade the tower to /// /// /// True if successful /// public virtual bool UpgradeTowerToLevel(int level) { if (level < 0 || isAtMaxLevel || level >= levels.Length) { return false; } SetLevel(level); return true; } public void Sell() { Remove(); } /// /// Removes tower from placement area and destroys it /// public override void Remove() { base.Remove(); // 清空局内升级数据: ResetInSceneTowerLevel(); attackRise = 0.0f; placementArea.Clear(gridPosition, dimensions); Destroy(gameObject); } /// /// unsubsribe when necessary /// protected virtual void OnDestroy() { if (LevelManager.instanceExists) { LevelManager.instance.levelStateChanged += OnLevelStateChanged; } else if (EndlessLevelManager.instanceExists) EndlessLevelManager.instance.LevelStateChanged += OnLevelStateChanged; } /// /// Cache and update oftenly used data /// public void SetLevel(int level) { if (level < 0 || level >= levels.Length) { return; } currentLevel = level; if (currentTowerLevel != null) { Destroy(currentTowerLevel.gameObject); } // instantiate the visual representation currentTowerLevel = Instantiate(levels[currentLevel], transform); // initialize TowerLevel currentTowerLevel.Initialize(this, enemyLayerMask, configuration.alignmentProvider); // health data ScaleHealth(); // // disable affectors LevelState levelState = LevelState.Intro; if (LevelManager.instanceExists) levelState = LevelManager.instance.levelState; else if (EndlessLevelManager.instanceExists) levelState = EndlessLevelManager.instance.EndlessLeveltate; bool initialise = levelState == LevelState.AllEnemiesSpawned || levelState == LevelState.SpawningEnemies; initialise = false; currentTowerLevel.SetAffectorState(initialise, gridPosition.x); } /// /// Scales the health based on the previous health /// Requires override when the rules for scaling health on upgrade changes /// 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); } } /// /// Intiailises affectors based on the level state /// protected virtual void OnLevelStateChanged(LevelState previous, LevelState current) { bool initialise = current == LevelState.AllEnemiesSpawned || current == LevelState.SpawningEnemies; initialise = false; //currentTowerLevel.SetAffectorState(initialise); currentTowerLevel.SetAffectorState(bInAttackMode, gridPosition.x); } } }