2025-07-14 19:41:58 +08:00

563 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @Author: 白哉
* @Description:
* @Date: 2025年04月03日 星期四 11:04:31
* @Modify:
*/
using System;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
namespace RuntimeData
{
// 地图上所有的小兵数据
[Serializable]
public class UnitMapData : ISerializationCallbackReceiver
{
public List<UnitData> UnitList;
public Dictionary<uint, UnitData> _unitDict;
public bool UnitMapRenderMark;
public UnitMapData()
{
UnitList = new List<UnitData>();
_unitDict = new Dictionary<uint, UnitData>();
UnitMapRenderMark = true;
}
public UnitMapData(UnitMapData copyData)
{
UnitList = new List<UnitData>();
_unitDict = new Dictionary<uint, UnitData>();
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<uint, UnitData>();
_unitDict.Clear();
foreach (var unit in UnitList) _unitDict[unit.Id] = unit;
}
public void OnTurnStart(MapData map, PlayerData player)
{
var units = new HashSet<UnitData>();
map.GetUnitDataListByPlayerId(player.Id, units);
foreach (var unit in UnitList)
{
if (!units.Contains(unit)) continue;
unit.OnTurnStart(map);
}
}
public void OnTurnEnd(MapData map, PlayerData player)
{
var units = new HashSet<UnitData>();
map.GetUnitDataListByPlayerId(player.Id, units);
foreach (var unit in UnitList)
{
if (!units.Contains(unit)) continue;
unit.OnTurnEnd(map);
}
}
// 新建小兵
public UnitData AddUnitData(UnitType unitType,GiantType giantType, MapIdGenerator idGenerator)
{
var unit = new UnitData(unitType, giantType,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 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 bool Veteran;
//存储carry的UnitType
public UnitType CarryUnitType;
public GiantType CarryGiantType;
//存储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, out var unitTypeInfo))
return 0;
if (unitTypeInfo.NoMaxHealth)
{
if (CarryUnitType != UnitType.None)
{
if(Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(CarryUnitType, CarryGiantType,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, out var info))
return 0;
if (GetHealthRatio() <= 0.5f) return info.Cost * 0.5f;
return info.Cost;
}
// 获取造价
public float GetCost()
{
if (!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType, 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;
Health = copyData.Health;
MP = copyData.MP;
AP = copyData.AP;
CP = copyData.CP;
//AttackRange = copyData.AttackRange;
//MoveRange = copyData.MoveRange;
Exp = copyData.Exp;
Veteran = copyData.Veteran;
CarryUnitType = copyData.CarryUnitType;
CarryGiantType = copyData.CarryGiantType;
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;
Health = copyData.Health;
MP = copyData.MP;
AP = copyData.AP;
CP = copyData.CP;
//AttackRange = copyData.AttackRange;
//MoveRange = copyData.MoveRange;
Exp = copyData.Exp;
Veteran = copyData.Veteran;
CarryUnitType = copyData.CarryUnitType;
CarryGiantType = copyData.CarryGiantType;
CarryExp = copyData.CarryExp;
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, MapIdGenerator idGenerator)
{
Id = idGenerator.GeneratorId();
UnitType = unitType;
GiantType = giantType;
InitData();
}
public void InitData()
{
if (Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType, out var unitTypeInfo)
&& unitTypeInfo.NoMaxHealth)
{
//TODO 目前 nomaxhealth和carry不是一个概念
CarryUnitType = UnitType.Warrior;
}
Alive = true;
Health = GetMaxHealth();
MP = 0;
AP = 0;
CP = 0;
//AttackRange = Table.Instance.QueryUnitAttackRange(UnitType);
//MoveRange = Table.Instance.QueryUnitMoveRange(UnitType);
Exp = 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);
}
//返回该unit的视野半径
public int GetSightRange()
{
if (Table.Instance.QueryUnitHasSkill(UnitType, SkillType.SCOUT))
return 2;
return 1;
}
public int GetAttackRange()
{
return Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType,GiantType,out var info)?info.AttackRange:0;
}
public int GetMoveRange()
{
return Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType,GiantType,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 Table.Instance.QueryUnitHasSkill(UnitType, SkillType.STATIC) || isStaticExp;
}
//返回该unit处于城市的时候是否获得防御加成
public bool CheckIsCityDefenseBuff()
{
return Table.Instance.QueryUnitHasSkill(UnitType, SkillType.FORTIFY);
}
//LandAndPort, WaterAndAshore, LandAndWater, WaterOnly, LandOnly, Fly
public LandType GetLandType()
{
return Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType,GiantType,out var Info)?Info.LandType:LandType.None;
}
// 获得总攻击力的string显示
public string GetAttackShowString(MapData map)
{
if(!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType, 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, 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, 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, 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);
}
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 true;
}
return false;
}
// 是否可以被伤害结算
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 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);
}
}
}