/* * @Author: 白哉 * @Description: * @Date: 2025年04月03日 星期四 11:04:31 * @Modify: */ using System; using System.Collections.Generic; using Logic.CrashSight; using Logic.Skill; using Unity.VisualScripting; using UnityEngine; namespace RuntimeData { // 地图上所有的小兵数据 [Serializable] public class UnitMapData : ISerializationCallbackReceiver { public List UnitList; public Dictionary _unitDict; public bool UnitMapRenderMark; 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; } } 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 OnBeforeSerialize() { } public void OnAfterDeserialize() { _unitDict ??= new Dictionary(); _unitDict.Clear(); foreach (var unit in UnitList) _unitDict[unit.Id] = unit; } public void OnTurnStart(MapData map, PlayerData player) { var units = new HashSet(); map.GetUnitDataListByPlayerId(player.Id, units); foreach (var unit in units) unit.OnTurnStart(map); } public void OnTurnEnd(MapData map, PlayerData player) { var units = new HashSet(); map.GetUnitDataListByPlayerId(player.Id, units); foreach (var unit in units) 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 class UnitData : IdentifierBase { private static System.Random _random; // 是否存活 public bool Alive; // 单位类型 public UnitType UnitType; public GiantType GiantType; public uint UnitLevel; //棋子种类 public ChessType ChessType; // 血量 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; //Attack信息的RenderMakr public bool AttackRenderMark; public Vector3 AttackRenderMarkTargetPos; public bool AttackRenderMarkNeedBack; public AttackAnimType AttackRenderMarkAttackAnimType; public bool BounceRenderMark; public float BounceRenderMakrWaitTime; // 军团编号 public uint LegionId; //获取最大血量 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 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 => 8, 1 => 11, 2 => 13, 3 => 15, 4 => 20, 5 => 30, _ => 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; } public UnitData() { InitData(); } 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()); } 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()) { 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() { if(GetSkill(SkillType.SCOUT,out var _)) return 2; return 1; } public int GetAttackRange() { return Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType,GiantType,UnitLevel,out var info)?info.AttackRange:0; } public int GetMoveRange() { return Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType,GiantType,UnitLevel,out var info)?info.MoveRange:0; } //返回该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) { if(!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType,UnitLevel, out var info)) return 0; if (IsCriticalHitRate(map)) return info.Attack * GetExtraAttack(map) * 2; return info.Attack * GetExtraAttack(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) { if(!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType,UnitLevel, out var info)) return 0; return info.Defense * GetExtraDefense(map); } // 获取防御倍数 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 GetCriticalHitRate(MapData map) { var criticalHitRate = 0f; foreach (var skill in Skills) criticalHitRate += skill.GetCriticalHitRate(this, map); return criticalHitRate; } // 是否能移动到伟人身周 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)) return true; if (terrainType == TerrainType.ShallowSea && (landType == LandType.WaterAndAshore || landType == LandType.WaterOnly)) 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) { if (_random == null) _random = new System.Random(); return _random.NextDouble() <= GetCriticalHitRate(map); } // 移动后的变化 public void OnMove(MapData map, GridData target, MoveType moveType) { foreach (var skill in Skills) skill.OnMove(this, target, map,moveType); } //清空 AP Cp MP public void ClearAPMPCP() { AP = 0; MP = 0; CP = 0; } } }