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; /// /// 公用数据,或者其他一些不知道放哪的数据 /// [FightDebug] public UnitCommonData commonData; /// /// logic移动相关数据,view层主要与此进行同步 /// [FightDebug] public UnitTransData transData; /// /// 生存相关数据,控制角色的死亡,复活等 /// [FightDebug] public UnitAliveData aliveData; /// /// 战斗相关数据,主要用于公式计算相关 /// [FightDebug] public UnitFightData fightData { get; private set; } /// /// 战斗内的控制数据,主要用于战斗内的逻辑控制 /// [FightDebug] public UnitControlData controlData; /// /// 状态数据,主要用于标识判定 /// [FightDebug] public UnitStatusData statusData { get; set; } public bool needRemove; /// /// gameunit的buff管理器 /// 因为需要通过buff来控制一些属性,所以需要在gameunit中管理buff /// 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() { } /// /// 用于从备战席到战场的初始化 /// 添加到战场中,并进行ready,此时并没有真正进入战斗 /// public void Ready() { Node.GameObject.SetActive(true); _OnReady(); EventManager.Instance.Send(EventManager.EventName.LevelUnitBorn, this); } protected virtual void _OnReady() { } /// /// 进入战斗,真正的进入战斗,如果有相关全局技能,则会触发 /// public void EnterBattle() { viewData = new UnitViewData(this); _OnEnterBattle(); EventManager.Instance.Send(EventManager.EventName.INFIGHT_UNIT_READY, this); // 尝试触发格子buff _TriggerBlockBuff(); } protected virtual void _OnEnterBattle() { } /// /// 离开战斗,如果有相关全局技能,则会触发 /// public void ExitBattle() { Node.GameObject.SetActive(false); _OnExitBattle(); } protected virtual void _OnExitBattle() { } /// /// 回到备战席,通常需要隐藏模型一类的 /// 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(); 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 (buffManager != null) { buffManager.TriggerOnTakeDamage(); } fightData.hurtAccumulate += realDamage; 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) { if (unit.statusData.CheckCanBeTarget(this)) { // 在攻击范围内,直接切换攻击目标 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; } /// /// 该方法仅由skillhandle进行调用 /// /// /// public void _UseSkill(int cellIndex, SkillHandle skillHandle) { //test // PlayAudio(); _OnUseSkill(cellIndex, skillHandle); } protected virtual void _OnUseSkill(int cellIndex, SkillHandle skillHandle) { } /// /// AI自动使用技能 /// 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 ""; } } }