2026-05-23 18:51:24 +08:00

1955 lines
68 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 Logic;
using Logic.CrashSight;
using Logic.Skill;
using MemoryPack;
using TH1_Logic.Core;
using TH1_Logic.HeroTask;
using TH1_Renderer;
using TH1Renderer;
using UnityEngine;
namespace RuntimeData
{
// 行动点枚举
public enum ActionPointType
{
Common,
Move,
Attack,
Capture,
}
// 地图上所有的小兵数据
[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()
{
UnitList ??= new List<UnitData>();
_unitDict ??= new Dictionary<uint, UnitData>();
_unitDict.Clear();
foreach (var unit in UnitList)
{
if (unit == null) continue;
_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);
}
}
[MemoryPackIgnore]
private List<UnitData> _turnUnitBuffer;
public void OnTurnStart(MapData map, PlayerData player)
{
_turnUnitBuffer ??= new List<UnitData>();
_turnUnitBuffer.Clear();
map.GetUnitDataListByPlayerId(player.Id, _turnUnitBuffer);
foreach (var unit in _turnUnitBuffer)
{
Main.UnitLogic.StartNextTurn(map, unit);
unit.OnTurnStart(map);
}
}
public void OnAfterTurnStart(MapData map, PlayerData player)
{
_turnUnitBuffer ??= new List<UnitData>();
_turnUnitBuffer.Clear();
map.GetUnitDataListByPlayerId(player.Id, _turnUnitBuffer);
foreach (var unit in _turnUnitBuffer)
{
unit.OnAfterTurnStart(map);
}
}
public void OnTurnEnd(MapData map, PlayerData player)
{
_turnUnitBuffer ??= new List<UnitData>();
_turnUnitBuffer.Clear();
map.GetUnitDataListByPlayerId(player.Id, _turnUnitBuffer);
foreach (var unit in _turnUnitBuffer)
{
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)
{
UnitList ??= new List<UnitData>();
_unitDict ??= new Dictionary<uint, UnitData>();
var removed = false;
for (var i = UnitList.Count - 1; i >= 0; i--)
{
var unitData = UnitList[i];
if (unitData == null || unitData.Id != unitId) continue;
UnitList.RemoveAt(i);
removed = true;
}
_unitDict.Remove(unitId);
if (!removed)
LogSystem.LogWarning($"UnitMapData.RemoveUnitData: UnitList missing unitId={unitId}, rebuilt dict may have been stale.");
}
// 通过 uid 找小兵数据 unitData
public bool GetUnitDataByUnitId(uint unitId, out UnitData unitData)
{
_unitDict ??= new Dictionary<uint, UnitData>();
if (_unitDict.TryGetValue(unitId, out unitData)) return true;
if (UnitList != null)
{
foreach (var unit in UnitList)
{
if (unit == null || unit.Id != unitId) continue;
unitData = unit;
_unitDict[unitId] = unit;
LogSystem.LogWarning($"UnitMapData.GetUnitDataByUnitId: recovered stale dict entry unitId={unitId}.");
return true;
}
}
unitData = null;
return false;
}
}
[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);
}
public static bool operator ==(UnitFullType left, UnitFullType right)
{
return left.Equals(right);
}
public static bool operator !=(UnitFullType left, UnitFullType right)
{
return !(left == right);
}
}
//小兵数据
[MemoryPackable]
public partial class UnitData : IdentifierBase
{
// 判断是否已经setDie并从mapDataRelation中除名如果是判断unit是否存活应该用IsAlive函数
[MemoryPackInclude]
private bool _notSetDie;
//单位类型
public UnitFullType UnitFullType;
// 单位类型(legacy)
public UnitType UnitType => UnitFullType.UnitType;
public GiantType GiantType => UnitFullType.GiantType;
public uint UnitLevel => UnitFullType.UnitLevel;
//棋子种类
public ChessType ChessType;
// 血量
public int Health;
private const float PositiveIntEpsilon = 0.0001f;
private const double PositiveIntDoubleEpsilon = 0.000001d;
public static int CeilPositiveToInt(float value)
{
if (value <= 0f) return 0;
var rounded = Mathf.RoundToInt(value);
if (rounded > 0 && Mathf.Abs(value - rounded) <= PositiveIntEpsilon) return rounded;
return Mathf.CeilToInt(value);
}
public static int CeilPositiveToInt(double value)
{
if (value <= 0d) return 0;
var rounded = (int)Math.Round(value);
if (rounded > 0 && Math.Abs(value - rounded) <= PositiveIntDoubleEpsilon) return rounded;
return (int)Math.Ceiling(value);
}
// 攻击范围
//英雄经验值
public int GiantExp;
public UnitFullType OriginUnitFullType;
//是否老兵
//public bool Veteran;
//存储carry的UnitType
public UnitFullType CarryUnitFullType;
public UnitType CarryUnitType => CarryUnitFullType.UnitType;
public GiantType CarryGiantType => CarryUnitFullType.GiantType;
public uint CarryUnitLevel => CarryUnitFullType.UnitLevel;
//存储carry的exp状态
//public int CarryExp;
//存储carry的Veteran状态
//public bool CarryVeteran;
// 防御削减系数
public float DefenseReduction;
// 军团编号
[MemoryPackIgnore]
public uint LegionId;
public UnitFullType FullTypeCache;
public List<SkillBase> SkillCache;
public Dictionary<ActionPointType, int> ActionPoint;
// 行动点缓存UI用不参与逻辑
[MemoryPackIgnore]
private Dictionary<ActionPointType, int> _actionCache;
public Dictionary<ActionPointType, int> ActionCache => _actionCache;
public void SetAlive() { _notSetDie = true; }
public void SetDie() { _notSetDie = false; }
public bool IsAlive()
{
return _notSetDie && Health > 0;
}
// 单位已被扣到 0 血但仍未 SetDie即未走过 UnitDie/UnitUnnaturalDie
// Why: 用于在伤害结算末尾兜底僵尸单位IsCanBeKill 拒绝 + OnDamaged 被 Frozen 跳过等场景)。
public bool IsZombie()
{
return _notSetDie && 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 bool IsValidOnMap(MapData map, GridData expectedGrid = null)
{
if (map?.UnitMap == null) return false;
if (!map.UnitMap.GetUnitDataByUnitId(Id, out var currentUnit)) return false;
if (!ReferenceEquals(currentUnit, this)) return false;
if (!map.GetPlayerDataByUnitId(Id, out _)) return false;
if (expectedGrid == null) return true;
return map.GetGridDataByUnitId(Id, out var currentGrid)
&& currentGrid != null
&& currentGrid.Id == expectedGrid.Id;
}
public UnitRenderer Renderer(MapData map)
{
if (!map.IsCurrentShowMap()) return null;
var mapRenderer = MapRenderer.Instance;
if (mapRenderer?.ROUnitMap == null) return null;
return mapRenderer.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()
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsSetMaxHealth(this, out var maxHealth))
{
return maxHealth;
}
}
if (!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitFullType, out var unitTypeInfo))
return 0;
if (unitTypeInfo.NoMaxHealth)
{
if (CarryUnitFullType.UnitType != UnitType.None)
{
if(Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(CarryUnitFullType,out var carryUnitTypeInfo))
return carryUnitTypeInfo.MaxHealth + GetOfficerHealth();
return 0;
}
return 0;
}
else
return unitTypeInfo.MaxHealth + GetOfficerHealth();
}
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)
{
return TryGetPosition(map, out var position) ? position : Vector3.zero;
}
public bool TryGetPosition(MapData map, out Vector3 position)
{
position = Vector3.zero;
if (map == null || map != Main.MapData) return false;
var mapRenderer = MapRenderer.Instance;
if (mapRenderer?.ROUnitMap != null
&& mapRenderer.ROUnitMap.TryGetValue(Id, out var renderer)
&& renderer != null)
{
position = renderer.GetPosition();
return true;
}
if (map.GetGridDataByUnitId(Id, out var gridData) && gridData != null && Table.Instance != null)
{
position = Table.Instance.GridToWorld(gridData, "isUnit");
LogSystem.LogWarning($"UnitData.GetPosition: unitId={Id} missing in ROUnitMap, fallback to grid position.");
return true;
}
LogSystem.LogWarning($"UnitData.GetPosition: unitId={Id} missing in ROUnitMap and grid relation.");
return false;
}
// 获取血量百分比
public float GetHealthRatio()
{
return (float)Health / GetMaxHealth();
}
// 获取ProjectileType
public ProjectileType GetProjectileType(MapData map,GridData targetGrid)//, MoveAttackType moveAttackType)
{
if (!Grid(map, out var originGrid)) return ProjectileType.None;
int distance = map.GridMap.CalcDistance(originGrid, targetGrid);
//TODO 将来复杂了就走skill生命周期现在就全先写在这儿了
//如果拥有kanakositting全部变为远程
if (GetSkill(SkillType.KANAKOSITTING, out var _))
{
return ProjectileType.KanakoAttack;
}
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(UnitFullType, out var info))
return 0;
//如果是英雄,要单独结算,按照英雄的不同等级定价结算
if (UnitFullType.UnitType == UnitType.Giant)
return UnitFullType.UnitLevel switch
{
1 => 10,
2 => 10,
3 => 15,
4 => 25,
_ => 0
};
//如果生命值低于50%,得分打8折
if (GetHealthRatio() <= 0.5f) return info.Cost * 0.8f;
return info.Cost;
}
// 获取造价
public float GetCost()
{
if (!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitFullType, out var info))
return 0;
return info.Cost;
}
[MemoryPackConstructor]
public UnitData()
{
}
//注意这里没有处理unit Copy之后skill要触发skillAdd生命周期的情况
public UnitData(UnitData copyData)
{
Id = copyData.Id;
_notSetDie = copyData._notSetDie;
UnitFullType = copyData.UnitFullType;
Health = copyData.Health;
GiantExp = copyData.GiantExp;
CarryUnitFullType = copyData.CarryUnitFullType;
OriginUnitFullType = copyData.OriginUnitFullType;
LegionId = copyData.LegionId;
DefenseReduction = copyData.DefenseReduction;
foreach (var skill in copyData.Skills) Skills.Add(skill.GetCopySkill());
SkillCache = new List<SkillBase>();
foreach (var skill in copyData.SkillCache) SkillCache.Add(skill.GetCopySkill());
ActionPoint = new Dictionary<ActionPointType, int>();
foreach (var kv in copyData.ActionPoint)
{
ActionPoint[kv.Key] = kv.Value;
}
_actionCache = new Dictionary<ActionPointType, int>();
}
//注意这里没有处理unit Copy之后skill要触发skillAdd生命周期的情况
public void DeepCopy(UnitData copyData)
{
Id = copyData.Id;
_notSetDie = copyData._notSetDie;
UnitFullType = copyData.UnitFullType;
ChessType = copyData.ChessType;
Health = copyData.Health;
GiantExp = copyData.GiantExp;
CarryUnitFullType = copyData.CarryUnitFullType;
OriginUnitFullType = copyData.OriginUnitFullType;
LegionId = copyData.LegionId;
DefenseReduction = copyData.DefenseReduction;
Skills.Clear();
foreach (var skill in copyData.Skills) Skills.Add(skill.GetCopySkill());
SkillCache ??= new List<SkillBase>();
SkillCache.Clear();
foreach (var skill in copyData.SkillCache) SkillCache.Add(skill.GetCopySkill());
ActionPoint ??= new Dictionary<ActionPointType, int>();
ActionPoint.Clear();
foreach (var kv in copyData.ActionPoint)
{
ActionPoint[kv.Key] = kv.Value;
}
_actionCache ??= new Dictionary<ActionPointType, int>();
}
// 无参数初始化
public UnitData(UnitFullType unitFullType, MapIdGenerator idGenerator)
{
Id = idGenerator.GeneratorId();
UnitFullType = unitFullType;
SkillCache = new List<SkillBase>();
ActionPoint = new Dictionary<ActionPointType, int>();
_actionCache = new Dictionary<ActionPointType, int>();
InitData();
}
// MemoryPack 反序列化之后的后处理
[MemoryPackOnDeserialized]
public void OnAfterMemoryPackDeserialize()
{
_actionCache ??= new Dictionary<ActionPointType, int>();
}
public void InitData()
{
if (Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitFullType, out var unitTypeInfo)
&& unitTypeInfo.NoMaxHealth)
{
//TODO 目前 nomaxhealth和carry不是一个概念
CarryUnitFullType.UnitType = UnitType.Warrior;
}
_notSetDie = true;
Health = GetMaxHealth();
ChessType = unitTypeInfo.ChessType;
//AttackRange = Table.Instance.QueryUnitAttackRange(UnitType);
//MoveRange = Table.Instance.QueryUnitMoveRange(UnitType);
//Exp = 0;
GiantExp = 0;
//Veteran = false;
LegionId = 0;
}
//----------------------------------------- 判断属性 ----------------------------------------------
/// <summary>
/// 静态判断该UnitType是否属于BigGuy类不含等级判断
/// </summary>
public static bool IsBigGuyType(UnitType unitType)
{
return unitType is UnitType.BigGuy
or UnitType.KaguyaFrenchWolf
or UnitType.KomeijiIndianBigGuy
or UnitType.KomeijiIndianJuggernaut
or UnitType.WolfJuggernaut
or UnitType.Juggernaut
or UnitType.RemiliaEgyptianKoakuma
or UnitType.RemiliaEgyptianKoakumaLion
or UnitType.MoriyaHebi;
}
public bool IsBigGuy(bool useToCheckDie = false)
{
if(UnitType == UnitType.BigGuy) return true;
if(UnitType == UnitType.KaguyaFrenchWolf) return true;
if(UnitType == UnitType.KomeijiIndianBigGuy) return true;
if(UnitType == UnitType.KomeijiIndianJuggernaut) return true;
if(UnitType == UnitType.WolfJuggernaut) return true;
if(UnitType == UnitType.Juggernaut) return true;
if(UnitType == UnitType.RemiliaEgyptianKoakuma && !useToCheckDie) return true;
if(UnitType == UnitType.RemiliaEgyptianKoakumaLion) return true;
if(UnitType == UnitType.MoriyaHebi && UnitLevel >= 3) return true;
return false;
}
public bool IsHero(bool useToCheckDie = false)
{
if(GiantType == GiantType.None && CarryGiantType == GiantType.None) return false;
if(UnitType == UnitType.KaguyaFrenchMokouEgg) return true;
if(GiantType == GiantType.FrenchMokou && useToCheckDie) return false;
return true;
}
// 全局通知调用
public void OnTurnStart(MapData map)
{
OnSkillsTurnStart(map);
_actionCache.Clear();
}
public void OnAfterTurnStart(MapData map)
{
OnSkillsAfterTurnStart(map);
}
public void OnTurnEnd(MapData map)
{
OnSkillsTurnEnd(map);
}
protected override void OnSkillsTurnStart(MapData map)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.BeforeTurnStart();
if (skill.IsFinished())
{
skill.OnFinished(this, map);
Skills.Remove(skill);
continue;
}
skill.OnTurnStart(this, map);
}
}
protected override void OnSkillsAfterTurnStart(MapData map)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.OnAfterTurnStart(this, map);
}
}
protected override void OnSkillsTurnEnd(MapData map)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.OnTurnEnd(this, map);
}
}
//返回该unit的视野半径(考虑unit站在map的实机位置下的视野半径)
public int GetSightRange(MapData map)
{
int v = 1;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
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;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
v += skill.GetExtraSight(this,map);
}
if (grid.Feature == TerrainFeature.Mountain)
v = Mathf.Max(v, 2);
return v;
}
public int GetAttackRange(MapData mapData)
{
var attackRange = 0;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
attackRange += skill.GetExtraAttackRange(mapData,this);
}
attackRange +=
Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitFullType, out var info)
? info.AttackRange
: 0;
return attackRange;
}
//最终移动能力。 目前仅用于Kanako Sitting的情况(拥有移动力,但是无法移动)
public int FinalMoveRange(MapData mapData)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (!skill.GetFinalMoveRange(this, out var finalMoveRange)) continue;
return finalMoveRange;
}
return GetMoveRange(mapData);
}
public int GetMoveRange(MapData mapData)
{
if (!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitFullType, out var info))
return 0;
var moveRange = info.MoveRange;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
moveRange += skill.GetExtraMoveRange(mapData,this);
}
return moveRange;
}
//返回该unit是否是静止经验(无法升级)
public bool CheckIsStaticExp(MapData map)
{
var isStaticExp = false;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
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(UnitFullType,out var Info)?Info.LandType:LandType.None;
}
//----------------------------------------- 数值计算相关函数 ---------------------------------------------
// 获取技能加成倍数 (本人拥有的其他技能对特定技能的加成倍数)
public float GetSpecialSkillBonus(MapData mapData, SkillType skillType)
{
var value = 1f;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
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 > 0 ?" + ":" - ") + Mathf.Abs(add);
if (mul != 1f) ret += " (× " + mul.ToString() + ")";
return ret;
}
public float GetRawAttackValue(MapData map, UnitData target = null)
{
if(!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitFullType, out var info)) return 0;
return info.Attack;
}
// 基础攻击力
public float GetBaseAttackValue(MapData map, UnitData target = null)
{
if(!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitFullType, 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;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
value += skill.GetAttackAdditionParam(map, this, target);
}
return value;
}
// 攻击力乘算系数
public float GetAttackMultiplicationParam(MapData map, UnitData target = null)
{
var value = 1f;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
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 > 0 ?" + ":" - ") + Mathf.Abs(add);
if (mul != 1f) ret += " (× " + mul.ToString() + ")";
return ret;
}
// 获得总射程的string显示
public string GetMoveRangeShowString(MapData mapData)
{
var raw = Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitFullType, out var info)
? info.MoveRange
: 0;
var add = 0;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
add += skill.GetExtraMoveRange(mapData,this);
}
//var mul = GetDefenseMultiplicationParam(map);
string ret = raw.ToString();
if (add != 0)
{
//特判椛椛的铁十字追击
if(GetSkill(SkillType.MOMIJIHUNTER,out var _))
ret += (add > 0 ?" + ":" - ") + Mathf.Abs(add) + "?";
else
ret += (add > 0 ?" + ":" - ") + Mathf.Abs(add);
}
//if (mul != 1f) ret += " (× " + mul.ToString() + ")";
return ret;
}
// 获得总射程的string显示
public string GetAttackRangeShowString(MapData mapData)
{
var raw = Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitFullType, out var info)
? info.AttackRange
: 0;
var add = 0;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
add += skill.GetExtraAttackRange(mapData,this);
}
//var mul = GetDefenseMultiplicationParam(map);
string ret = raw.ToString();
if (add != 0) ret += (add > 0 ?" + ":" - ") + Mathf.Abs(add);
//if (mul != 1f) ret += " (× " + mul.ToString() + ")";
return ret;
}
public float GetRawDefenseValue(MapData map, UnitData target = null)
{
if(!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitFullType, out var info)) return 0;
return info.Defense;
}
// 基础防御力
public float GetBaseDefenseValue(MapData map, UnitData target = null)
{
if(!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitFullType, 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;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
value += skill.GetDefenseAdditionParam(map, this, target);
}
return value;
}
//只用于显示防御外壳判断用的系数计算(会去除<1的乘算因子)
public float GetDefenseMultiplicationParamOnlyForDefenseShow(MapData map, UnitData target = null)
{
var buffValue = 1f; // 增益效果(>1取最大值
var debuffMult = 1f; // 减益效果(<1累乘
var isZero = 1f;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
var t = skill.GetDefenseMultiplicationParam(map, this, target);
isZero *= t;
// 分离增益和减益
if (t > 1f)
buffValue = Mathf.Max(t, buffValue); // 增益取最大
else if (t < 1f)
debuffMult *= t; // 减益累乘
}
var p = GetTerrainDefenseMultiplicationParam(map);
if (p > 1f)
buffValue = Mathf.Max(p, buffValue);
else if (p < 1f)
debuffMult *= p;
isZero *= p;
if (isZero == 0f) return 0f;
// 最终防御系数 = 最大增益 * 减益累乘
return buffValue;
}
// 防御力乘算系数
public float GetDefenseMultiplicationParam(MapData map, UnitData target = null)
{
var buffValue = 1f; // 增益效果(>1取最大值
var debuffMult = 1f; // 减益效果(<1累乘
var isZero = 1f;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
var t = skill.GetDefenseMultiplicationParam(map, this, target);
isZero *= t;
// 分离增益和减益
if (t > 1f)
buffValue = Mathf.Max(t, buffValue); // 增益取最大
else if (t < 1f)
debuffMult *= t; // 减益累乘
}
var p = GetTerrainDefenseMultiplicationParam(map);
if (p > 1f)
buffValue = Mathf.Max(p, buffValue);
else if (p < 1f)
debuffMult *= p;
isZero *= p;
if (isZero == 0f) return 0f;
// 最终防御系数 = 最大增益 * 减益累乘
return buffValue * debuffMult;
}
#region [------------------------------------------------------------------ AttackAlly ------------------------------------------------------------------]
/// <summary>
/// 是否具备 AttackAlly 能力
/// </summary>
public bool AttackAllyEnable(MapData mapData, UnitData target)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.AttackAllyEnable(mapData, this, target))
return true;
}
return false;
}
/// <summary>
/// 获取 AttackAlly 基础恢复数值
/// </summary>
public int AttackAllyBaseHeal(MapData mapData, UnitData target)
{
int ret = 0;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
ret += skill.AttackAllyBaseHeal(mapData, this, target);
}
return ret;
}
/// <summary>
/// 获取 AttackAlly 恢复数值加成(加法)
/// </summary>
public int AttackAllyHealAddition(MapData mapData, UnitData target)
{
int ret = 0;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
ret += skill.AttackAllyHealAddition(mapData, this, target);
}
return ret;
}
/// <summary>
/// 获取 AttackAlly 对自身造成的伤害如Koakuma的治疗代价
/// </summary>
public int AttackAllySelfDamage(MapData mapData, UnitData target)
{
int ret = 0;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
ret += skill.AttackAllySelfDamage(mapData, this, target);
}
return ret;
}
#endregion
// 地形防御乘算系数
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 || grid.Resource == ResourceType.RemiliaMilitary) extraDefense *= 1.5f;
return extraDefense;
}
// 获取暴击率
public float GetCriticalHitRate(MapData map)
{
var criticalHitRate = 0f;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
criticalHitRate += skill.GetCriticalHitRate(this, map);
}
return criticalHitRate;
}
#region [------------------------------ Skill -----------------------------------]
//清楚隐身状态
/*public void RemoveHideState(MapData map)
{
foreach(skill)
//RemoveSkill(SkillType.HideState, map);
}*/
//获取officer的额外血量
public int GetOfficerHealth()
{
int ret = 0;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
ret += skill.GetOfficerHealth();
}
return ret;
}
//判断当前是不是officer
public bool IsOfficer()
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsOfficer()) return true;
}
return false;
}
public bool IsPrepareOfficer()
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsPrepareOfficer()) return true;
}
return false;
}
public bool IsCanBeOfficer()
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsCanBeOfficer()) return true;
}
return false;
}
// 是否能移动到伟人身周
public bool IsCanMoveGiantNearbyGrid(MapData map)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsCanMoveGiantNearbyGrid(this, map)) return true;
}
return false;
}
// 是否movekill
public bool IsCanMoveKill(MapData mapData)
{
if (GetAttackRange(mapData) == 1)
return true;
return false;
}
// 是否拥有特别伤害技能例如ROYALFLAME
public bool IsHasAttackSkill(MapData map)
{
return false;
}
// 是否能移动无人城市
public bool IsCanMoveNoUnitSelfCity(MapData map)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsCanMoveToNoUnitSelfCity(this, map)) return true;
}
return false;
}
// 是否可以死亡
public bool CanBeKilled(MapData map)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (!skill.IsCanBeKill(this, map)) return false;
}
return true;
}
// 是否可以被伤害结算
public bool IsLimitDamaged(MapData map, int dmg)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsLimitDamaged(this, map, dmg)) return true;
}
return false;
}
// 是否经验锁定
public bool IsExpLock(MapData map)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
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;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
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;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsCanMoveOnFeature(this, map,featureType)) return true;
}
return false;
}
//返回该unit是否能攻击所有人
public bool CanAttackAll(MapData map)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.CanAttackAll(this, map)) return true;
}
return false;
}
//返回该unit是否隐身
public bool IsHideState(MapData map)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsHideState()) return true;
}
return false;
}
//返回该unit是否不可见(不考虑视野),与上方IsHideState的区别在于 我方/盟友的隐身单位是可见的,敌方的隐身单位才不可见
public bool IsHideAndCantSee(MapData map,PlayerData player)
{
if (!IsHideState(map)) return false;
if (player == null) return false;
if (Player(map, out var unitPlayer) && map.SameUnion(unitPlayer.Id, player.Id)) return false;
return true;
}
//返回是否限制unit攻击
public bool IsLimitSelfAttack(MapData map)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsLimitSelfAttack(this, map)) return true;
}
return false;
}
//返回该unit是否能移动
public bool IsLimitSelfMove(MapData map)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsLimitSelfMove(this, map)) return true;
}
return false;
}
//返回该unit是否能攻击ground
public bool IsCanAttackTargetGrid(MapData map, GridData target)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsCanAttackTargetGrid(map,this,target)) return true;
}
return false;
}
//返回该unit是否能攻击Ally
public bool IsCanAttackAlly()
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsCanAttackAlly()) return true;
}
return false;
}
//返回该unit是否处在载具上
public bool IsOnCarry()
{
foreach (var skill in Skills)
{
if (skill.IsOnCarry()) return true;
}
return false;
}
//返回该unit是否可以向BonePile献祭古明地非Giant单位、拥有BoneSacrifice技能、或拥有CorpseBuff技能的单位
public bool CanFeedBonePile(MapData map)
{
if (GetSkill(SkillType.BoneSacrifice, out _)) return true;
if (GetSkill(SkillType.CorpseBuff, out var corpsBuff) && corpsBuff.Level > 0) return true;
if (UnitType == UnitType.Giant) return false;
if (!Player(map, out var player)) return false;
if (player.PlayerCivId != 3) return false;
return true;
}
//返回该unit是否能攻击ground
public bool IsCanAttackTargetAlly(MapData map, UnitData target)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (!skill.IsCanAttackTargetAlly(map,this,target)) return false;
}
return true;
}
public bool IsCanAttackTargetUnit(MapData map, UnitData target)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (!skill.IsCanAttackTargetUnit(map, this, target)) return false;
}
return true;
}
//返回该unit是否能反击
public bool IsLimitSelfCounterAttack(MapData map)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsLimitSelfCounterAttack(this, map)) return true;
}
return false;
}
//返回目标 unit 是否能反击
public bool IsLimitTargetCounterAttack(MapData map)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsLimitTargetCounterAttack(this, map)) return true;
}
return false;
}
public bool IsCanTransport()
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsCanTransport()) return true;
}
return false;
}
// 移动是否会失败(并不限制移动)
public bool IsActiveMoveFailed(MapData map, GridData target, MoveType moveType, List<Vector2Int> path = null)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.ActiveMoveFailed(this, target, map, moveType, path)) return true;
}
return false;
}
// 移动后的变化
public void BeforeMove(MapData map, GridData target, MoveType moveType, List<Vector2Int> path = null)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.BeforeMove(this, target, map, moveType, path);
}
}
// 移动后
public void OnMove(MapData map, GridData target, MoveType moveType, List<Vector2Int> path = null)
{
if (map == null || target == null || !IsValidOnMap(map, target)) return;
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (!IsValidOnMap(map, target)) return;
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.OnMove(this, target, map,moveType, path);
}
if (!IsValidOnMap(map, target)) return;
//赋予格子特殊效果,scarletEmpire的单位走到格子上时会得到被赋予一个技能realTimeVampire
// 注意:多人允许相同 Empire 后,多名 PlayerCivId==0 玩家会同时享有此特权,符合预期保留逻辑。
if(target.HasSpType(GridSpType.RemiliaGrid) && target.RealUnit(map,out var unit) && unit.Player(map,out var player) && player.PlayerCivId == 0)
AddSkill_Legacy(SkillType.ScarletMistRealTimeVampire, map,true,-1,false,-1,false,SpecialAddSkillType.Force,0);
else
if(GetSkill(SkillType.ScarletMistRealTimeVampire,out var _))
RemoveSkill(SkillType.ScarletMistRealTimeVampire,map);
}
// 成为移动目标时
public void OnBeInteractTarget(MapData map, UnitData origin, GridData target)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.OnBeInteractTarget(origin, this, target, map);
}
}
// 伤害结算前
public void BeforeDamagedSupportStage(MapData map, SettlementInfo info)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.BeforeDamagedSupportStage(map, info);
}
}
// 伤害结算前
public void BeforeDamagedTransformStage(MapData map, SettlementInfo info)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.BeforeDamagedTransformStage(map, info);
}
}
// 对他人攻击前
public void BeforeActiveAttackOther(MapData mapData, UnitData origin, UnitData target,out int addDmg)
{
addDmg = 0;
if (mapData == null || origin == null || target == null) return;
if (!origin.IsValidOnMap(mapData) || !target.IsValidOnMap(mapData)) return;
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (!origin.IsValidOnMap(mapData) || !target.IsValidOnMap(mapData)) return;
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.BeforeActiveAttackOther(mapData, origin, target, out var tmpAddDmg);
addDmg += tmpAddDmg;
}
}
// 对他人攻击后
public void AfterActiveAttackOther(MapData mapData, AttackInfo attackInfo)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.AfterActiveAttackOther(mapData, attackInfo);
}
}
// 受他人攻击后
public void AfterActiveAttacked(MapData mapData, AttackInfo attackInfo)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.AfterActiveAttacked(mapData, attackInfo);
}
}
// 对他人伤害结算前
public void BeforeDamageOther(MapData map, SettlementInfo info)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.BeforeDamageOther(map, info);
}
}
// 伤害结算时
public void OnDamaged(MapData mapData, SettlementInfo info)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.OnDamaged(mapData, info);
}
}
// 消失前
public void BeforeDisappear(MapData mapData)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.BeforeDisappear(mapData, this);
}
}
// 对他人伤害结算时
public void OnDamageOther(MapData mapData, SettlementInfo info)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.OnDamageOther(mapData, info);
}
}
// 对他人伤害结算后
public void AfterDamageOther(MapData mapData, SettlementInfo info)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.AfterDamageOther(mapData, info);
}
}
// 对他人治疗结算时
public void OnHealOther(MapData mapData, UnitData target,HealType healType)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.OnHealOther(mapData,this,target, healType);
}
}
// 治疗前修改回复量(被治疗者视角)
public int BeforeHealSelf(MapData mapData, UnitData origin, HealType healType, int recover)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
recover = skill.BeforeHealSelf(mapData, this, origin, healType, recover);
}
return recover;
}
// AttackAlly 准备治疗前Healer 视角)
public void OnAttackAllyJustBeforeHeal(MapData mapData, UnitData target, HealType healType)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.OnAttackAllyJustBeforeHeal(mapData, this, target, healType);
}
}
// 对他人治疗结算后Healer 视角)
public void OnAttackAllyAfterHeal(MapData mapData, UnitData target, HealType healType, int realHealed, int overflow)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.OnAttackAllyAfterHeal(mapData, this, target, healType, realHealed, overflow);
}
}
//获取抵达某格所需要的movecostinfo下限目前仅用于momijiHUnter也就是说moveinfo>该值才
public float GetGridMoveFloor(MapData mapData, UnitData originUnit,GridData targetGrid)
{
var isFrozen = IsFrozen();
var copy = new List<SkillBase>(Skills);
float ret = 0f;
foreach (var skill in copy)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
ret = Mathf.Max(ret,skill.GetGridMoveFloor(mapData,originUnit,targetGrid));
}
return ret;
}
//获取自身占据的population数额
public int GetPopulation()
{
if (GetSkill(SkillType.NOPOPULATION, out var _))
return 0;
return 1;
}
public int GetKillCount()
{
int ret = 0;
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
ret += skill.GetKillCount();
}
return ret;
}
//判断是否被某人视作英雄
public bool TreatedAsHero(MapData map,UnitData unit)
{
return TreatedAsHero(map, unit, out _);
}
public bool TreatedAsHero(MapData map, UnitData unit, out GiantType giantType)
{
giantType = GiantType.None;
if (UnitFullType.UnitType == UnitType.Giant)
{
giantType = UnitFullType.GiantType;
return true;
}
if (CarryUnitFullType.UnitType == UnitType.Giant)
{
giantType = CarryUnitFullType.GiantType;
return true;
}
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsTreatAsHero(map, this, unit, out giantType)) return true;
}
return false;
}
// 判断是否只能在我方领土内移动
public bool IsLimitMoveToSelfTerrain(MapData map)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsLimitMoveToSelfTerrain(this, map)) return true;
}
return false;
}
// 判断是否限制行动点
public bool IsLimitActionPoint()
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsLimitActionPoint(this)) return true;
}
return false;
}
// 是否无视ZOC
public bool IsIgnoreZOC()
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsIgnoreZOC()) return true;
}
return false;
}
// 是否无视森林Trees 植被)带来的移动减损 —— BAMBOOMOVE / CREEP 等技能聚合
public bool IsIgnoreForestMoveDebuff(MapData mapData)
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (skill.IsIgnoreForestMoveDebuff(this, mapData)) return true;
}
return false;
}
// 是否具备ZOC控制能力
public bool HasZOC()
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
if (!skill.HasZOC()) return false;
}
return true;
}
#endregion
//------------------------------------------------- 对unitData的基础操作 ----------------------------------------------
//清空 GetActionPoint(ActionPointType.Attack) Cp GetActionPoint(ActionPointType.Move)
public void ClearActionPoint()
{
ActionPoint.Clear();
var map = Main.MapData;
if (map == null) return;
// 用副本遍历:技能内部可能 RemoveSkill 改动 Skills 集合
var snapshot = new List<SkillBase>(Skills);
foreach (var skill in snapshot)
skill?.OnClearActionPoint(map, this);
}
public void SetFullActionPoint()
{
ActionPoint.Clear();
ActionPoint[ActionPointType.Common] = 1;
}
public void SetFullActionPoint_AllSkillRefresh()
{
SetFullActionPoint();
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.OnRefresh();
}
}
public int AddHealth(int hp)
{
var offset = Math.Min(GetMaxHealth() - Health, hp);
Health += offset;
return offset;
}
public int AddHealth(float hp)
{
return AddHealth(CeilPositiveToInt(hp));
}
public void SetOfficer()
{
var isFrozen = IsFrozen();
foreach (var skill in Skills)
{
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
skill.SetOfficer();
}
}
public bool IsFrozen()
{
foreach (var skill in Skills)
{
if (skill.IsAllSkillBan()) return true;
}
return false;
}
//用于筛选哪些skill能被ban 哪些不能被ban
public bool IsSkillFrozenFilter(SkillBase skill)
{
return skill.SkillPriority == SkillPriority.Normal;
return false;
}
public bool IsSkillFrozenForSkillBase(SkillBase skill)
{
return IsFrozen() && IsSkillFrozenFilter(skill);
}
/// <summary>
/// 判断单位是否拥有且正在生效某个技能。
/// 与 GetSkill 的区别是GetSkill 只判断“是否持有”,本方法会额外排除被全技能封禁(Force)的技能。
/// </summary>
/// <param name="skillType">目标技能类型</param>
/// <param name="skill">返回技能实例</param>
/// <returns>true=拥有且生效false=未拥有或已被封禁</returns>
public bool HasEffectiveSkill(SkillType skillType, out SkillBase skill)
{
skill = null;
if (!GetSkill(skillType, out var foundSkill)) return false;
if (IsSkillFrozenForSkillBase(foundSkill)) return false;
skill = foundSkill;
return true;
}
// 增加
public void AddActionPoint(ActionPointType actionPointType)
{
if (IsLimitActionPoint()) return;
ActionPoint.TryAdd(actionPointType, 0);
ActionPoint[actionPointType]++;
}
// 获取
public int GetActionPoint(ActionPointType actionPointType)
{
if (IsLimitActionPoint()) return 0;
if (ActionPoint.ContainsKey(actionPointType) && ActionPoint[actionPointType] > 0)
return ActionPoint[actionPointType];
return ActionPoint.GetValueOrDefault(ActionPointType.Common, 0);
}
// 减少
public void ReduceActionPoint(ActionPointType actionPointType)
{
if (IsLimitActionPoint()) return;
_actionCache.TryAdd(actionPointType, 0);
_actionCache.TryAdd(ActionPointType.Common, 0);
if (ActionPoint.ContainsKey(actionPointType) && ActionPoint[actionPointType] > 0)
{
ActionPoint[actionPointType]--;
_actionCache[actionPointType]++;
return;
}
ActionPoint.TryAdd(ActionPointType.Common, 0);
ActionPoint[ActionPointType.Common]--;
_actionCache[ActionPointType.Common]++;
}
//判断是否拥有某种行动点
public bool HasActionPoint(ActionPointType actionPointType)
{
if (IsLimitActionPoint()) return false;
if (ActionPoint.ContainsKey(actionPointType) && ActionPoint[actionPointType] > 0) return true;
return ActionPoint[ActionPointType.Common] > 0;
}
}
}