/* * @Author: 白哉 * @Description: 成就条件 * @Date: 2025年05月13日 星期二 17:05:32 * @Modify: */ using System; using System.Collections.Generic; using Logic.Pool; using OPS.Obfuscator.Attribute; using RuntimeData; using UnityEngine; namespace Logic.Achievement { public enum AchievementConditionType { // 召唤 n 次伟人 TrainGiant, // 建造 n 次奇观 BuildWonder, // 奇观属于城市 WonderInCity, // 奇观上有单位持续 n 回合 UnitOnWonder, // 周围有 n 个建筑 AroundBuildings, // 周围有 n 个奇观 AroundWonders, // 周围有 n 个敌方单位 AroundEnemyUnits, // 周围有 n 个友方单位 AroundSelfUnits, // 周围有 n 个特定城市格子 AroundCityGrids, // n 回合有击杀无伤亡 KillNoAttacked, // 在地图中央竖线上 InMiddleLine, // 从上至下第 n 行 InRow, // 地图规格 n * m MapSize, // 夺回奇观城市 n 次 ReclaimWonderCity, // 属于特定城市 InCity, // 在 n 个不同城市建造过这个奇观 BuildInDifferentCity, // 某 职阶 的伟人占领过奇观的拥有城市 OccupyWonderCity, // 与特定城市通过 n 个 资源连接 ConnectCity, // n 个不同伟人到过此处 DifferentGiantArrive, // 间隔回合消灭从海上登陆该奇观的小兵 KillLandTroop, // 建造 n 回合内信仰翻 n 倍 FaithTimes, // 周围有 n 个文明的土地(曾经来自) AroundCivilizationLand, // 所在城市有 n 个 资源 InCityResources, // 转换该奇观上的地方单位 ConvertUnit, // 使用非 某阵营 持续 n 回合达成其余条件 NotCiv, // 己方特定类型 unit type 在奇观上死亡 UnitTypeDie, } [DoNotObfuscateClass] [Serializable] public abstract class AchievementConditionBase : ISerializationCallbackReceiver { protected static List _aroundBuf; public virtual void OnBeforeSerialize() { } public virtual void OnAfterDeserialize() { } public abstract AchievementConditionType GetConditionType(); public abstract void ClearCache(); public abstract bool CheckCondition(AchievementItem item, MapData map); public abstract void GetProgress(out int current, out int target); public abstract bool CheckChanged(AchievementConditionBase condition); public abstract void CopyChange(AchievementConditionBase condition); // 用于记录回退,所以期望一定是返回 false 从而回退成就,所以默认返回true public virtual bool ReCheckCondition() { return true; } public virtual void ClearUserData() { } public virtual void OnTurnStart(MapData map, PlayerData player) { } public virtual void OnTrainUnit(MapData map, PlayerData player, CityData city, UnitData newUnit) { } public virtual void OnBuildWonder(MapData map, PlayerData player, CityData city, GridData grid) { } public virtual void OnKillUnit(MapData map, UnitData origin, UnitData target) { } public virtual void OnUnitMove(MapData map, UnitData unit, GridData gridData) { } public virtual void OnGameEnd(MapData map, bool isWin) { } public virtual string GetConditionDescription() { return string.Empty; } } [DoNotObfuscateClass] [Serializable] public class TrainGiantCondition : AchievementConditionBase { public int TargetCount; public GiantType TargetGiant; public int TrainCount; public TrainGiantCondition() { TargetCount = 1; TrainCount = 0; TargetGiant = GiantType.None; } public override AchievementConditionType GetConditionType() { return AchievementConditionType.TrainGiant; } public override void OnGameEnd(MapData map, bool isWin) { if (!isWin) return; if (map == null) return; var player = map.PlayerMap.SelfPlayerData; if (player == null) return; if (!player.PlayerHeroData.HasHero(TargetGiant)) return; TrainCount++; } public override void ClearCache() { } public override void ClearUserData() { TrainCount = 0; } public override bool CheckCondition(AchievementItem item, MapData map) { return TrainCount >= TargetCount; } public override void GetProgress(out int current, out int target) { current = Mathf.Min(TrainCount, TargetCount); target = TargetCount; } public override void CopyChange(AchievementConditionBase condition) { var cond = condition as TrainGiantCondition; if (cond == null) return; if (TargetGiant != cond.TargetGiant) return; TrainCount += cond.TrainCount; } public override bool ReCheckCondition() { return TrainCount >= TargetCount; } public override bool CheckChanged(AchievementConditionBase condition) { var cond = condition as TrainGiantCondition; if (cond == null) return true; TargetGiant = cond.TargetGiant; TargetCount = cond.TargetCount; return false; } } [DoNotObfuscateClass] [Serializable] public class BuildWonderConditionCondition : AchievementConditionBase { public int TargetCount; public WonderLibrary Wonder; public int BuildCount; public BuildWonderConditionCondition() { TargetCount = 1; BuildCount = 0; Wonder = WonderLibrary.EgyptianRemiliaPEACE; } public override AchievementConditionType GetConditionType() { return AchievementConditionType.BuildWonder; } public override void OnBuildWonder(MapData map, PlayerData player, CityData city, GridData grid) { //if (player.Id != map.PlayerMap.SelfPlayerId) return; //if (grid.Wonder != Wonder) return; //BuildCount++; } public override void OnGameEnd(MapData map, bool isWin) { if (!isWin) return; if (map == null) return; var player = map.PlayerMap.SelfPlayerData; if (player == null) return; if (!player.Wonder.IsWonderLibraryBuilt(Wonder,player)) return; BuildCount++; } public override void ClearCache() { } public override bool CheckCondition(AchievementItem item, MapData map) { return BuildCount >= TargetCount; } public override void GetProgress(out int current, out int target) { current = Mathf.Min(BuildCount, TargetCount); target = TargetCount; } public override void CopyChange(AchievementConditionBase condition) { var cond = condition as BuildWonderConditionCondition; if (cond == null) return; if (Wonder != cond.Wonder) return; BuildCount += cond.BuildCount; } public override bool CheckChanged(AchievementConditionBase condition) { var cond = condition as BuildWonderConditionCondition; if (cond == null) return true; Wonder = cond.Wonder; TargetCount = cond.TargetCount; return false; } } [DoNotObfuscateClass] [Serializable] public class WonderInCityConditionCondition : AchievementConditionBase { public WonderLibrary Wonder; public CityLibrary TargetCity; public WonderInCityConditionCondition() { TargetCity = CityLibrary.Cairo; } public override AchievementConditionType GetConditionType() { return AchievementConditionType.WonderInCity; } public override void ClearCache() { } public override bool CheckCondition(AchievementItem item, MapData map) { var cityList = new List(); map.GetCityDataListByPlayerId(map.PlayerMap.SelfPlayerId, cityList); foreach (var city in cityList) { if (city.CityInfo != TargetCity) continue; foreach (var gridId in city.Territory.TerritoryArea) { if (!map.GridMap.GetGridDataByGid(gridId, out var gridData)) continue; if (gridData.Wonder != Wonder) continue; return true; } } return false; } public override void GetProgress(out int current, out int target) { current = 0; target = 1; } public override void CopyChange(AchievementConditionBase condition) { var cond = condition as WonderInCityConditionCondition; if (cond == null) return; if (Wonder != cond.Wonder) return; } public override bool CheckChanged(AchievementConditionBase condition) { var cond = condition as WonderInCityConditionCondition; if (cond == null) return true; Wonder = cond.Wonder; TargetCity = cond.TargetCity; return false; } } [DoNotObfuscateClass] [Serializable] public class UnitOnWonderConditionCondition : AchievementConditionBase { public WonderLibrary Wonder; public GiantType Giant; public int TargetTurns; public uint RecordTurn; public uint _gridId; public UnitOnWonderConditionCondition() { Wonder = WonderLibrary.EgyptianRemiliaEYE; Giant = GiantType.None; TargetTurns = 1; RecordTurn = 0; _gridId = 0; } public override AchievementConditionType GetConditionType() { return AchievementConditionType.UnitOnWonder; } public override void OnTurnStart(MapData map, PlayerData player) { } public override void ClearCache() { RecordTurn = 0; } public override bool CheckCondition(AchievementItem item, MapData map) { if (map == null) return false; if (!map.GridMap.GetGridDataByGid(_gridId, out var gridData)) { foreach (var grid in map.GridMap.GridList) { if (grid.Wonder != Wonder) continue; gridData = grid; break; } } if (gridData == null) { RecordTurn = map.PlayerMap.SelfPlayerData.Turn; return false; } _gridId = gridData.Id; if (!gridData.RealUnit(map,out var unitData)) { RecordTurn = map.PlayerMap.SelfPlayerData.Turn; return false; } if (unitData.UnitFullType.GiantType != Giant) { RecordTurn = map.PlayerMap.SelfPlayerData.Turn; return false; } return RecordTurn + TargetTurns <= map.PlayerMap.SelfPlayerData.Turn; } public override void GetProgress(out int current, out int target) { current = Mathf.Min((int)RecordTurn, TargetTurns); target = TargetTurns; } public override void CopyChange(AchievementConditionBase condition) { var cond = condition as UnitOnWonderConditionCondition; if (cond == null) return; if (Wonder != cond.Wonder) return; } public override bool CheckChanged(AchievementConditionBase condition) { var cond = condition as UnitOnWonderConditionCondition; if (cond == null) return true; Wonder = cond.Wonder; Giant = cond.Giant; TargetTurns = cond.TargetTurns; return false; } } [DoNotObfuscateClass] [Serializable] public class AroundBuildingsConditionCondition : AchievementConditionBase { public WonderLibrary Wonder; public int OffsetX; public int OffsetY; public int TargetCount; public TerrainType Terrain; public TerrainFeature Feature; public Vegetation Vegetation; public ResourceType Resource; private uint _gridId; private int _recordCount; public AroundBuildingsConditionCondition() { OffsetX = 1; OffsetY = 1; TargetCount = 1; Terrain = TerrainType.None; Feature = TerrainFeature.None; Vegetation = Vegetation.None; Resource = ResourceType.None; } public override AchievementConditionType GetConditionType() { return AchievementConditionType.AroundBuildings; } public override void ClearCache() { } public override bool CheckCondition(AchievementItem item, MapData map) { if (map == null) return false; _recordCount = 0; if (!map.GridMap.GetGridDataByGid(_gridId, out var gridData)) { foreach (var grid in map.GridMap.GridList) { if (grid.Wonder != Wonder) continue; gridData = grid; break; } } if (gridData == null) return false; _gridId = gridData.Id; _aroundBuf ??= new List(); _aroundBuf.Clear(); map.GridMap.GetAroundGridData(OffsetX, OffsetY, gridData, _aroundBuf); foreach (var aroundGrid in _aroundBuf) { if (Terrain != TerrainType.None && aroundGrid.Terrain == Terrain) _recordCount++; if (Feature != TerrainFeature.None && aroundGrid.Feature == Feature) _recordCount++; if (Vegetation != Vegetation.None && aroundGrid.Vegetation == Vegetation) _recordCount++; if (Resource != ResourceType.None && aroundGrid.Resource == Resource) _recordCount++; } return _recordCount >= TargetCount; } public override void GetProgress(out int current, out int target) { current = Mathf.Min(_recordCount, TargetCount); target = TargetCount; } public override void CopyChange(AchievementConditionBase condition) { var cond = condition as AroundBuildingsConditionCondition; if (cond == null) return; } public override bool CheckChanged(AchievementConditionBase condition) { var cond = condition as AroundBuildingsConditionCondition; if (cond == null) return true; Wonder = cond.Wonder; OffsetX = cond.OffsetX; OffsetY = cond.OffsetY; TargetCount = cond.TargetCount; Terrain = cond.Terrain; Feature = cond.Feature; Vegetation = cond.Vegetation; Resource = cond.Resource; return false; } } [DoNotObfuscateClass] [Serializable] public class AroundWondersConditionCondition : AchievementConditionBase { public WonderLibrary Wonder; public WonderLibrary AroundWonder; public int OffsetX; public int OffsetY; public int TargetCount; private uint _gridId; private uint _recordCount; public AroundWondersConditionCondition() { OffsetX = 1; OffsetY = 1; TargetCount = 1; } public override AchievementConditionType GetConditionType() { return AchievementConditionType.AroundWonders; } public override void ClearCache() { } public override bool CheckCondition(AchievementItem item, MapData map) { if (map == null) return false; _recordCount = 0; if (!map.GridMap.GetGridDataByGid(_gridId, out var gridData)) { foreach (var grid in map.GridMap.GridList) { if (grid.Wonder != Wonder) continue; gridData = grid; break; } } if (gridData == null) return false; _gridId = gridData.Id; _aroundBuf ??= new List(); _aroundBuf.Clear(); map.GridMap.GetAroundGridData(OffsetX, OffsetY, gridData, _aroundBuf); foreach (var aroundGrid in _aroundBuf) { if (aroundGrid.Wonder == AroundWonder) _recordCount++; } return _recordCount >= TargetCount; } public override void GetProgress(out int current, out int target) { current = Mathf.Min((int)_recordCount, TargetCount); target = TargetCount; } public override void CopyChange(AchievementConditionBase condition) { var cond = condition as AroundWondersConditionCondition; if (cond == null) return; } public override bool CheckChanged(AchievementConditionBase condition) { var cond = condition as AroundWondersConditionCondition; if (cond == null) return true; Wonder = cond.Wonder; AroundWonder = cond.AroundWonder; OffsetX = cond.OffsetX; OffsetY = cond.OffsetY; TargetCount = cond.TargetCount; return false; } } [DoNotObfuscateClass] [Serializable] public class AroundEnemyUnitsConditionCondition : AchievementConditionBase { public WonderLibrary Wonder; public int TargetCount; public int OffsetX; public int OffsetY; private uint _gridId; private uint _recordCount; public AroundEnemyUnitsConditionCondition() { OffsetX = 1; OffsetY = 1; TargetCount = 1; } public override AchievementConditionType GetConditionType() { return AchievementConditionType.AroundEnemyUnits; } public override void ClearCache() { } public override bool CheckCondition(AchievementItem item, MapData map) { if (map == null) return false; if (!map.GridMap.GetGridDataByGid(_gridId, out var gridData)) { foreach (var grid in map.GridMap.GridList) { if (grid.Wonder != Wonder) continue; gridData = grid; break; } } if (gridData == null) return false; _gridId = gridData.Id; _aroundBuf ??= new List(); _aroundBuf.Clear(); map.GridMap.GetAroundGridData(OffsetX, OffsetY, gridData, _aroundBuf); _recordCount = 0; using var pooledSelfUnits = THCollectionPool.GetHashSetHandle(out var selfUnits); map.GetUnitDataListByPlayerId(map.PlayerMap.SelfPlayerId, selfUnits); foreach (var aroundGrid in _aroundBuf) { if (!aroundGrid.RealUnit(map, out var unit)) continue; if (selfUnits.Contains(unit)) continue; _recordCount++; } return _recordCount >= TargetCount; } public override void GetProgress(out int current, out int target) { current = Mathf.Min((int)_recordCount, TargetCount); target = TargetCount; } public override void CopyChange(AchievementConditionBase condition) { var cond = condition as AroundEnemyUnitsConditionCondition; if (cond == null) return; } public override bool CheckChanged(AchievementConditionBase condition) { var cond = condition as AroundEnemyUnitsConditionCondition; if (cond == null) return true; Wonder = cond.Wonder; TargetCount = cond.TargetCount; OffsetX = cond.OffsetX; OffsetY = cond.OffsetY; return false; } } [DoNotObfuscateClass] [Serializable] public class AroundSelfUnitsConditionCondition : AchievementConditionBase { public WonderLibrary Wonder; public int TargetCount; public int OffsetX; public int OffsetY; private uint _gridId; private uint _recordCount; public AroundSelfUnitsConditionCondition() { OffsetX = 1; OffsetY = 1; TargetCount = 1; } public override AchievementConditionType GetConditionType() { return AchievementConditionType.AroundSelfUnits; } public override void ClearCache() { } public override bool CheckCondition(AchievementItem item, MapData map) { if (map == null) return false; if (!map.GridMap.GetGridDataByGid(_gridId, out var gridData)) { foreach (var grid in map.GridMap.GridList) { if (grid.Wonder != Wonder) continue; gridData = grid; break; } } if (gridData == null) return false; _gridId = gridData.Id; _aroundBuf ??= new List(); _aroundBuf.Clear(); map.GridMap.GetAroundGridData(OffsetX, OffsetY, gridData, _aroundBuf); _recordCount = 0; using var pooledSelfUnits = THCollectionPool.GetHashSetHandle(out var selfUnits); map.GetUnitDataListByPlayerId(map.PlayerMap.SelfPlayerId, selfUnits); foreach (var aroundGrid in _aroundBuf) { if (!aroundGrid.RealUnit(map, out var unit)) continue; if (!selfUnits.Contains(unit)) continue; _recordCount++; } return _recordCount >= TargetCount; } public override void GetProgress(out int current, out int target) { current = Mathf.Min((int)_recordCount, TargetCount); target = TargetCount; } public override void CopyChange(AchievementConditionBase condition) { var cond = condition as AroundSelfUnitsConditionCondition; if (cond == null) return; } public override bool CheckChanged(AchievementConditionBase condition) { var cond = condition as AroundSelfUnitsConditionCondition; if (cond == null) return true; Wonder = cond.Wonder; TargetCount = cond.TargetCount; OffsetX = cond.OffsetX; OffsetY = cond.OffsetY; return false; } } [DoNotObfuscateClass] [Serializable] public class AroundCityGridsConditionCondition : AchievementConditionBase { public WonderLibrary Wonder; public CityLibrary TargetCity; public int TargetCount; public int OffsetX; public int OffsetY; private uint _gridId; private uint _recordCount; public AroundCityGridsConditionCondition() { OffsetX = 1; OffsetY = 1; } public override AchievementConditionType GetConditionType() { return AchievementConditionType.AroundCityGrids; } public override void ClearCache() { } public override bool CheckCondition(AchievementItem item, MapData map) { if (map == null) return false; if (!map.GridMap.GetGridDataByGid(_gridId, out var gridData)) { foreach (var grid in map.GridMap.GridList) { if (grid.Wonder != Wonder) continue; gridData = grid; break; } } if (gridData == null) return false; _gridId = gridData.Id; _aroundBuf ??= new List(); _aroundBuf.Clear(); map.GridMap.GetAroundGridData(OffsetX, OffsetY, gridData, _aroundBuf); _recordCount = 0; foreach (var aroundGrid in _aroundBuf) { if (!map.GetCityDataByTerritoryGid(aroundGrid.Id, out var city)) continue; if (city.CityInfo != TargetCity) continue; _recordCount++; } return _recordCount >= TargetCount; } public override void GetProgress(out int current, out int target) { current = Mathf.Min((int)_recordCount, TargetCount); target = TargetCount; } public override void CopyChange(AchievementConditionBase condition) { var cond = condition as AroundSelfUnitsConditionCondition; if (cond == null) return; } public override bool CheckChanged(AchievementConditionBase condition) { var cond = condition as AroundCityGridsConditionCondition; if (cond == null) return true; Wonder = cond.Wonder; TargetCity = cond.TargetCity; TargetCount = cond.TargetCount; OffsetX = cond.OffsetX; OffsetY = cond.OffsetY; return false; } } }