939 lines
31 KiB
C#
939 lines
31 KiB
C#
/*
|
||
* @Author: 白哉
|
||
* @Description:
|
||
* @Date: 2025年04月03日 星期四 11:04:31
|
||
* @Modify:
|
||
*/
|
||
|
||
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using Logic;
|
||
using Logic.CrashSight;
|
||
using Logic.Skill;
|
||
using MemoryPack;
|
||
using TH1_Logic.Core;
|
||
using TH1_Logic.HeroTask;
|
||
using TH1_Renderer;
|
||
using TH1Renderer;
|
||
using Unity.VisualScripting;
|
||
using UnityEngine;
|
||
|
||
|
||
namespace RuntimeData
|
||
{
|
||
|
||
|
||
// 地图上所有的小兵数据
|
||
[MemoryPackable]
|
||
public partial class UnitMapData
|
||
{
|
||
public List<UnitData> UnitList;
|
||
[MemoryPackIgnore]
|
||
//public bool UnitMapRenderMark;
|
||
private Dictionary<uint, UnitData> _unitDict;
|
||
|
||
|
||
[MemoryPackConstructor]
|
||
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;
|
||
}
|
||
}
|
||
|
||
// MemoryPack 反序列化之后的后处理
|
||
[MemoryPackOnDeserialized]
|
||
public void OnAfterMemoryPackDeserialize()
|
||
{
|
||
_unitDict ??= new Dictionary<uint, UnitData>();
|
||
_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<UnitData>();
|
||
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<UnitData>();
|
||
map.GetUnitDataListByPlayerId(player.Id, units);
|
||
|
||
foreach (var unit in units)
|
||
{
|
||
Main.UnitLogic.UnitEndTurn(map, unit);
|
||
unit.OnTurnEnd(map);
|
||
}
|
||
}
|
||
|
||
// 新建小兵
|
||
public UnitData AddUnitData(UnitFullType unitFullType, MapIdGenerator idGenerator)
|
||
{
|
||
var unit = new UnitData(unitFullType ,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<UnitFullType>
|
||
{
|
||
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;
|
||
//TODO 暂时使用,之后要干掉 数据层不存render信息,要在unitRenderer里存储
|
||
//public bool RenderMark;
|
||
|
||
//单位类型
|
||
public UnitFullType UnitFullType => new UnitFullType(UnitType,GiantType,UnitLevel);
|
||
// 单位类型(legacy)
|
||
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;
|
||
// 军团编号
|
||
public uint LegionId;
|
||
|
||
|
||
public bool IsAlive()
|
||
{
|
||
return Alive && Health > 0;
|
||
}
|
||
|
||
public PlayerData Player(MapData map)
|
||
{
|
||
map.GetPlayerDataByUnitId(this.Id, out var player);
|
||
return player;
|
||
}
|
||
|
||
public bool Player(MapData map,out PlayerData player)
|
||
{
|
||
return map.GetPlayerDataByUnitId(this.Id, out 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 bool Grid(MapData map,out GridData grid)
|
||
{
|
||
return map.GetGridDataByUnitId(Id, out grid);
|
||
}
|
||
|
||
public UnitRenderer Renderer(MapData map)
|
||
{
|
||
if (!map.IsCurrentShowMap()) return null;
|
||
return MapRenderer.Instance.ROUnitMap.GetValueOrDefault(this.Id);
|
||
}
|
||
|
||
public HeroTaskContentBase HeroTask(MapData map)
|
||
{
|
||
HeroTaskContentBase heroTask = null;
|
||
Player(map)?.PlayerHeroData.HeroTaskDict.TryGetValue(UnitFullType,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 bool IsMainMap()
|
||
{
|
||
if (!Main.MapData.UnitMap.GetUnitDataByUnitId(Id, out var unitData)
|
||
|| unitData != this)
|
||
return false;
|
||
return true;
|
||
}
|
||
|
||
public bool InMainSight()
|
||
{
|
||
if (!IsMainMap()) return false;
|
||
var grid = Grid(Main.MapData);
|
||
if (grid == null) return false;
|
||
return grid.InMainSight();
|
||
}
|
||
|
||
//获取画面的位置
|
||
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();
|
||
}
|
||
|
||
|
||
// 获取ProjectileType
|
||
public ProjectileType GetProjectileType(int distance)
|
||
{
|
||
if (!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitFullType, out var info))
|
||
return ProjectileType.None;
|
||
if (distance == 1 && info.ForceMelee)
|
||
return ProjectileType.Melee;
|
||
return info.ProjectileType;
|
||
}
|
||
|
||
|
||
// 获取军事分
|
||
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(UnitFullType unitFullType, MapIdGenerator idGenerator)
|
||
{
|
||
Id = idGenerator.GeneratorId();
|
||
//UnitFullType = unitFullType;
|
||
UnitType = unitFullType.UnitType;
|
||
GiantType = unitFullType.GiantType;
|
||
UnitLevel = unitFullType.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)
|
||
{
|
||
RemoveInActiveSkill(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)
|
||
{
|
||
RemoveInActiveSkill(map);
|
||
foreach (var skill in Skills)skill.OnTurnEnd(this, map);
|
||
AP = 0;
|
||
CP = 0;
|
||
MP = 0;
|
||
}
|
||
|
||
//返回该unit的视野半径(考虑unit站在map的实机位置下的视野半径)
|
||
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;
|
||
}
|
||
|
||
//返回该unit如果站在具体的pos下的视野半径
|
||
public int GetSightRange(MapData map,GridData grid)
|
||
{
|
||
int v = 1;
|
||
foreach (var skill in Skills)
|
||
v += skill.GetExtraSight(this,map);
|
||
if (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;
|
||
}
|
||
|
||
// 获取技能加成倍数 (本人拥有的其他技能对特定技能的加成倍数)
|
||
public float GetSpecialSkillBonus(MapData mapData, SkillType skillType)
|
||
{
|
||
var value = 1f;
|
||
foreach (var skill in Skills) value *= skill.GetSpecialSkillBonus(mapData, this, skillType);
|
||
return value;
|
||
}
|
||
|
||
// 获得总攻击力的string显示
|
||
public string GetAttackShowString(MapData map)
|
||
{
|
||
var raw = GetRawAttackValue(map, null);
|
||
var add = GetAttackAdditionParam(map, null);
|
||
var mul = GetAttackMultiplicationParam(map);
|
||
string ret = raw.ToString();
|
||
if (add != 0) ret += " + " + add.ToString();
|
||
if (mul != 1f) ret += " (× " + mul.ToString() + ")";
|
||
return ret;
|
||
}
|
||
|
||
public float GetRawAttackValue(MapData map, UnitData target = null)
|
||
{
|
||
if(!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType,UnitLevel, out var info)) return 0;
|
||
return info.Attack;
|
||
}
|
||
|
||
// 基础攻击力
|
||
public float GetBaseAttackValue(MapData map, UnitData target = null)
|
||
{
|
||
if(!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType,UnitLevel, out var info)) return 0;
|
||
return info.Attack + GetAttackAdditionParam(map, target);
|
||
}
|
||
|
||
// 总攻击力
|
||
public float GetAllAttackValue(MapData map, UnitData target = null)
|
||
{
|
||
return GetBaseAttackValue(map, target) * GetAttackMultiplicationParam(map, target);
|
||
}
|
||
|
||
// 攻击力加算系数
|
||
public float GetAttackAdditionParam(MapData map, UnitData target = null)
|
||
{
|
||
var value = 0f;
|
||
foreach (var skill in Skills) value += skill.GetAttackAdditionParam(map, this, target);
|
||
return value;
|
||
}
|
||
|
||
// 攻击力乘算系数
|
||
public float GetAttackMultiplicationParam(MapData map, UnitData target = null)
|
||
{
|
||
var value = 1f;
|
||
foreach (var skill in Skills) value *= skill.GetAttackMultiplicationParam(map, this, target);
|
||
return value;
|
||
}
|
||
|
||
// 获得总防御力的string显示
|
||
public string GetDefenseShowString(MapData map)
|
||
{
|
||
var raw = GetRawDefenseValue(map, null);
|
||
var add = GetDefenseAdditionParam(map, null);
|
||
var mul = GetDefenseMultiplicationParam(map);
|
||
string ret = raw.ToString();
|
||
if (add != 0) ret += " + " + add.ToString();
|
||
if (mul != 1f) ret += " (× " + mul.ToString() + ")";
|
||
return ret;
|
||
}
|
||
|
||
public float GetRawDefenseValue(MapData map, UnitData target = null)
|
||
{
|
||
if(!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType,UnitLevel, out var info)) return 0;
|
||
return info.Defense;
|
||
}
|
||
|
||
// 基础防御力
|
||
public float GetBaseDefenseValue(MapData map, UnitData target = null)
|
||
{
|
||
if(!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType,UnitLevel, out var info)) return 0;
|
||
return info.Defense + GetDefenseAdditionParam(map, target);
|
||
}
|
||
|
||
// 总防御力
|
||
public float GetAllDefenseValue(MapData map, UnitData target = null)
|
||
{
|
||
return GetBaseDefenseValue(map, target) * GetDefenseMultiplicationParam(map, target);
|
||
}
|
||
|
||
// 防御力加算系数
|
||
public float GetDefenseAdditionParam(MapData map, UnitData target = null)
|
||
{
|
||
var value = 0f;
|
||
foreach (var skill in Skills) value += skill.GetDefenseAdditionParam(map, this, target);
|
||
return value;
|
||
}
|
||
|
||
// 防御力乘算系数
|
||
public float GetDefenseMultiplicationParam(MapData map, UnitData target = null)
|
||
{
|
||
var value = 1f;
|
||
var isZero = 1f;
|
||
foreach (var skill in Skills)
|
||
{
|
||
var t = skill.GetDefenseMultiplicationParam(map, this, target);
|
||
value = Mathf.Max(t,value);
|
||
isZero *= t;
|
||
}
|
||
var p = GetTerrainDefenseMultiplicationParam(map);
|
||
value = Mathf.Max(p,value);
|
||
isZero *= p;
|
||
if (isZero == 0f) return 0f;
|
||
return value;
|
||
}
|
||
|
||
// 地形防御乘算系数
|
||
public float GetTerrainDefenseMultiplicationParam(MapData map)
|
||
{
|
||
var extraDefense = 1f;
|
||
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 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;
|
||
}
|
||
|
||
// 是否movekill
|
||
public bool IsCanMoveKill(MapData map)
|
||
{
|
||
if (GetAttackRange() == 1)
|
||
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 CanAttackAll(MapData map)
|
||
{
|
||
foreach (var skill in Skills)
|
||
{
|
||
if (skill.CanAttackAll(this, map)) 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)
|
||
{
|
||
for (int i = Skills.Count - 1; i >= 0; i--)
|
||
{
|
||
Skills[i].OnMove(this, target, map,moveType);
|
||
}
|
||
//赋予格子特殊效果
|
||
if(target.HasSpType(GridSpType.RemiliaGrid))
|
||
AddSkill(SkillType.ScarletMistRealTimeVampire);
|
||
else
|
||
if(GetSkill(SkillType.ScarletMistRealTimeVampire,out var _))
|
||
RemoveSkill(SkillType.ScarletMistRealTimeVampire,map);
|
||
RemoveInActiveSkill(map);
|
||
}
|
||
|
||
// 伤害结算前
|
||
public void BeforeDamaged(MapData map, SettlementInfo info)
|
||
{
|
||
for (int i = Skills.Count - 1; i >= 0; i--) Skills[i].BeforeDamaged(map, info);
|
||
RemoveInActiveSkill(map);
|
||
}
|
||
|
||
// 对他人伤害结算前
|
||
public void BeforeDamageOther(MapData map, SettlementInfo info)
|
||
{
|
||
for (int i = Skills.Count - 1; i >= 0; i--) Skills[i].BeforeDamageOther(map, info);
|
||
RemoveInActiveSkill(map);
|
||
}
|
||
|
||
// 伤害结算时
|
||
public void OnDamaged(MapData mapData, SettlementInfo info)
|
||
{
|
||
for (int i = Skills.Count - 1; i >= 0; i--) Skills[i].OnDamaged(mapData, info);
|
||
RemoveInActiveSkill(mapData);
|
||
HeroTask(mapData)?.OnDamaged(mapData, info);
|
||
}
|
||
|
||
// 对他人伤害结算时
|
||
public void OnDamageOther(MapData mapData, SettlementInfo info)
|
||
{
|
||
for (int i = Skills.Count - 1; i >= 0; i--) Skills[i].OnDamageOther(mapData, info);
|
||
RemoveInActiveSkill(mapData);
|
||
HeroTask(mapData)?.OnDamageOther(mapData, info);
|
||
}
|
||
|
||
//获取自身占据的population数额
|
||
public int GetPopulation()
|
||
{
|
||
if (GetSkill(SkillType.NOPOPULATION, out var _))
|
||
return 0;
|
||
return 1;
|
||
}
|
||
|
||
//判断是否被某人视作英雄
|
||
public bool TreatedAsHero(MapData map,UnitData unit)
|
||
{
|
||
if (UnitFullType.UnitType == UnitType.RemiliaEgyptianKoakuma)
|
||
{
|
||
if (unit.Player(map) != Player(map)) return false;
|
||
return true;
|
||
}
|
||
|
||
if (UnitFullType.UnitType == UnitType.Giant) return true;
|
||
if (CarryUnitType == UnitType.Giant) return true;
|
||
return false;
|
||
}
|
||
|
||
//------------------------------------------------- 对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;
|
||
}
|
||
}
|
||
|
||
} |