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);
}
}
}