/* * @Author: 白哉 * @Description: * @Date: 2025年04月03日 星期四 11:04:31 * @Modify: */ using System; using System.Collections.Generic; using Logic.CrashSight; using Logic.Skill; using MemoryPack; using TH1_Logic.Core; using TH1_Logic.HeroTask; using TH1Renderer; using Unity.VisualScripting; using UnityEngine; namespace RuntimeData { // 地图上所有的小兵数据 [MemoryPackable] public partial class UnitMapData { public List UnitList; [MemoryPackIgnore] public bool UnitMapRenderMark; private Dictionary _unitDict; [MemoryPackConstructor] public UnitMapData() { UnitList = new List(); _unitDict = new Dictionary(); UnitMapRenderMark = true; } public UnitMapData(UnitMapData copyData) { UnitList = new List(); _unitDict = new Dictionary(); foreach (var unitData in copyData.UnitList) { var newUnitData = new UnitData(unitData); UnitList.Add(newUnitData); _unitDict[newUnitData.Id] = newUnitData; } } // MemoryPack 反序列化之后的后处理 [MemoryPackOnDeserialized] public void OnAfterMemoryPackDeserialize() { _unitDict ??= new Dictionary(); _unitDict.Clear(); foreach (var unit in UnitList) _unitDict[unit.Id] = unit; } public void DeepCopy(UnitMapData copyData) { _unitDict.Clear(); for (int i = 0; i < copyData.UnitList.Count; i++) { var copyUnit = copyData.UnitList[i]; if (i >= UnitList.Count) { var unit = new UnitData(copyUnit); UnitList.Add(unit); _unitDict[unit.Id] = unit; } else { UnitList[i].DeepCopy(copyUnit); _unitDict[UnitList[i].Id] = UnitList[i]; } } for (int i = UnitList.Count - 1; i >= copyData.UnitList.Count; i--) { _unitDict.Remove(UnitList[i].Id); UnitList.RemoveAt(i); } } public void OnTurnStart(MapData map, PlayerData player) { var units = new HashSet(); map.GetUnitDataListByPlayerId(player.Id, units); foreach (var unit in units) { Main.UnitLogic.StartNextTurn(map, unit); unit.OnTurnStart(map); } } public void OnTurnEnd(MapData map, PlayerData player) { var units = new HashSet(); map.GetUnitDataListByPlayerId(player.Id, units); foreach (var unit in units) { Main.UnitLogic.UnitEndTurn(map, unit); unit.OnTurnEnd(map); } } // 新建小兵 public UnitData AddUnitData(UnitType unitType,GiantType giantType,uint unitLevel, MapIdGenerator idGenerator) { var unit = new UnitData(unitType, giantType,unitLevel ,idGenerator); UnitList.Add(unit); _unitDict[unit.Id] = unit; return unit; } // 删除小兵 public void RemoveUnitData(uint unitId) { if (_unitDict.TryGetValue(unitId, out var unitData)) { UnitList.Remove(unitData); _unitDict.Remove(unitId); } } // 通过 uid 找小兵数据 unitData public bool GetUnitDataByUnitId(uint unitId, out UnitData unitData) { return _unitDict.TryGetValue(unitId, out unitData); } } [Serializable] public struct UnitFullType : IEquatable { public UnitType UnitType; public GiantType GiantType; public uint UnitLevel; public UnitFullType(UnitType unitType, GiantType giantType, uint level) { UnitType = unitType; GiantType = giantType; UnitLevel = level; } public bool Equals(UnitFullType other) { return UnitType == other.UnitType && GiantType == other.GiantType && UnitLevel == other.UnitLevel; } public override bool Equals(object obj) { return obj is UnitFullType other && Equals(other); } public override int GetHashCode() { return HashCode.Combine((int)UnitType, (int)GiantType, UnitLevel); } } //小兵数据 [MemoryPackable] public partial class UnitData : IdentifierBase { // 是否存活 public bool Alive; //单位类型 public UnitFullType UnitFullType; // 单位类型(legacy) public UnitType UnitType ; public GiantType GiantType; public uint UnitLevel; //棋子种类 public ChessType ChessType; //TODO 将来要彻底干掉legacy单位类型 public UnitFullType GetUnitFullType => new UnitFullType {UnitType = UnitType,GiantType = GiantType,UnitLevel = UnitLevel }; // 血量 public int Health; // move points,行动值 public int MP; // attack points,攻击值 public int AP; // capture city points, 城市行动值,用来占领或者建设城市 public int CP; // 攻击范围 //public int AttackRange; // 移动范围 //public int MoveRange; // 经验值 public int Exp; //英雄经验值 public int GiantExp; //是否老兵 public bool Veteran; //存储carry的UnitType public UnitType CarryUnitType; public GiantType CarryGiantType; public uint CarryUnitLevel; //存储carry的exp状态 public int CarryExp; //存储carry的Veteran状态 public bool CarryVeteran; // 防御削减系数 public float DefenseReduction; // 军团编号 public uint LegionId; //Attack信息的RenderMakr [MemoryPackIgnore] public bool AttackRenderMark; [MemoryPackIgnore] public Vector3 AttackRenderMarkTargetPos; [MemoryPackIgnore] public bool AttackRenderMarkNeedBack; [MemoryPackIgnore] public AttackAnimType AttackRenderMarkAttackAnimType; [MemoryPackIgnore] public bool BounceRenderMark; [MemoryPackIgnore] public float BounceRenderMakrWaitTime; public PlayerData Player(MapData map) { map.GetPlayerDataByUnitId(this.Id, out var player); return player; } public CityData City(MapData map) { map.GetCityDataByUnitId(this.Id, out var city); return city; } public GridData Grid(MapData map) { map.GetGridDataByUnitId(Id, out var grid); return grid; } public HeroTaskContentBase HeroTask(MapData map) { HeroTaskContentBase heroTask = null; Player(map)?.PlayerHeroData.HeroTaskDict.TryGetValue(GetUnitFullType,out heroTask); return heroTask; } //获取最大血量 public int GetMaxHealth() { if (!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType,UnitLevel, out var unitTypeInfo)) return 0; if (unitTypeInfo.NoMaxHealth) { if (CarryUnitType != UnitType.None) { if(Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(CarryUnitType, CarryGiantType,CarryUnitLevel,out var carryUnitTypeInfo)) return carryUnitTypeInfo.MaxHealth + (CarryVeteran?5:0); return 0; } return 0; } else return unitTypeInfo.MaxHealth + (Veteran?5:0); } //获取画面的位置 public Vector3 GetPosition(MapData map) { if (map != Main.MapData) return Vector3.zero; var t = MapRenderer.Instance.ROUnitMap[Id]; if(t == null)return Vector3.zero; return t.GetPosition(); } // 获取血量百分比 public float GetHealthRatio() { return (float)Health / GetMaxHealth(); } // 获取军事分 public float GetMilitary() { if (!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType,UnitLevel, out var info)) return 0; //如果是英雄,要单独结算,按照英雄的不同等级定价结算 if (UnitType == UnitType.Giant) return UnitLevel switch { 0 => 10, 1 => 10, 2 => 15, 3 => 25, _ => 0 }; //如果生命值低于50%,得分打8折 if (GetHealthRatio() <= 0.5f) return info.Cost * 0.8f; return info.Cost; } // 获取造价 public float GetCost() { if (!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType,UnitLevel, out var info)) return 0; return info.Cost; } [MemoryPackConstructor] public UnitData() { } //注意,这里没有处理unit Copy之后,skill要触发skillAdd生命周期的情况 public UnitData(UnitData copyData) { Id = copyData.Id; Alive = copyData.Alive; UnitType = copyData.UnitType; GiantType = copyData.GiantType; UnitLevel = copyData.UnitLevel; Health = copyData.Health; MP = copyData.MP; AP = copyData.AP; CP = copyData.CP; //AttackRange = copyData.AttackRange; //MoveRange = copyData.MoveRange; Exp = copyData.Exp; GiantExp = copyData.GiantExp; Veteran = copyData.Veteran; CarryUnitType = copyData.CarryUnitType; CarryGiantType = copyData.CarryGiantType; CarryUnitLevel = copyData.CarryUnitLevel; CarryVeteran = copyData.CarryVeteran; CarryExp = copyData.CarryExp; LegionId = copyData.LegionId; CarryVeteran = copyData.CarryVeteran; DefenseReduction = copyData.DefenseReduction; foreach (var skill in copyData.Skills) Skills.Add(skill.GetCopySkill()); } //注意,这里没有处理unit Copy之后,skill要触发skillAdd生命周期的情况 public void DeepCopy(UnitData copyData) { Id = copyData.Id; Alive = copyData.Alive; UnitType = copyData.UnitType; GiantType = copyData.GiantType; UnitLevel = copyData.UnitLevel; ChessType = copyData.ChessType; Health = copyData.Health; MP = copyData.MP; AP = copyData.AP; CP = copyData.CP; //AttackRange = copyData.AttackRange; //MoveRange = copyData.MoveRange; Exp = copyData.Exp; GiantExp = copyData.GiantExp; Veteran = copyData.Veteran; CarryUnitType = copyData.CarryUnitType; CarryGiantType = copyData.CarryGiantType; CarryExp = copyData.CarryExp; CarryUnitLevel = copyData.CarryUnitLevel; CarryVeteran = copyData.CarryVeteran; LegionId = copyData.LegionId; CarryVeteran = copyData.CarryVeteran; DefenseReduction = copyData.DefenseReduction; foreach (var skill in copyData.Skills) { AddSkill(skill.GetSkillType()); if (!GetSkill(skill.GetSkillType(), out var selfSkill)) continue; selfSkill.DeepCopy(skill); } for (int i = Skills.Count - 1; i >= 0; i--) { if (copyData.GetSkill(Skills[i].GetSkillType(), out _)) continue; Skills.RemoveAt(i); } } // 无参数初始化 public UnitData(UnitType unitType,GiantType giantType,uint unitLevel, MapIdGenerator idGenerator) { Id = idGenerator.GeneratorId(); UnitType = unitType; GiantType = giantType; UnitLevel = unitLevel; InitData(); } public void InitData() { if (Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType,UnitLevel, out var unitTypeInfo) && unitTypeInfo.NoMaxHealth) { //TODO 目前 nomaxhealth和carry不是一个概念 CarryUnitType = UnitType.Warrior; } Alive = true; Health = GetMaxHealth(); ChessType = unitTypeInfo.ChessType; MP = 0; AP = 0; CP = 0; //AttackRange = Table.Instance.QueryUnitAttackRange(UnitType); //MoveRange = Table.Instance.QueryUnitMoveRange(UnitType); Exp = 0; GiantExp = 0; Veteran = false; LegionId = 0; } // 全局通知调用 public void OnTurnStart(MapData map) { for (int i = Skills.Count - 1; i >= 0; i--) { var skill = Skills[i]; if (skill.IsFinished()) { skill.OnFinished(this, map); Skills.RemoveAt(i); continue; } skill.OnTurnStart(this, map); } } public void OnTurnEnd(MapData map) { foreach (var skill in Skills)skill.OnTurnEnd(this, map); AP = 0; CP = 0; MP = 0; } //返回该unit的视野半径 public int GetSightRange(MapData map) { int v = 1; foreach (var skill in Skills) v += skill.GetExtraSight(this,map); if (map.GetGridDataByUnitId(this.Id, out var grid) && grid.Feature == TerrainFeature.Mountain) v = Mathf.Max(v, 2); return v; } public int GetAttackRange() { var attackRange = 0; foreach (var skill in Skills) { attackRange += skill.GetExtraAttackRange(this); } attackRange += Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType, UnitLevel, out var info) ? info.AttackRange : 0; return attackRange; } public int GetMoveRange() { if (!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType, UnitLevel, out var info)) return 0; var moveRange = info.MoveRange; foreach (var skill in Skills) { moveRange += skill.GetExtraMoveRange(this); } return moveRange; } //返回该unit是否是静止经验(无法升级) public bool CheckIsStaticExp(MapData map) { var isStaticExp = false; foreach (var skill in Skills) { if (skill.IsLimitSelfExp(this, map)) isStaticExp = true; } return isStaticExp; } //返回该unit处于城市的时候是否获得防御加成 public bool CheckIsCityDefenseBuff() { return GetSkill(SkillType.FORTIFY,out var _); } //LandAndPort, WaterAndAshore, LandAndWater, WaterOnly, LandOnly, Fly public LandType GetLandType() { return Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType,GiantType,UnitLevel,out var Info)?Info.LandType:LandType.None; } // 获得总攻击力的string显示 public string GetAttackShowString(MapData map) { if(!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType,UnitLevel, out var info)) return "0"; float extra = GetExtraAttack(map); if (extra == 1f) return info.Attack.ToString(); return info.Attack + "(×" + extra + ")"; } // 获得总攻击力 public float GetAttackValue(MapData map, UnitData target=null) { if(!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType,UnitLevel, out var info)) return 0; if (IsCriticalHitRate(map)) return info.Attack * GetExtraAttack(map) * 2; var value = info.Attack * GetExtraAttack(map); if (target != null) { var attackOffsetValue = GetAttackerValueOffset(map,target); if (GetSkill(SkillType.EIRINFRENCHBUFF, out var _) && target.GetUnitFullType.UnitType == UnitType.Giant) attackOffsetValue *= 2; value += attackOffsetValue; } return value * GetAllExtraAttack(map); } // 获取总防御力的string显示 public string GetDefenseShowString(MapData map) { if(!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType,UnitLevel, out var info)) return "0"; float extra = GetExtraDefense(map); if (extra == 1f) return info.Defense.ToString(); return info.Defense + "(×" + extra + ")"; } // 获取总防御力 public float GetDefenseValue(MapData map, UnitData origin=null) { if(!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType,UnitLevel, out var info)) return 0; var value = info.Defense * GetExtraDefense(map); if (origin != null) value += origin.GetDefenderValueOffset(map,origin); return value; } // 获取防御倍数 public float GetExtraDefense(MapData map) { var extraDefense = 1f; foreach (var skill in Skills) { extraDefense *= skill.GetExtraDefense(this, map); } if (!map.GetGridDataByUnitId(Id, out var grid) || !map.GetPlayerDataByUnitId(Id, out var unitPlayer)) { LogSystem.LogError("UnitData GetExtraDefense Cant find grid or player by uid"); return extraDefense; } //如果是中立土地 if (!map.GetPlayerDataByTerritoryGridId(grid.Id, out var gridPlayer)) { return extraDefense; } //如果不是盟友土地 if(!map.SameUnion(unitPlayer.Id,gridPlayer.Id)) return extraDefense; if (grid.Resource == ResourceType.NavalBase || grid.Resource == ResourceType.Military) extraDefense *= 1.5f; return extraDefense; } // 获取攻击倍数 public float GetExtraAttack(MapData map) { var extraAttack = 1f; foreach (var skill in Skills) extraAttack *= skill.GetExtraAttack(this, map); return extraAttack; } // 获取总攻击倍数 public float GetAllExtraAttack(MapData map) { var extraAttack = 1f; foreach (var skill in Skills) extraAttack *= skill.GetAllExtraAttack(this, map); return extraAttack; } // 获取暴击率 public float GetCriticalHitRate(MapData map) { var criticalHitRate = 0f; foreach (var skill in Skills) criticalHitRate += skill.GetCriticalHitRate(this, map); return criticalHitRate; } // 受攻击时给对方的攻击力偏移 public float GetAttackerValueOffset(MapData mapData,UnitData target) { var value = 0f; foreach (var skill in Skills) value += skill.GetAttackerValueOffset(mapData,target); return value; } // 攻击时给对方的防御力偏移 public float GetDefenderValueOffset(MapData mapData,UnitData origin) { var value = 0f; foreach (var skill in Skills) value += skill.GetDefenderValueOffset(mapData,origin); return value; } // 是否能移动到伟人身周 public bool IsCanMoveGiantNearbyGrid(MapData map) { foreach (var skill in Skills) { if (skill.IsCanMoveGiantNearbyGrid(this, map)) return true; } return false; } // 是否拥有特别伤害技能,例如ROYALFLAME public bool IsHasAttackSkill(MapData map) { return false; } // 是否能移动无人城市 public bool IsCanMoveNoUnitSelfCity(MapData map) { foreach (var skill in Skills) { if (skill.IsCanMoveToNoUnitSelfCity(this, map)) return true; } return false; } // 是否可以死亡 public bool CanBeKilled(MapData map) { foreach (var skill in Skills) { if (!skill.IsCanBeKill(this, map)) return false; } return true; } // 是否可以被伤害结算 public bool CanBeDamaged(MapData map, int dmg) { foreach (var skill in Skills) { if (skill.IsCanBeDamaged(this, map, dmg)) return true; } return false; } // 是否经验锁定 public bool IsExpLock(MapData map) { foreach (var skill in Skills) { if (skill.IsLimitSelfExp(this, map)) return true; } return false; } //返回该unit是否能在terrain上移动 public bool IsCanMoveOnTerrain(MapData map, TerrainType terrainType) { var landType = GetLandType(); if (terrainType == TerrainType.Land && (landType == LandType.LandAndPort || landType == LandType.LandOnly || landType == LandType.LandAndWater || landType == LandType.Fly)) return true; if (terrainType == TerrainType.ShallowSea && (landType == LandType.WaterAndAshore || landType == LandType.WaterOnly || landType == LandType.LandAndWater || landType == LandType.Fly)) return true; foreach (var skill in Skills) { if (skill.IsCanMoveOnTerrain(this, map, terrainType)) return true; } return false; } //返回该unit是否能在feature上移动 public bool IsCanMoveOnFeature(MapData map, TerrainFeature featureType) { if (featureType != TerrainFeature.Mountain) return true; foreach (var skill in Skills) { if (skill.IsCanMoveOnFeature(this, map,featureType)) return true; } return false; } //返回该unit是否能攻击 public bool IsLimitSelfAttack(MapData map) { foreach (var skill in Skills) { if (skill.IsLimitSelfAttack(this, map)) return true; } return false; } //返回该unit是否能反击 public bool IsLimitSelfCounterAttack(MapData map) { foreach (var skill in Skills) { if (skill.IsLimitSelfCounterAttack(this, map)) return true; } return false; } //返回目标 unit 是否能反击 public bool IsLimitTargetCounterAttack(MapData map) { foreach (var skill in Skills) { if (skill.IsLimitTargetCounterAttack(this, map)) return true; } return false; } // 是否能暴击 private bool IsCriticalHitRate(MapData map) { return map.Net.GetRandom().NextDouble() <= GetCriticalHitRate(map); } // 移动后的变化 public void OnMove(MapData map, GridData target, MoveType moveType) { foreach (var skill in Skills) skill.OnMove(this, target, map,moveType); } //获取自身占据的population数额 public int GetPopulation() { if (GetSkill(SkillType.NOPOPULATION, out var _)) return 0; return 1; } //------------------------------------------------- 对unitData的基础操作 ---------------------------------------------- //清空 AP Cp MP public void ClearAPMPCP() { AP = 0; MP = 0; CP = 0; } public void SetFullAPCPMP() { AP = 1; MP = 1; CP = 1; } public int AddHealth(int hp) { var offset = Math.Min(GetMaxHealth() - Health, hp); Health += offset; return offset; } } }