839 lines
26 KiB
C#
839 lines
26 KiB
C#
using Framework;
|
|
using Gameplay.Buff;
|
|
using Gameplay.Character;
|
|
using Gameplay.Level;
|
|
using System;
|
|
using cfg.BuffCfg;
|
|
using CodeStage.AntiCheat.ObscuredTypes;
|
|
using Cysharp.Threading.Tasks;
|
|
using Gameplay.Area;
|
|
using Gameplay.Bullet;
|
|
using Gameplay.Common;
|
|
using Gameplay.Common.Attri;
|
|
using Gameplay.Fight.Flag;
|
|
using Gameplay.Performance;
|
|
using Gameplay.Pool;
|
|
using Gameplay.PostProcess.BlackArea;
|
|
using Gameplay.Skill;
|
|
using Gameplay.Unit.AI;
|
|
using Gameplay.Unit.Data;
|
|
using UnityEngine;
|
|
|
|
namespace Gameplay.Unit
|
|
{
|
|
public class GameUnit : Framework.Wrapper.Unit
|
|
{
|
|
|
|
public bool isReady = false;
|
|
|
|
public readonly EGameUnitType gameunitType;
|
|
|
|
public EAvatarType avatarType
|
|
{
|
|
get;
|
|
protected set;
|
|
}
|
|
|
|
public DebugShowInfo debugShowInfo;
|
|
|
|
public Transform transform
|
|
{
|
|
get
|
|
{
|
|
return _node.transform;
|
|
}
|
|
}
|
|
|
|
public UnitViewData viewData;
|
|
|
|
/// <summary>
|
|
/// 公用数据,或者其他一些不知道放哪的数据
|
|
/// </summary>
|
|
[FightDebug]
|
|
public UnitCommonData commonData;
|
|
|
|
/// <summary>
|
|
/// logic移动相关数据,view层主要与此进行同步
|
|
/// </summary>
|
|
[FightDebug]
|
|
public UnitTransData transData;
|
|
|
|
/// <summary>
|
|
/// 生存相关数据,控制角色的死亡,复活等
|
|
/// </summary>
|
|
[FightDebug]
|
|
public UnitAliveData aliveData;
|
|
|
|
/// <summary>
|
|
/// 战斗相关数据,主要用于公式计算相关
|
|
/// </summary>
|
|
[FightDebug]
|
|
public UnitFightData fightData;
|
|
|
|
/// <summary>
|
|
/// 战斗内的控制数据,主要用于战斗内的逻辑控制
|
|
/// </summary>
|
|
[FightDebug]
|
|
public UnitControlData controlData;
|
|
|
|
/// <summary>
|
|
/// 状态数据,主要用于标识判定
|
|
/// </summary>
|
|
[FightDebug]
|
|
public UnitStatusData statusData
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public bool needRemove;
|
|
|
|
/// <summary>
|
|
/// gameunit的buff管理器
|
|
/// 因为需要通过buff来控制一些属性,所以需要在gameunit中管理buff
|
|
/// </summary>
|
|
public UnitBuffManager buffManager;
|
|
public UnitAIManager aiManager;
|
|
|
|
public DelayMoraleDamage delayMoraleDamage;
|
|
|
|
public GameUnit(uint id,
|
|
int troopId,
|
|
EGameUnitType type) : base(id)
|
|
{
|
|
transData = new UnitTransData(this);
|
|
commonData = new UnitCommonData(this);
|
|
aliveData = new UnitAliveData(this);
|
|
fightData = new UnitFightData(this);
|
|
controlData = new UnitControlData(this);
|
|
statusData = new UnitStatusData(this);
|
|
|
|
aiManager = new UnitAIManager(this);
|
|
delayMoraleDamage = new DelayMoraleDamage(this);
|
|
|
|
avatarType = EAvatarType.Unknown;
|
|
gameunitType = type;
|
|
commonData.troopId = troopId;
|
|
|
|
// 初始化逃跑时间
|
|
fightData.baseRetreateTime = TableManager.Instance.Tables.GlobalConfig.ForceEscapeTime;
|
|
fightData.retreateTime = TableManager.Instance.Tables.GlobalConfig.ForceEscapeTime;
|
|
|
|
}
|
|
|
|
public async UniTask Prepare()
|
|
{
|
|
await _OnPrepare();
|
|
Node.GameObject.SetActive(false);
|
|
}
|
|
|
|
protected virtual async UniTask _OnPrepare()
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// 用于从备战席到战场的初始化
|
|
/// 添加到战场中,并进行ready,此时并没有真正进入战斗
|
|
/// </summary>
|
|
public void Ready()
|
|
{
|
|
Node.GameObject.SetActive(true);
|
|
_OnReady();
|
|
|
|
EventManager.Instance.Send(EventManager.EventName.LevelUnitBorn, this);
|
|
}
|
|
|
|
protected virtual void _OnReady()
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 进入战斗,真正的进入战斗,如果有相关全局技能,则会触发
|
|
/// </summary>
|
|
public void EnterBattle()
|
|
{
|
|
viewData = new UnitViewData(this);
|
|
|
|
_OnEnterBattle();
|
|
|
|
EventManager.Instance.Send(EventManager.EventName.INFIGHT_UNIT_READY, this);
|
|
|
|
// 尝试触发格子buff
|
|
_TriggerBlockBuff();
|
|
}
|
|
|
|
protected virtual void _OnEnterBattle()
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 离开战斗,如果有相关全局技能,则会触发
|
|
/// </summary>
|
|
public void ExitBattle()
|
|
{
|
|
Node.GameObject.SetActive(false);
|
|
_OnExitBattle();
|
|
}
|
|
|
|
protected virtual void _OnExitBattle()
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 回到备战席,通常需要隐藏模型一类的
|
|
/// </summary>
|
|
public void BackPrepare()
|
|
{
|
|
_OnBackPrepare();
|
|
Node.GameObject.SetActive(false);
|
|
}
|
|
|
|
protected virtual void _OnBackPrepare()
|
|
{
|
|
|
|
}
|
|
|
|
public void LogicUpdate(float dt)
|
|
{
|
|
if (controlData.forceUpdateTarget)
|
|
{
|
|
_UpdateTargets();
|
|
}
|
|
_OnLogicUpdate(dt);
|
|
if (statusData.isAIControll)
|
|
{
|
|
aiManager.LogicUpdate(dt);
|
|
}
|
|
_UpdateBlackArea();
|
|
}
|
|
|
|
private void _UpdateBlackArea()
|
|
{
|
|
if (commonData.troopId == ETroopsId.Self)
|
|
{
|
|
return;
|
|
}
|
|
var isInLightArea = BlackAreaManager.instance.CheckIsInLightArea(transData.cellIndex);
|
|
viewData.SetShow(isInLightArea);
|
|
}
|
|
|
|
protected virtual void _OnLogicUpdate(float dt)
|
|
{
|
|
|
|
}
|
|
|
|
public void SetPosAndYaw(int cellIndex,
|
|
float yaw)
|
|
{
|
|
transData.disableEvent = true;
|
|
// 设置数据
|
|
transData.pos = AreaManager.instance.GetCellPosByIndex(cellIndex);
|
|
transData.yaw = yaw;
|
|
// 设置view
|
|
_node.GameObject.transform.position = transData.pos;
|
|
_node.GameObject.transform.eulerAngles = new Vector3(0, yaw, 0);
|
|
transData.disableEvent = false;
|
|
}
|
|
|
|
public void RecoverMorale(int value)
|
|
{
|
|
var finalValue = Mathf.FloorToInt(value * fightData.moraleRecoverScale);
|
|
_OnRecoverMorale(finalValue);
|
|
}
|
|
|
|
protected virtual void _OnRecoverMorale(int value)
|
|
{
|
|
aliveData.currentMorale += value;
|
|
if (aliveData.currentMorale > aliveData.maxMorale)
|
|
{
|
|
aliveData.currentMorale = aliveData.maxMorale;
|
|
}
|
|
}
|
|
|
|
private bool _CheckIsUnbeatble()
|
|
{
|
|
if (SROptions.Current == null) return false;
|
|
var isSelf = commonData.troopId == ETroopsId.Self;
|
|
var isUnbeatable = isSelf ? SROptions.Current.SelfUnbeatable : SROptions.Current.EnemyUnbeatable;
|
|
return isUnbeatable;
|
|
}
|
|
|
|
public void TakeMoraleDamage(int damage,
|
|
GameUnit sender)
|
|
{
|
|
if (_CheckIsUnbeatble())
|
|
{
|
|
return;
|
|
}
|
|
|
|
var baseDamage = damage;
|
|
var damageScale = sender.fightData.moraleDamageScale;
|
|
var beDamageScale = fightData.moraleBeDamageScale;
|
|
var realDamage = Mathf.CeilToInt(baseDamage * damageScale * beDamageScale);
|
|
|
|
// 特殊检查
|
|
var yalishuaijianBuffs = buffManager.GetBuffsByType(EBuffType.SpecialYaLiShuaiJian);
|
|
if (yalishuaijianBuffs.Count != 0)
|
|
{
|
|
// 只去第一个,靠配表保证只有一个
|
|
var yalishuaijianBuff = yalishuaijianBuffs[0] as BuffSpecialYaLiShuaiJian;
|
|
if (yalishuaijianBuff == null)
|
|
{
|
|
DebugUtil.LogError("不应该出现这个错误,说明类型转换出错");
|
|
return;
|
|
}
|
|
var decreaseRate = yalishuaijianBuff.decreasePercent;
|
|
var decreseValue = Mathf.CeilToInt(decreaseRate * realDamage);
|
|
realDamage -= decreseValue;
|
|
|
|
// decrease的伤害,按秒给出去
|
|
delayMoraleDamage.AddSecondsDamage(decreseValue, yalishuaijianBuff.delayTime);
|
|
}
|
|
|
|
_OnTakeMoraleDamage(sender, realDamage);
|
|
}
|
|
|
|
public void DamageMoraleImd(GameUnit sender, int damage)
|
|
{
|
|
var newMorale = aliveData.currentMorale - damage;
|
|
|
|
if (newMorale < 0)
|
|
{
|
|
newMorale = 0;
|
|
}
|
|
|
|
// 死撑检查
|
|
if (statusData.isDeadRetreat && this is Character.Character c)
|
|
{
|
|
var buff = c.buffManager.GetBuffByType(EBuffType.DeadRetreat) as BuffDeadRetreat;
|
|
if (buff == null)
|
|
{
|
|
DebugUtil.LogError("角色身上有死撑状态,但是buff为空");
|
|
return;
|
|
}
|
|
|
|
var retreateValue = c.runtimeData.configData.retreatMorale;
|
|
if (newMorale < retreateValue)
|
|
{
|
|
// 不扣减士气
|
|
// 按系数转为扣血
|
|
var damageRate = buff.morale2DmgRate;
|
|
var damageValue = Mathf.CeilToInt(damage * damageRate);
|
|
_OnTakeNormalDamage(damageValue, sender, false, false);
|
|
return;
|
|
}
|
|
}
|
|
|
|
aliveData.currentMorale = newMorale;
|
|
}
|
|
|
|
protected virtual void _OnTakeMoraleDamage(GameUnit sender, int damage)
|
|
{
|
|
commonData.lastInFightSeconds = LevelManager.Instance.CurrentLevel.LevelTime;
|
|
DamageMoraleImd(sender, damage);
|
|
}
|
|
|
|
public void RecoverShield(int value,
|
|
bool canOverFlow)
|
|
{
|
|
_OnRecoverShield(value, canOverFlow);
|
|
}
|
|
|
|
protected virtual void _OnRecoverShield(int value,
|
|
bool canOverFlow)
|
|
{
|
|
if (canOverFlow)
|
|
{
|
|
aliveData.currentShield += value;
|
|
var maxShiled = aliveData.maxShield + fightData.overflowShiledMaxValue;
|
|
if (aliveData.currentShield > maxShiled)
|
|
{
|
|
aliveData.currentShield = maxShiled;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (aliveData.currentHp < aliveData.maxShield)
|
|
{
|
|
aliveData.currentShield += value;
|
|
var maxShiled = aliveData.maxShield;
|
|
if (aliveData.currentShield > maxShiled)
|
|
{
|
|
aliveData.currentShield = maxShiled;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public void RecoverHp(int value)
|
|
{
|
|
_OnRecoverHp(value);
|
|
}
|
|
|
|
protected virtual void _OnRecoverHp(int value)
|
|
{
|
|
aliveData.currentHp += value;
|
|
if (aliveData.currentHp > aliveData.maxHp)
|
|
{
|
|
aliveData.currentHp = aliveData.maxHp;
|
|
}
|
|
}
|
|
|
|
public void TakeNormalDamage(ObscuredInt damage,
|
|
GameUnit sender,
|
|
bool isCritical)
|
|
{
|
|
|
|
|
|
|
|
statusData.lastAttackUnit = sender;
|
|
commonData.lastInFightSeconds = LevelManager.Instance.CurrentLevel.LevelTime;
|
|
commonData.lastBeHitSeconds = LevelManager.Instance.CurrentLevel.LevelTime;
|
|
|
|
// 通用处理
|
|
var senderLevel = sender.commonData.level;
|
|
if (sender.gameunitType == EGameUnitType.Vehicle)
|
|
{
|
|
// 载具进行攻击时, 等级强制为受击者当前等级
|
|
senderLevel = commonData.level;
|
|
}
|
|
var defense = fightData.defense;
|
|
if (defense < 0)
|
|
{
|
|
defense = 0;
|
|
}
|
|
// 减伤值
|
|
var valueN = GLConfig.Inst.data.FPN;
|
|
var valueK = GLConfig.Inst.data.FPK;
|
|
var preCalc = (senderLevel - commonData.level) * valueN + defense + valueK;
|
|
var reduceValue = 1f;
|
|
if (preCalc > 0)
|
|
{
|
|
reduceValue = defense / preCalc;
|
|
}
|
|
var reduceScaler = 1 - reduceValue;
|
|
var skillRate = sender.fightData.skillRate;
|
|
var scaleForSpecial = 1f;
|
|
switch (gameunitType)
|
|
{
|
|
case EGameUnitType.Character:
|
|
scaleForSpecial = sender.fightData.scaleForHuman;
|
|
break;
|
|
case EGameUnitType.Vehicle:
|
|
scaleForSpecial = sender.fightData.scaleForVehicle;
|
|
break;
|
|
}
|
|
var finalDamageScale = sender.fightData.finalDamageScale;
|
|
var beHitScale = fightData.beDamageScale;
|
|
|
|
var hasShield = aliveData.currentShield > 0;
|
|
|
|
var ignoreRandom = UnityEngine.Random.Range(0, 1f);
|
|
var ignoreShieldRate = sender.fightData.ignoreShieldRate;
|
|
var isignoreShield = ignoreRandom < ignoreShieldRate;
|
|
if (isignoreShield)
|
|
{
|
|
hasShield = false;
|
|
}
|
|
|
|
var scaleAttack = hasShield ? sender.fightData.attackScaleForShiled : sender.fightData.attackScaleForHp;
|
|
|
|
var realDamage = Mathf.CeilToInt(damage * skillRate * reduceScaler * scaleAttack * scaleForSpecial * finalDamageScale * beHitScale);
|
|
|
|
realDamage += fightData.extraDamageOnNormalAttack;
|
|
|
|
if (realDamage < 1)
|
|
{
|
|
realDamage = 1;
|
|
}
|
|
|
|
if (DebugUtil.LogEnable)
|
|
{
|
|
DebugUtil.Log($"{sender.GetDescString()} 对 {GetDescString()} 造成了 {damage} 伤害 实际伤害为 {realDamage} 是否暴击 {isCritical} 是否无视护盾 {isignoreShield}");
|
|
}
|
|
|
|
_OnTakeNormalDamage(realDamage, sender, isCritical, isignoreShield);
|
|
}
|
|
|
|
protected virtual void _OnTakeNormalDamage(ObscuredInt realDamage,
|
|
GameUnit sender,
|
|
bool isCritical,
|
|
bool ignoreShield)
|
|
{
|
|
if (!PerformanceManager.instance.data.disableFloatDamage)
|
|
{
|
|
var data = ObjPoolManager.instance.Get<EventDataGetDamaged>();
|
|
data.sender = sender;
|
|
data.owner = this;
|
|
data.damage = realDamage;
|
|
data.isCritical = isCritical;
|
|
EventManager.Instance.Send(EventManager.EventName.INFIGHT_GET_DAMAGED, data);
|
|
ObjPoolManager.instance.Return(data);
|
|
}
|
|
|
|
if (aliveData.currentShield > 0 && !ignoreShield)
|
|
{
|
|
if (aliveData.currentShield >= realDamage)
|
|
{
|
|
if (_CheckIsUnbeatble())
|
|
{
|
|
return;
|
|
}
|
|
aliveData.currentShield -= realDamage;
|
|
|
|
if (debugShowInfo.cacheConfigId != 0)
|
|
{
|
|
EventManager.Instance.Send(EventManager.EventName.INFIGHT_AUDIO_BE_ATTACK_AND_HAS_SHEILD, debugShowInfo.cacheConfigId);
|
|
}
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
|
|
if (_CheckIsUnbeatble())
|
|
{
|
|
return;
|
|
}
|
|
realDamage -= aliveData.currentShield;
|
|
aliveData.currentShield = 0;
|
|
|
|
|
|
var isDead = _DamageHP(realDamage);
|
|
if (isDead)
|
|
{
|
|
sender.buffManager.TriggerKillUnit(this);
|
|
}
|
|
else
|
|
{
|
|
if (debugShowInfo.cacheConfigId != 0)
|
|
{
|
|
EventManager.Instance.Send(EventManager.EventName.INFIGHT_AUDIO_BE_ATTACK_AND_NO_SHEILD, debugShowInfo.cacheConfigId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
var isDead = _DamageHP(realDamage);
|
|
if (isDead)
|
|
{
|
|
sender.buffManager.TriggerKillUnit(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool _DamageHP(int damage)
|
|
{
|
|
if (_CheckIsUnbeatble())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
aliveData.currentHp -= damage;
|
|
if (aliveData.currentHp <= 0)
|
|
{
|
|
aliveData.currentHp = 0;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public void OnSelect()
|
|
{
|
|
if (DebugUtil.LogEnable)
|
|
DebugUtil.Log("Select: ----- GameUnit : {0}", GetID());
|
|
|
|
_OnSelect();
|
|
EventManager.Instance.Send(EventManager.EventName.LevelUnitSelect, this);
|
|
}
|
|
|
|
protected virtual void _OnSelect()
|
|
{
|
|
SelecterView.Instance.SetSelectAndTarget(Node, null);
|
|
}
|
|
|
|
public void OnUnSelect()
|
|
{
|
|
if (DebugUtil.LogEnable)
|
|
DebugUtil.Log("UnSelect ---- GameUnit: {0}", GetID());
|
|
|
|
_OnUnSelect();
|
|
EventManager.Instance.Send(EventManager.EventName.LevelUnitUnSelect, this);
|
|
}
|
|
|
|
protected virtual void _OnUnSelect()
|
|
{
|
|
SelecterView.Instance.UnSelect(Node);
|
|
}
|
|
|
|
public void MoveAway(GameUnit unit)
|
|
{
|
|
Vector2Int targetPos;
|
|
var map = LevelManager.Instance.CurrentLevel.Map;
|
|
map.WorldPosition2BlockPosition(unit.Node.GetPosition(), out targetPos);
|
|
var selfPos = map.TGSCellIndex2BlockPosition(transData.cellIndex);
|
|
selfPos.x = Math.Clamp((selfPos.x - targetPos.x) > 0 ? selfPos.x + 1 : selfPos.x - 1, 0, map.MapData.Height - 1);
|
|
selfPos.y = Math.Clamp((selfPos.y - targetPos.y) > 0 ? selfPos.y + 1 : selfPos.y - 1, 0, map.MapData.Width - 1);
|
|
|
|
MoveTo(map.BlockPosition2TGSCellIndex(selfPos), true);
|
|
}
|
|
|
|
public void MoveTo(GameUnit unit)
|
|
{
|
|
if (unit == null)
|
|
{
|
|
DebugUtil.LogError("moveto的对象为空");
|
|
return;
|
|
}
|
|
controlData.followUnit = unit;
|
|
|
|
if (LevelManager.Instance.CurrentLevel.selectUnit == this)
|
|
{
|
|
EventManager.Instance.Send(EventManager.EventName.INFIGHT_OP_SET_TARGET);
|
|
}
|
|
|
|
// 这里需要判定是否是敌方
|
|
// 如果是敌方,且在攻击范围内,则直接切换攻击目标
|
|
if (unit.commonData.troopId != commonData.troopId)
|
|
{
|
|
var cellIndex = unit.transData.cellIndex;
|
|
var selfCellIndex = transData.cellIndex;
|
|
var distance = AreaManager.instance.GetDistance(selfCellIndex, cellIndex);
|
|
if (distance <= fightData.attackDistance)
|
|
{
|
|
// 在攻击范围内,直接切换攻击目标
|
|
controlData.targetEnemy = unit;
|
|
return;
|
|
}
|
|
}
|
|
|
|
MoveTo(unit.transData.cellIndex, false);
|
|
}
|
|
|
|
public void MoveTo(int cellIndex,
|
|
bool cancelFollow)
|
|
{
|
|
if (cancelFollow)
|
|
{
|
|
controlData.followUnit = null;
|
|
}
|
|
|
|
var map = LevelManager.Instance.CurrentLevel.Map;
|
|
if (map == null) return;
|
|
|
|
controlData.targetCellIndex = cellIndex;
|
|
|
|
if (LevelManager.Instance.CurrentLevel.selectUnit == this)
|
|
{
|
|
var wrapCellPos = map.TGSCellIndex2WorldPosition(cellIndex);
|
|
SelecterView.Instance.SetSelectAndTarget(Node, new SelecterView.TargetInfo()
|
|
{
|
|
pos = wrapCellPos
|
|
});
|
|
|
|
EventManager.Instance.Send(EventManager.EventName.INFIGHT_OP_SET_MOVEPOS);
|
|
}
|
|
}
|
|
|
|
|
|
public void StopToCurrentCell()
|
|
{
|
|
controlData.targetCellIndex = transData.cellIndex;
|
|
controlData.followUnit = null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 该方法仅由skillhandle进行调用
|
|
/// </summary>
|
|
/// <param name="cellIndex"></param>
|
|
/// <param name="skillHandle"></param>
|
|
public void _UseSkill(int cellIndex,
|
|
SkillHandle skillHandle)
|
|
{
|
|
//test
|
|
// PlayAudio();
|
|
_OnUseSkill(cellIndex, skillHandle);
|
|
}
|
|
|
|
private async void PlayAudio()
|
|
{
|
|
await AudioManager.Instance.PlayAudio("DemoProj_S1");
|
|
}
|
|
|
|
protected virtual void _OnUseSkill(int cellIndex,
|
|
SkillHandle skillHandle)
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// AI自动使用技能
|
|
/// </summary>
|
|
public void AITryUseSkill()
|
|
{
|
|
}
|
|
|
|
public ViewBullet EmitSkillBullet(int bulletId,
|
|
GameUnit targetUnit,
|
|
SkillHandle skillHandle)
|
|
{
|
|
commonData.lastInFightSeconds = LevelManager.Instance.CurrentLevel.LevelTime;
|
|
|
|
var bullet = BulletManager.instance.EmitBullet(bulletId, targetUnit, skillHandle.owner);
|
|
if (bullet != null)
|
|
{
|
|
if (statusData.needSkillPaused)
|
|
{
|
|
SkillManager.instance.screenEffect.AttachObj(bullet.rootObj);
|
|
}
|
|
}
|
|
|
|
return bullet;
|
|
|
|
}
|
|
|
|
public ViewBullet EmitSkillBullet(int bulletId,
|
|
int targetCellIndex,
|
|
SkillHandle skillHandle)
|
|
{
|
|
commonData.lastInFightSeconds = LevelManager.Instance.CurrentLevel.LevelTime;
|
|
|
|
var bullet = BulletManager.instance.EmitBullet(bulletId, targetCellIndex, skillHandle.owner);
|
|
if (bullet != null)
|
|
{
|
|
if (statusData.needSkillPaused)
|
|
{
|
|
SkillManager.instance.screenEffect.AttachObj(bullet.rootObj);
|
|
}
|
|
}
|
|
|
|
return bullet;
|
|
|
|
}
|
|
|
|
public void UpdateTargets()
|
|
{
|
|
_UpdateTargets();
|
|
controlData.forceUpdateTarget = false;
|
|
}
|
|
|
|
protected virtual void _UpdateTargets()
|
|
{
|
|
|
|
}
|
|
|
|
public void TriggerCellIndexChange()
|
|
{
|
|
if (buffManager == null)
|
|
{
|
|
// 说明还没有初始化
|
|
return;
|
|
}
|
|
// 先触发已有buff
|
|
buffManager.TriggerCellIndexChange();
|
|
// 再判定格子是否有需要添加的buff
|
|
|
|
_TriggerBlockBuff();
|
|
_TriggerPickFlag();
|
|
}
|
|
|
|
private void _TriggerPickFlag()
|
|
{
|
|
if (statusData.isHoldFlag) return;
|
|
if (!statusData.CheckCanPickFlag()) return;
|
|
var pickFlag = FlagManager.instance.PickFlag(transData.cellIndex);
|
|
if (pickFlag == null)
|
|
{
|
|
return;
|
|
}
|
|
pickFlag.Dispose();
|
|
buffManager.AddBuffById(CodeDefine.HOLD_FLAG_BUFF_ID);
|
|
}
|
|
|
|
private void _TriggerBlockBuff()
|
|
{
|
|
if (buffManager == null)
|
|
{
|
|
return;
|
|
}
|
|
// 移除旧的
|
|
_TriggerRemoveBlockBuff();
|
|
|
|
// 添加新的
|
|
_TriggerAddBlockBuff();
|
|
}
|
|
|
|
private void _TriggerRemoveBlockBuff()
|
|
{
|
|
// -1 的时候 直接返回
|
|
if (transData.lastCellIndex == -1) return;
|
|
var oldBlockData = LevelManager.Instance.CurrentLevel.Map.GetBlockData(transData.lastCellIndex);
|
|
if (oldBlockData == null)
|
|
{
|
|
DebugUtil.LogError("CellIndexChange中的BlockData为空,cellIndex:{0}", transData.lastCellIndex);
|
|
return;
|
|
}
|
|
var blockProperty = oldBlockData.GetTerrainTypeProperty();
|
|
if (blockProperty == null)
|
|
{
|
|
DebugUtil.LogError("CellIndexChange中的BlockProperty为空,cellIndex:{0}", transData.lastCellIndex);
|
|
return;
|
|
}
|
|
|
|
if (!blockProperty.AddBuff)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var buffIds = blockProperty.buffIds;
|
|
if (buffIds == null) return;
|
|
for (var i = 0; i < buffIds.Length; ++i)
|
|
{
|
|
var buffId = buffIds[i];
|
|
buffManager.RemoveBuffById(buffId);
|
|
}
|
|
}
|
|
|
|
|
|
private void _TriggerAddBlockBuff()
|
|
{
|
|
var blockData = LevelManager.Instance.CurrentLevel.Map.GetBlockData(transData.cellIndex);
|
|
if (blockData == null)
|
|
{
|
|
DebugUtil.LogError("CellIndexChange中的BlockData为空,cellIndex:{0}", transData.cellIndex);
|
|
return;
|
|
}
|
|
var blockProperty = blockData.GetTerrainTypeProperty();
|
|
if (blockProperty == null)
|
|
{
|
|
DebugUtil.LogError("CellIndexChange中的BlockProperty为空,cellIndex:{0}", transData.cellIndex);
|
|
return;
|
|
}
|
|
if (!blockProperty.AddBuff)
|
|
{
|
|
return;
|
|
}
|
|
var buffIds = blockProperty.buffIds;
|
|
if (buffIds == null) return;
|
|
for (var i = 0; i < buffIds.Length; ++i)
|
|
{
|
|
var buffId = buffIds[i];
|
|
buffManager.AddBuffById(buffId);
|
|
}
|
|
}
|
|
|
|
public virtual string GetDescString()
|
|
{
|
|
return "";
|
|
}
|
|
|
|
}
|
|
}
|