/* * @Author: 白哉 * @Description: 行为逻辑类 * @Date: 2025年04月10日 星期四 11:04:44 * @Modify: */ using System; using System.Collections.Generic; using Logic.AI; using Logic.CrashSight; using Logic.Skill; using MemoryPack; using RuntimeData; using TH1_Anim; using TH1_Anim.Fragments; using TH1_Core.Events; using TH1_Core.Managers; using TH1_Logic.Action; using TH1_Logic.Core; using TH1_Presentation.Sequencer.Task; using TH1_Renderer; using TH1_Logic.Net; using TH1_Logic.Steam; using UnityEngine; using TH1Renderer; //记录ActionCheckCan失败时的原因 public enum ShowType { None, Locked, Cost, Done, Send, Cold, } namespace Logic.Action { // 行为类型枚举 public enum CommonActionType { Gain, Build, StartWonder, BuildWonder, TrainUnit, GridMisc, UnitAction, CityLevelUpAction, UnitSkill, LearnTech, UnitMove, UnitAttack, PlayerAction, TurnStart, TurnEnd, UnitPassiveMove, AIParamControl, UnitAttackAlly, UnitAttackGround, } public enum ActionShowState { None, Available, Unavailable, Expensive, Finished } public enum AIParamControlType { AllClear, APClear, MPClear, CPClear, AIMoney, Max, } // 通用行为参数类 [MemoryPackable] public partial class CommonActionParams { [MemoryPackIgnore] public MapData MapData; [MemoryPackIgnore] public PlayerData PlayerData; [MemoryPackIgnore] public UnitData UnitData; [MemoryPackIgnore] public CityData CityData; [MemoryPackIgnore] public GridData GridData; [MemoryPackIgnore] public UnitData TargetUnitData; [MemoryPackIgnore] public GridData TargetGridData; [MemoryPackIgnore] public PlayerData TargetPlayerData; public MainObjectType MainObjectType; public uint PlayerId; public uint UnitId; public uint CityId; public uint GridId; public uint TargetUnitId; public uint TargetGridId; public uint TargetPlayerId; [MemoryPackConstructor] public CommonActionParams() { } //必须走这个函数新建,否则需要调用下方的OnParamChanged刷新属性状态 public CommonActionParams(MapData mapData=null, PlayerData playerData=null, UnitData unitData=null, CityData cityData=null, GridData gridData=null, UnitData targetUnit=null, GridData targetGrid=null, PlayerData targetPlayer = null,MainObjectType mainObjectType=MainObjectType.None) { MapData = mapData; PlayerData = playerData; UnitData = unitData; CityData = cityData; GridData = gridData; TargetUnitData = targetUnit; TargetGridData = targetGrid; TargetPlayerData = targetPlayer; MainObjectType = mainObjectType; PlayerId = 0; UnitId = 0; CityId = 0; GridId = 0; TargetUnitId = 0; TargetGridId = 0; TargetPlayerId = 0; if (PlayerData != null) PlayerId = PlayerData.Id; if (UnitData != null) UnitId = UnitData.Id; if (CityData != null) CityId = CityData.Id; if (GridData != null) GridId = GridData.Id; if (TargetUnitData != null) TargetUnitId = TargetUnitData.Id; if (TargetGridData != null) TargetGridId = TargetGridData.Id; if (TargetPlayerData != null) TargetPlayerId = TargetPlayerData.Id; } public void RefreshParams() { if (PlayerId != 0 && MapData.PlayerMap.GetPlayerDataByPlayerID(PlayerId, out var player)) { PlayerData = player; } if (UnitId != 0 && MapData.UnitMap.GetUnitDataByUnitId(UnitId, out var unit)) { UnitData = unit; } if (CityId != 0 && MapData.CityMap.GetCityById(CityId, out var city)) { CityData = city; } if (GridId != 0 && MapData.GridMap.GetGridDataByGid(GridId, out var grid)) { GridData = grid; } if (TargetUnitId != 0 && MapData.UnitMap.GetUnitDataByUnitId(TargetUnitId, out var target)) { TargetUnitData = target; } if (TargetGridId != 0 && MapData.GridMap.GetGridDataByGid(TargetGridId, out var targetGrid)) { TargetGridData = targetGrid; } if (TargetPlayerId != 0 && MapData.PlayerMap.GetPlayerDataByPlayerID(TargetPlayerId, out var targetPlayer)) { TargetPlayerData = targetPlayer; } } public void OnParamChanged() { if (PlayerData != null) PlayerId = PlayerData.Id; else PlayerId = 0; if (UnitData != null) UnitId = UnitData.Id; else UnitId = 0; if (CityData != null) CityId = CityData.Id; else CityId = 0; if (GridData != null) GridId = GridData.Id; else GridId = 0; if (TargetUnitData != null) TargetUnitId = TargetUnitData.Id; else TargetUnitId = 0; if (TargetGridData != null) TargetGridId = TargetGridData.Id; else TargetGridId = 0; if (TargetPlayerData != null) TargetPlayerId = TargetPlayerData.Id; else TargetPlayerId = 0; } public CommonActionParams GetCopyParam() { var param = new CommonActionParams(); param.MapData = MapData; param.PlayerData = PlayerData; param.UnitData = UnitData; param.CityData = CityData; param.GridData = GridData; param.TargetUnitData = TargetUnitData; param.TargetGridData = TargetGridData; param.TargetPlayerData = TargetPlayerData; param.MainObjectType = MainObjectType; param.PlayerId = PlayerId; param.UnitId = UnitId; param.CityId = CityId; param.GridId = GridId; param.TargetUnitId = TargetUnitId; param.TargetGridId = TargetGridId; param.TargetPlayerId = TargetPlayerId; return param; } public string GetStringLog() { var log = $""; log += $"MainObjectType : {MainObjectType}\n"; log += $"PlayerId : {PlayerId}\n"; log += $"UnitId : {UnitId}\n"; log += $"CityId : {CityId}\n"; log += $"GridId : {GridId}\n"; log += $"TargetUnitId : {TargetUnitId}\n"; log += $"TargetGridId : {TargetGridId}\n"; log += $"TargetPlayerId : {TargetPlayerId}\n"; return log; } public string GetNotSameLog(CommonActionParams other) { var log = $""; if (MainObjectType != other.MainObjectType) log += $"MainObjectType : {MainObjectType}\n"; if (PlayerId != other.PlayerId) log += $"PlayerId : {PlayerId}\n"; if (UnitId != other.UnitId) log += $"UnitId : {UnitId}\n"; if (CityId != other.CityId) log += $"CityId : {CityId}\n"; if (GridId != other.GridId) log += $"GridId : {GridId}\n"; if (TargetUnitId != other.TargetUnitId) log += $"TargetUnitId : {TargetUnitId}\n"; if (TargetGridId != other.TargetGridId) log += $"TargetGridId : {TargetGridId}\n"; if (TargetPlayerId != other.TargetPlayerId) log += $"TargetPlayerId : {TargetPlayerId}\n"; return log; } } // 通用行为ID类 [Serializable] [MemoryPackable] public partial class CommonActionId { public CommonActionType ActionType; public WonderTypeEnum WonderType; public ResourceType ResourceType; public TerrainFeature FeatureType; public TerrainType TerrainType; public UnitType UnitType; public GiantType GiantType; public uint UnitLevel; public Vegetation Vegetation; public UnitActionType UnitActionType; public CityLevelUpActionType CityLevelUpActionType; public GridMiscActionType GridMiscActionType; public SkillType SkillType; public TechType TechType; public PlayerActionType PlayerActionType; public AIParamControlType AIParamType; [MemoryPackConstructor] public CommonActionId() { } //自动生成唯一Id Hash public uint Id => ComputeId(); private uint ComputeId() { unchecked // 溢出安全 { int hash = 17; hash = hash * 31 + ActionType.GetHashCode(); hash = hash * 31 + WonderType.GetHashCode(); hash = hash * 31 + ResourceType.GetHashCode(); hash = hash * 31 + FeatureType.GetHashCode(); hash = hash * 31 + TerrainType.GetHashCode(); hash = hash * 31 + UnitType.GetHashCode(); hash = hash * 31 + GiantType.GetHashCode(); hash = hash * 31 + UnitLevel.GetHashCode(); hash = hash * 31 + Vegetation.GetHashCode(); hash = hash * 31 + UnitActionType.GetHashCode(); hash = hash * 31 + CityLevelUpActionType.GetHashCode(); hash = hash * 31 + GridMiscActionType.GetHashCode(); hash = hash * 31 + SkillType.GetHashCode(); hash = hash * 31 + TechType.GetHashCode(); hash = hash * 31 + PlayerActionType.GetHashCode(); hash = hash * 31 + AIParamType.GetHashCode(); return (uint)hash; } } // 重载 == 运算符 当属性被修改时需要修改运算符重载方法 public static bool operator ==(CommonActionId a, CommonActionId b) { if (a is null) return b is null; if (b is null) return false; if (a.ActionType != b.ActionType) return false; if (a.WonderType != b.WonderType) return false; if (a.ResourceType != b.ResourceType) return false; if (a.TerrainType != b.TerrainType) return false; if (a.FeatureType != b.FeatureType) return false; if (a.UnitType != b.UnitType) return false; if (a.GiantType != b.GiantType) return false; if (a.UnitLevel != b.UnitLevel) return false; if (a.Vegetation != b.Vegetation) return false; if (a.UnitActionType != b.UnitActionType) return false; if (a.CityLevelUpActionType != b.CityLevelUpActionType) return false; if (a.GridMiscActionType != b.GridMiscActionType) return false; if (a.SkillType != b.SkillType) return false; if (a.TechType != b.TechType) return false; if (a.PlayerActionType != b.PlayerActionType) return false; if (a.AIParamType != b.AIParamType) return false; return true; } // 必须同时重载 != 运算符 public static bool operator !=(CommonActionId a, CommonActionId b) { return !(a == b); } public override int GetHashCode() { // 直接调用你的哈希计算逻辑,并转换为int return (int)ComputeId(); } public override bool Equals(object obj) { // 调用类型安全的Equals方法 return Equals(obj as CommonActionId); } public bool Equals(CommonActionId other) { // 如果另一个对象是null,它们不相等 if (other is null) { return false; } // 如果它们是同一个内存中的对象,它们肯定相等 if (ReferenceEquals(this, other)) { return true; } // 调用你已经写好的比较逻辑! // 我们可以直接使用你重载的 `==` 运算符,这样可以重用代码。 return this == other; } public string GetStringLog() { var log = $""; log += $"Action : {ActionType}\n"; log += $"Wonder : {WonderType}\n"; log += $"Resource : {ResourceType}\n"; log += $"Feature : {FeatureType}\n"; log += $"Terrain : {TerrainType}\n"; log += $"Unit : {UnitType}\n"; log += $"Giant : {GiantType}\n"; log += $"Vegetation : {Vegetation}\n"; log += $"UnitAction : {UnitActionType}\n"; log += $"CityLevelUpAction : {CityLevelUpActionType}\n"; log += $"GridMiscAction : {GridMiscActionType}\n"; log += $"Skill : {SkillType}\n"; log += $"Tech : {TechType}\n"; log += $"PlayerAction : {PlayerActionType}\n"; log += $"AIParam : {AIParamType}\n"; log += $"Tech : {TechType}\n"; return log; } } // 行为逻辑工厂类 public static class ActionLogicFactory { private static Dictionary ActionLogicDict; private static Dictionary _actionLogicIdDict; public static Dictionary GetActionLogicDict() { Refresh(); return ActionLogicDict; } public static Dictionary GetActionLogicIDDict() { Refresh(); return _actionLogicIdDict; } public static void RefreshPlayerAction() { CommonActionId commonActionId; //填加外交行为 foreach (PlayerActionType playerActionType in System.Enum.GetValues(typeof(PlayerActionType))) { if (playerActionType == PlayerActionType.None) continue; commonActionId = new CommonActionId { ActionType = CommonActionType.PlayerAction, PlayerActionType = playerActionType }; ActionLogicDict[commonActionId] = new PlayerActionDiplomacy(commonActionId); } //填加英雄相关行为 foreach (GiantType giantType in System.Enum.GetValues(typeof(GiantType))) { if (giantType == GiantType.None) continue; //选择英雄 commonActionId = new CommonActionId { ActionType = CommonActionType.PlayerAction, PlayerActionType = PlayerActionType.SelectHero, GiantType = giantType }; ActionLogicDict[commonActionId] = new PlayerActionSelectHero(commonActionId); //强制完成英雄的任务 commonActionId = new CommonActionId { ActionType = CommonActionType.PlayerAction, PlayerActionType = PlayerActionType.FinishHeroTask, GiantType = giantType }; ActionLogicDict[commonActionId] = new PlayerActionFinishHeroTask(commonActionId); } } public static void Refresh() { if (ActionLogicDict != null) return; ActionLogicDict = new Dictionary(); CommonActionId commonActionId; // 移动和攻击 Action 入库 commonActionId = new CommonActionId { ActionType = CommonActionType.UnitMove }; ActionLogicDict[commonActionId] = new UnitMoveAction(commonActionId); commonActionId = new CommonActionId { ActionType = CommonActionType.UnitAttack }; ActionLogicDict[commonActionId] = new UnitAttackAction(commonActionId); commonActionId = new CommonActionId { ActionType = CommonActionType.UnitAttackGround }; ActionLogicDict[commonActionId] = new UnitAttackGroundAction(commonActionId); commonActionId = new CommonActionId { ActionType = CommonActionType.UnitPassiveMove }; ActionLogicDict[commonActionId] = new UnitPassiveMoveAction(commonActionId); commonActionId = new CommonActionId { ActionType = CommonActionType.UnitAttackAlly }; ActionLogicDict[commonActionId] = new UnitAttackAllyAction(commonActionId); // 回合开始和结束 Action 入库 commonActionId = new CommonActionId { ActionType = CommonActionType.TurnStart }; ActionLogicDict[commonActionId] = new PlayerTurnStartAction(commonActionId); commonActionId = new CommonActionId { ActionType = CommonActionType.TurnEnd }; ActionLogicDict[commonActionId] = new PlayerTurnEndAction(commonActionId); for (int i = (int)AIParamControlType.AllClear; i < (int)AIParamControlType.Max; i++) { commonActionId = new CommonActionId { ActionType = CommonActionType.AIParamControl, AIParamType = (AIParamControlType)i, }; ActionLogicDict[commonActionId] = new AIParamControlAction(commonActionId); } for (int i = (int)PlayerActionType.OfferAlly; i < (int)PlayerActionType.Max; i++) { commonActionId = new CommonActionId { ActionType = CommonActionType.PlayerAction, PlayerActionType = (PlayerActionType)i, }; ActionLogicDict[commonActionId] = new PlayerActionDiplomacy(commonActionId); } foreach (ResourceType resourceType in System.Enum.GetValues(typeof(ResourceType))) { if (resourceType == ResourceType.None) continue; // 先登记所有Gain 收获一次性资源的行为逻辑 if (resourceType == ResourceType.Animal || resourceType == ResourceType.Fish || resourceType == ResourceType.Fruit) { commonActionId = new CommonActionId { ActionType = CommonActionType.Gain, ResourceType = resourceType, }; ActionLogicDict[commonActionId] = new GainResourceAction(commonActionId); continue; } // 登记Build 建设建筑的行为逻辑 commonActionId = new CommonActionId { ActionType = CommonActionType.Build, ResourceType = resourceType, }; switch (resourceType) { case ResourceType.ForestTemple: case ResourceType.WaterTemple: case ResourceType.Temple: case ResourceType.MountainTemple: case ResourceType.KingTemple: ActionLogicDict[commonActionId] = new BuildActionBuildTemple(commonActionId); continue; case ResourceType.Preserve: ActionLogicDict[commonActionId] = new BuildActionBuildPreserve(commonActionId); continue; case ResourceType.NavalBase: ActionLogicDict[commonActionId] = new BuildActionBuildNavalBase(commonActionId); continue; case ResourceType.KaguyaFrenchYard: ActionLogicDict[commonActionId] = new BuildActionBuildKaguyaFrenchYard(commonActionId); continue; case ResourceType.EgyptianIrrigation: ActionLogicDict[commonActionId] = new BuildActionBuildEgyptianIrrigation(commonActionId); continue; case ResourceType.RemiliaMilitary: ActionLogicDict[commonActionId] = new BuildActionBuildRemiliaMilitary(commonActionId); continue; case ResourceType.MetalStation: ActionLogicDict[commonActionId] = new BuildActionBuildMetalStation(commonActionId); continue; case ResourceType.MoriyaMilitary: ActionLogicDict[commonActionId] = new BuildActionBuildMoriyaMilitary(commonActionId); continue; default: ActionLogicDict[commonActionId] = new BuildAction(commonActionId); continue; } } //登记build road这种特殊情况 commonActionId = new CommonActionId { ActionType = CommonActionType.Build, FeatureType = TerrainFeature.Road }; ActionLogicDict[commonActionId] = new BuildAction(commonActionId); //GridMisc grid的杂类行为逻辑 foreach (GridMiscActionType gridMiscActionType in System.Enum.GetValues(typeof(GridMiscActionType))) { if (gridMiscActionType == GridMiscActionType.None) continue; commonActionId = new CommonActionId { ActionType = CommonActionType.GridMisc, GridMiscActionType = gridMiscActionType }; switch (gridMiscActionType) { case GridMiscActionType.UpgradeTemple: ActionLogicDict[commonActionId] = new GridMiscActionUpgradeTemple(commonActionId); continue; case GridMiscActionType.GrowForestOutside: ActionLogicDict[commonActionId] = new GridMiscActionGrowTreeOutside(commonActionId); continue; case GridMiscActionType.CreateMountain: ActionLogicDict[commonActionId] = new GridMiscActionCreateMountain(commonActionId); continue; case GridMiscActionType.SellMetal: ActionLogicDict[commonActionId] = new GridMiscActionSellMetal(commonActionId); continue; default: ActionLogicDict[commonActionId] = new GridMiscAction(commonActionId); continue; }; } //登记BuildWonder建造奇观的行为逻辑 foreach (WonderTypeEnum wonderType in System.Enum.GetValues(typeof(WonderTypeEnum))) { if(wonderType == WonderTypeEnum.None) continue; //登记建造奇观的action commonActionId = new CommonActionId { ActionType = CommonActionType.BuildWonder, WonderType = wonderType, }; ActionLogicDict[commonActionId] = new BuildWonderAction(commonActionId); //登记建造开启奇观任务的action commonActionId = new CommonActionId { ActionType = CommonActionType.StartWonder, WonderType = wonderType, }; ActionLogicDict[commonActionId] = new StartWonderAction(commonActionId); } // TrainUnit 建造unit的行为逻辑 foreach (UnitType unitType in Enum.GetValues(typeof(UnitType))) { if(unitType == UnitType.None) continue; if (unitType == UnitType.Giant) { foreach (GiantType giantType in Enum.GetValues(typeof(GiantType))) { if(giantType == GiantType.None) continue; commonActionId = new CommonActionId { ActionType = CommonActionType.TrainUnit, UnitType = unitType, GiantType = giantType }; //Debug.Log(ActionId.GiantType); ActionLogicDict[commonActionId] = new TrainUnitActionTrainHero(commonActionId); } continue; } commonActionId = new CommonActionId { ActionType = CommonActionType.TrainUnit, UnitType = unitType, }; if (unitType == UnitType.KaguyaFrenchAnimalWarrior) ActionLogicDict[commonActionId] = new TrainUnitActionTrainKaguyaFrenchAnimalWarrior(commonActionId); else ActionLogicDict[commonActionId] = new TrainUnitAction(commonActionId); } //cityLevelUp的各个行为逻辑 foreach (CityLevelUpActionType cityLevelUpActionType in System.Enum.GetValues(typeof(CityLevelUpActionType))) { if(cityLevelUpActionType == CityLevelUpActionType.None) continue; commonActionId = new CommonActionId { ActionType = CommonActionType.CityLevelUpAction, CityLevelUpActionType = cityLevelUpActionType }; ActionLogicDict[commonActionId] = new CityLevelUpActionAction(commonActionId); } //unitAction自身行为的各个行为逻辑 foreach (UnitActionType unitActionType in System.Enum.GetValues(typeof(UnitActionType))) { commonActionId = new CommonActionId { ActionType = CommonActionType.UnitAction, UnitActionType = unitActionType }; switch (unitActionType) { case UnitActionType.None: continue; case UnitActionType.HeroUpgrade: ActionLogicDict[commonActionId] = new UnitActionGiantUpgrade(commonActionId); continue; case UnitActionType.ROYALFLAMESPRO: ActionLogicDict[commonActionId] = new UnitActionROYALFLAMESPRO(commonActionId); continue; case UnitActionType.HEAL: ActionLogicDict[commonActionId] = new UnitActionHEAL(commonActionId); continue; case UnitActionType.TEWIFRENCHBUFF: ActionLogicDict[commonActionId] = new UnitActionTEWIFRENCHBUFF(commonActionId); continue; case UnitActionType.MOKOUFRENCHBOOM: ActionLogicDict [commonActionId] = new UnitActionMOKOUFRENCHBOOM(commonActionId); continue; case UnitActionType.KAGUYAFRENCHAROUND: ActionLogicDict [commonActionId] = new UnitActionKAGUYAFRENCHAROUND(commonActionId); continue; case UnitActionType.ForceDisband: ActionLogicDict [commonActionId] = new UnitActionForceDisband(commonActionId); continue; case UnitActionType.RemoveRedMist: ActionLogicDict [commonActionId] = new UnitActionRemoveRedMist(commonActionId); continue; case UnitActionType.REMILIABUFF: ActionLogicDict [commonActionId] = new UnitActionREMILIABUFF(commonActionId); continue; case UnitActionType.AbsorbRedMist: ActionLogicDict [commonActionId] = new UnitActionAbsorbRedMist(commonActionId); continue; case UnitActionType.REMILIAABSORB: ActionLogicDict [commonActionId] = new UnitActionRemiliaAbsorb(commonActionId); continue; case UnitActionType.KANAKOSIT: ActionLogicDict [commonActionId] = new UnitActionKanakoSit(commonActionId); continue; case UnitActionType.KANAKOUNSIT: ActionLogicDict [commonActionId] = new UnitActionKanakoUnSit(commonActionId); continue; case UnitActionType.AYAMOVEAGAIN: ActionLogicDict [commonActionId] = new UnitActionAyaMoveAgain(commonActionId); continue; default: ActionLogicDict[commonActionId] = new UnitActionAction(commonActionId); continue; } } foreach (UnitType unitType in Enum.GetValues(typeof(UnitType))) if(!(unitType is UnitType.None or UnitType.Giant) && Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(unitType,GiantType.None,0,out var info) && info.LandType == LandType.WaterAndAshore) { if (unitType == UnitType.Boat) continue; commonActionId = new CommonActionId { ActionType = CommonActionType.UnitAction, UnitType = unitType }; ActionLogicDict[commonActionId] = new UnitActionAction(commonActionId); } //登记所有学习科技的action foreach (TechType techType in System.Enum.GetValues(typeof(TechType))) { commonActionId = new CommonActionId { ActionType = CommonActionType.LearnTech, TechType = techType }; ActionLogicDict[commonActionId] = new LearnTechAction(commonActionId); } //登记6种unitskill类的科技,该科技会让该玩家当前的和未来的所有unit都拥有某个skill foreach (SkillType skillType in System.Enum.GetValues(typeof(SkillType))) { if (skillType == SkillType.MOUNTAINMOVE || skillType == SkillType.MOUNTAINDEFENSE || skillType == SkillType.WATERMOVE || skillType == SkillType.WATERDEFENSE || skillType == SkillType.OCEANMOVE || skillType == SkillType.OCEANDEFENSE || skillType == SkillType.FORESTDEFENSE) { commonActionId = new CommonActionId { ActionType = CommonActionType.UnitSkill, SkillType = skillType }; ActionLogicDict[commonActionId] = new UnitSkillAction(commonActionId); } } //登记playerAction RefreshPlayerAction(); if (_actionLogicIdDict == null) { _actionLogicIdDict = new Dictionary(); foreach (var kv in ActionLogicDict) { _actionLogicIdDict[kv.Key.Id] = kv.Value; } } } public static ActionLogicBase GetActionLogic(CommonActionId actionId) { Refresh(); foreach (var kv in ActionLogicDict) { if (kv.Key != actionId) continue; return kv.Value; } return null; } // 返回一个玩家有什么 Action public static bool PlayerHasAction(CommonActionParams param, out List actionList) { param.MainObjectType = MainObjectType.Player; actionList = new List(); var actionDict = GetActionLogicDict(); foreach (var action in actionDict.Values) { if(action.CheckCan(param)) actionList.Add(action); } return actionList.Count > 0; } //返回一个 grid 对于 player data 而言有什么 action public static bool GridHasAction(CommonActionParams param, out List actionList) { param.MainObjectType = MainObjectType.Grid; actionList = new List(); var actionDict = GetActionLogicDict(); foreach (var action in actionDict.Values) { if (!action.CheckCan(param)) continue; actionList.Add(action); } return actionList.Count > 0; } //返回一个 grid 对于 player data 而言有什么 action public static bool GridHasAction(CommonActionParams param, List actionList) { param.MainObjectType = MainObjectType.Grid; var actionDict = GetActionLogicDict(); bool hasAction = false; foreach (var action in actionDict.Values) { if (!action.CheckCan(param)) continue; actionList.Add(action); hasAction = true; } return hasAction; } public static bool CityHasAction(CommonActionParams param, out List actionList) { param.MainObjectType = MainObjectType.City; actionList = new List(); var actionDict = GetActionLogicDict(); foreach (var action in actionDict.Values) { if(action.CheckCan(param)) actionList.Add(action); } return actionList.Count > 0; } //返回一个 unit 对于 player data 而言有什么 action public static bool UnitHasAction(CommonActionParams param, out List actionList) { param.MainObjectType = MainObjectType.Unit; actionList = new List(); if (param.UnitData.CP <= 0) return false; var actionDict = GetActionLogicDict(); foreach (var action in actionDict.Values) { if (!action.CheckCan(param)) continue; actionList.Add(action); } return actionList.Count > 0; } // 返回一个 unit 的移动和攻击行为 public static bool UnitHasMoveAndAttackAction(MapData map, UnitData unit, out List actionList) { if (!unit.Alive) { actionList = null; return false; } var attackID = new CommonActionId { ActionType = CommonActionType.UnitAttack }; var moveId = new CommonActionId { ActionType = CommonActionType.UnitMove }; var attackAction = new UnitAttackAction(attackID); var moveAction = new UnitMoveAction(moveId); actionList = new List(); Main.UnitLogic.CalcUnitMoveInfo(map, unit.Id); foreach (var grid in map.GridMap.GridList) { var result = Main.UnitLogic.CheckUnitCanMoveOrAttack(map, unit, grid); if (result == MoveAttackType.None) continue; if (result == MoveAttackType.Attack) { if (unit.AP <= 0 || !map.GetUnitDataByGid(grid.Id, out var targetUnit)) continue; var param = new CommonActionParams(map, unitData:unit, targetUnit:targetUnit); param.RefreshParams(); actionList.Add(new AIActionBase(param, attackAction)); if (map.GetGridDataByUnitId(unit.Id, out var unitGrid)) { //Debug.Log($"生成Action 小兵攻击 {unit.Id}, 攻击范围{unit.GetAttackRange()}" +$"位置{unitGrid.Pos.X}, {unitGrid.Pos.Y}, " + $"目标 {targetUnit.Id}, " + $"目标位置{grid.Pos.X}, {grid.Pos.Y}"); } continue; } if (unit.MP > 0) { var param = new CommonActionParams(map, unitData:unit, gridData:grid); param.RefreshParams(); actionList.Add(new AIActionBase(param, moveAction)); } } return actionList.Count > 0; } //返回一个主体能够显示的action(注意,并非能“做”的action,有些行为没钱或者没科技,他也可以显示) public static bool MainObjectCanShowAction(CommonActionParams param, out List actionList,out List actionCantTypeList) { //注意,要将所有cityLevelUp直接屏蔽掉 在这里 actionList = new List(); actionCantTypeList = new List(); var actionDict = GetActionLogicDict(); foreach (var action in actionDict.Values) { if (!action.CheckShow(param,out var actionCantType)) continue; if (action.ActionId.ActionType == CommonActionType.CityLevelUpAction) continue; actionList.Add(action); actionCantTypeList.Add(actionCantType); } return actionList.Count > 0; } public static List GetActionLogicByType(CommonActionType type) { var actionList = new List(); foreach (var action in GetActionLogicDict().Values) { if (action.ActionId.ActionType != type) continue; actionList.Add(action); } return actionList; } public static MainObjectType GetMainObjectType(CommonActionType actionType) { if (actionType == CommonActionType.Gain) return MainObjectType.Grid; if (actionType == CommonActionType.Build) return MainObjectType.Grid; if (actionType == CommonActionType.StartWonder) return MainObjectType.Player; if (actionType == CommonActionType.BuildWonder) return MainObjectType.Grid; if (actionType == CommonActionType.TrainUnit) return MainObjectType.City; if (actionType == CommonActionType.GridMisc) return MainObjectType.Grid; if (actionType == CommonActionType.UnitAction) return MainObjectType.Unit; if (actionType == CommonActionType.CityLevelUpAction) return MainObjectType.City; if (actionType == CommonActionType.UnitSkill) return MainObjectType.Unit; if (actionType == CommonActionType.LearnTech) return MainObjectType.Player; if (actionType == CommonActionType.UnitMove) return MainObjectType.Unit; if (actionType == CommonActionType.UnitAttack) return MainObjectType.Unit; if (actionType == CommonActionType.PlayerAction) return MainObjectType.Player; if (actionType == CommonActionType.AIParamControl) return MainObjectType.Player; if (actionType == CommonActionType.UnitAttackAlly) return MainObjectType.Unit; if (actionType == CommonActionType.UnitAttackGround) return MainObjectType.Unit; return MainObjectType.Player; } } // 行为基类 public abstract class ActionLogicBase { protected CommonActionId _actionId; public CommonActionId ActionId => _actionId; protected float _duration; public float Duration { get => _duration; set => _duration = value; } public ActionLogicBase(CommonActionId id) { _actionId = id; _duration = 0; } public bool CheckEqualActionId(CommonActionId actionId) { return _actionId == actionId; } public int GetCost(int buildingLevel = 0) { if (!Table.Instance.ActionDataAssets.GetActionInfo(_actionId, out var info)) return 0; //temple特别的计算cost方式 if (_actionId.GridMiscActionType == GridMiscActionType.UpgradeTemple) return buildingLevel >= 5 ? 0 : (buildingLevel + 1) * info.Cost; return info.Cost; } public virtual float GetAnimTime(CommonActionParams actionParams) { //TODO 这里通用返回值要读表,暂时先直接返回0.1f return 0.05f; } public virtual bool CameraControl(CommonActionParams actionParams) { return false; } public float GetValue() { return 1f; } // 完整的执行调用, 供外部使用 public virtual bool CompleteExecute(CommonActionParams actionParams) { // 此处限制了只有在当前 Player 回合内才能执行对应Player的Action if (actionParams.PlayerId != 0 && ActionId.ActionType != CommonActionType.TurnStart && actionParams.MapData.CurPlayer != null && actionParams.MapData.CurPlayer.Id != actionParams.PlayerId) { LogSystem.LogError($"CompleteExecute Player 不一致 {ActionId.GetStringLog()}"); return false; } if (Main.Instance.IsNetActionExecuting) { return ExecuteWithoutFullActionPeriod(actionParams); } if (actionParams.MapData.Net.Mode == NetMode.Multi && actionParams.MapData == Main.MapData) { if (LobbyManager.Instance.Lobby.IsLobbyOwner()) { Main.Instance.IsNetActionExecuting = true; GameNetSender.Instance.ActionExcute(_actionId, actionParams); } else { GameNetSender.Instance.ActionConfirm(_actionId, actionParams); if (ActionId.ActionType == CommonActionType.TurnEnd) return false; Main.Instance.IsNetActionExecuting = true; } } // LogSystem.LogWarning($"CompleteExecute : {NetData.GetMapDataHash(Main.MapData)}"); BeforeExecute(actionParams); var ret = Execute(actionParams); AfterExecute(actionParams); Main.Instance.IsNetActionExecuting = false; return ret; } //仅仅复用Action的execute逻辑,但是不被视作一个完整的completeExecute,不会走网络同步和时序等等,通常是嵌套在另一个主体Action之中的一段逻辑 public virtual bool ExecuteWithoutFullActionPeriod(CommonActionParams actionParams) { return Execute(actionParams); } // 网络调用 public virtual bool NetCompleteExecute(CommonActionParams actionParams) { BeforeExecute(actionParams); var ret = Execute(actionParams); AfterExecute(actionParams); return ret; } // 实际的执行逻辑 protected abstract bool Execute(CommonActionParams actionParams); // 执行前逻辑 protected virtual void BeforeExecute(CommonActionParams actionParams) { // 必须在 action 执行之前记录 if (actionParams.MapData != Main.MapData) return; var actionData = new ActionNetData(); actionData.Version = Main.MapData.Net.GetActionVersion(); actionData.MapHash = NetData.GetMapDataHash(Main.MapData); actionData.Param = actionParams; actionData.ActionId = _actionId; Main.MapData.Net.Actions.Add(actionData); } // 执行后逻辑 protected virtual void AfterExecute(CommonActionParams actionParams) { //更新所有人的外交好感情况。临时用的。必须真map才做,AI预测的不做,性能爆炸了 if (actionParams.MapData == Main.MapData) { foreach (var pData in actionParams.MapData.PlayerMap.PlayerDataList) pData.RefreshFeelingValue(actionParams.MapData); } Main.PlayerLogic.CalcAllPlayerScore(Main.MapData); //刷新当前玩家的每回合获取金币数 if (actionParams.MapData == Main.MapData && Main.MapData.CurPlayer == Main.MapData.PlayerMap.SelfPlayerData) { EventManager.Publish(new UpdateUITopTopBar() { UpdateType = UpdateTopBarType.UpdateCoinPerTurn }); EventManager.Publish(new UpdateUITopTopBar() { UpdateType = UpdateTopBarType.UpdateTechPerTurn }); EventManager.Publish(new UpdateUITopTopBar() { UpdateType = UpdateTopBarType.UpdateFaith }); } Main.PlayerLogic.Update(Main.MapData); } public abstract bool CheckCan(CommonActionParams actionParams); public virtual bool CheckShow(CommonActionParams actionParams,out ShowType showType) { showType = ShowType.None; return CheckCan(actionParams); } public virtual ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; } public void TH1Debug() { Debug.Log($"{_actionId.ActionType} : {_actionId.ResourceType}/{_actionId.UnitType}/{_actionId.WonderType}"); } } // 建造奇观逻辑类 #buildwonder public class BuildWonderAction : ActionLogicBase { public BuildWonderAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams) { //Step #0 鲁棒性处理 if(!actionParams.MapData.GetCityDataByTerritoryGid(actionParams.GridData.Id,out var city)) return false; if (!Table.Instance.GridAndResourceDataAssets.GetWonderInfoByType(_actionId.WonderType,actionParams.PlayerData, out var wonderInfo)) return false; if (actionParams.PlayerData == null) return false; //Step #1 逻辑层:更新gridData相关信息,设置奇观完成情况 var player = actionParams.PlayerData; actionParams.GridData.ResourceUnderBuilding = actionParams.GridData.Resource; actionParams.GridData.Resource = ResourceType.Wonder; actionParams.GridData.Wonder = wonderInfo.Wonder; player.Wonder.SetWonderState(wonderInfo.WonderType,WonderState.FINISH_BUILD); //Step #2 逻辑层+视觉层:城市获得3点经验 Main.CityLogic.UpdateGrid_ViewOnly(actionParams.MapData,actionParams.GridData); Main.CityLogic.GridGiveCityExp_LogicView(actionParams.MapData,actionParams.PlayerData,actionParams.GridData,city,wonderInfo.Exp); //Step #3 更新成就完成情况 AchievementDataManager.Instance.OnBuildWonder(actionParams.MapData, player, city, actionParams.GridData); return true; } public override bool CheckCan(CommonActionParams actionParam) { //鲁棒性+基础数据准备,必须准备player(谁来建设?)和grid(在哪里建设?) if (actionParam.PlayerData == null) return false; if (actionParam.GridData == null) return false; var player = actionParam.PlayerData; var grid = actionParam.GridData; var map = actionParam.MapData; //找到grid所属于的player,如果是无主领土就return if (!map.GetPlayerDataByTerritoryGridId(grid.Id, out var gridPlayer)) return false; //如果player操作的grid都不属于自己return if (player != gridPlayer) return false; //如果根本无法建设这个奇观 return if (player.Wonder.GetWonderState(_actionId.WonderType) != WonderState.FINISH_NOT_BUILD) return false; //如果是山地或者深海,无法建设这个奇观 return false if (grid.Feature == TerrainFeature.Mountain || grid.Terrain == TerrainType.DeepSea || grid.Vegetation == Vegetation.Trees) return false; //如果有非联盟的敌人站在上面 if (map.GetUnitDataByGid(grid.Id, out var unit) && !map.CheckUnitIdBelongPlayerIdUnion(unit.Id, player.Id)) return false; //如果上面是常规资源,那么就是可以建设的 return true if (grid.Resource == ResourceType.None || grid.Resource == ResourceType.Fish || grid.Resource == ResourceType.Starfish || grid.Resource == ResourceType.Crop || grid.Resource == ResourceType.Fruit ) return true; if (GetCost() > actionParam.PlayerData.PlayerCoin) return false; return false; } public override bool CheckShow(CommonActionParams actionParam,out ShowType showType) { showType = ShowType.None; return CheckCan(actionParam); } public override ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; } } // Gain 收获资源逻辑类 public class GainResourceAction : ActionLogicBase { public GainResourceAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams) { if (!CheckCan(actionParams)) return false; CityData cityData = actionParams.CityData; if (cityData == null) actionParams.MapData.GetCityDataByTerritoryGid(actionParams.GridData.Id,out cityData); //Step #1 逻辑层 扣钱,消除资源 actionParams.PlayerData.SpendCoin(GetCost()); actionParams.GridData.Resource = ResourceType.None; //Step #2 逻辑层 & 表现层 :gridupdate + city获得exp var exp = Table.Instance.QueryActionExp(_actionId); Main.CityLogic.UpdateGrid_ViewOnly(actionParams.MapData,actionParams.GridData); Main.CityLogic.GridGiveCityExp_LogicView(actionParams.MapData,actionParams.PlayerData,actionParams.GridData,cityData,exp); //更新所有建筑的buildingLevel Main.PlayerLogic.UpdateTerritoryAllBuildingLevel(actionParams.MapData,actionParams.PlayerData.Id); return true; } public override bool CheckCan(CommonActionParams actionParam) { //如果是unit或者city来执行gain操作,直接return false if (actionParam.MainObjectType != MainObjectType.Grid) return false; var grid = actionParam.GridData; var map = actionParam.MapData; var player = actionParam.PlayerData; if (grid == null || map == null || player == null) return false; //如果没有对应科技,return false if (!player.TechTree.CheckActionCan(_actionId)) return false; //确认grid实际属于的player是谁 map.GetPlayerDataByTerritoryGridId(actionParam.GridData.Id, out var gridPlayer); //如果不在我方领土,return false if (gridPlayer == null || player.Id != gridPlayer.Id) return false; //钱不够 return if (GetCost() > actionParam.PlayerData.PlayerCoin) return false; //如果有非联盟的敌人站在上面 if (map.GetUnitDataByGid(grid.Id, out var unit) && !map.CheckUnitIdBelongPlayerIdUnion(unit.Id, player.Id)) return false; return _actionId.ResourceType == actionParam.GridData.Resource; } public override bool CheckShow(CommonActionParams actionParam,out ShowType showType) { showType = ShowType.None; if (actionParam.MainObjectType != MainObjectType.Grid) return false; var grid = actionParam.GridData; var map = actionParam.MapData; var player = actionParam.PlayerData; if (grid == null || map == null || player == null) return false; //如果没有对应科技也会显示 钱不够也会显示 //确认grid实际属于的player是谁 map.GetPlayerDataByTerritoryGridId(actionParam.GridData.Id, out var gridPlayer); //如果不在我方领土,return false if (gridPlayer == null || player.Id != gridPlayer.Id) return false; //如果有非联盟的敌人站在上面 if (map.GetUnitDataByGid(grid.Id, out var unit) && !map.CheckUnitIdBelongPlayerIdUnion(unit.Id, player.Id)) return false; //如果techpool里就没有这个技能,不显示 if (!Table.Instance.PlayerDataAssets.CheckActionInTechPool(_actionId, actionParam.PlayerData)) return false; return _actionId.ResourceType == actionParam.GridData.Resource; } public override ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; } } //CityLevelUp 行动逻辑类 public class CityLevelUpActionAction : ActionLogicBase { public CityLevelUpActionAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams) { //必须传入参数 paramMap paramCity //需要参数:paramMap paramCity paramGrid paramPlayer //鲁棒性判断 if (actionParams.CityData == null) return false; if (!actionParams.MapData.GetGridDataByCityId(actionParams.CityData.Id, out var paramGrid)) return false; if (actionParams.CityData.CityLevelUpPoint <= 0) return false; if (!actionParams.MapData.GetPlayerDataByCityId(actionParams.CityData.Id, out var paramPlayer)) return false; var paramMap = actionParams.MapData; var paramCity = actionParams.CityData; actionParams.CityData.CityLevelUpPoint --; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Explorer) { // 1. 锁定玩家输入 //main.InputLogic.LockInput(); // 2. 创建探索者,然后一边处理逻辑一边处理视觉,这里暂时用了maprenderer 来负责 MapRenderer.Instance.CreateTemporaryExplorer(actionParams.MapData,paramGrid, 3f); paramCity.SetCityRenderer(actionParams.MapData); return true; } if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Workshop) { paramCity.Workshop = true; paramCity.SetCityRenderer(actionParams.MapData); if((paramGrid?.InMainSight()??false) && paramPlayer == Main.MapData.PlayerMap.SelfPlayerData) paramGrid.Renderer(paramMap)?.PlayVFX(new GridVFXParams(GridVFXType.Luxury)); return true; } if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWealth) { if(PresentationManager.GetCityLevelupActionPos(_actionId.CityLevelUpActionType,out var pos)) paramPlayer.AddCoin(5,pos); else paramPlayer.AddCoin(5); paramCity.SetCityRenderer(paramMap); return true; } if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWall) { paramCity.CityWall = true; paramGrid?.Renderer(paramMap)?.InstantUpdateGrid(true); paramGrid?.Renderer(paramMap)?.PlayVFX(new GridVFXParams(GridVFXType.Fog)); //如果city上有单位,也要更新单位的渲染 if (actionParams.MapData.GetUnitDataByGid(paramGrid.Id, out var unit) && unit.InMainSight()) unit.Renderer(actionParams.MapData)?.InstantUpdateUnit(true); return true; } if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Expand) { Main.CityLogic.CityLevelUpActionExpand(actionParams.MapData,actionParams.CityData); actionParams.CityData.SetCityRenderer(actionParams.MapData); //要更新玩家所有城市所有格子的levelbuilding Main.PlayerLogic.UpdateTerritoryAllBuildingLevel(actionParams.MapData,paramPlayer.Id); //更新所有国家的联通情况 Main.PlayerLogic.UpdateAllPlayerConnected(actionParams.MapData); //更新特殊占领技能 if(paramPlayer.TechTree.CheckIfHasTechAtom(TechAtom.KaguyaFrenchNapoleonicCode)) Main.PlayerLogic.SetCityTerritoryGridSp(actionParams.MapData,actionParams.CityData,GridSpType.KaguyaGrid); return true; } if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Population) { //Step #2 逻辑层 & 表现层 :city获得exp var exp = 3; Main.CityLogic.GridGiveCityExp_LogicView(actionParams.MapData,paramPlayer,actionParams.CityData?.Grid(actionParams.MapData),actionParams.CityData,exp); return true; } if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Park) { actionParams.CityData.ParkCount++; actionParams.CityData.SetCityRenderer(actionParams.MapData); if((paramGrid?.InMainSight()??false) && paramPlayer == Main.MapData.PlayerMap.SelfPlayerData) paramGrid.Renderer(paramMap)?.PlayVFX(new GridVFXParams(GridVFXType.Luxury)); return true; } if (_actionId.CityLevelUpActionType == CityLevelUpActionType.BigGuy) { if(actionParams.MapData.GetUnitDataByGid(paramGrid.Id,out var unitData)) Main.UnitLogic.PassiveMoveAway(paramMap, unitData); var fullType = new UnitFullType(UnitType.BigGuy, GiantType.None, 0); if(paramPlayer.PlayerCivId == 1 && paramPlayer.PlayerForceId == 1) fullType = new UnitFullType(UnitType.KaguyaFrenchWolf, GiantType.None, 0); if(paramPlayer.PlayerCivId == 0 && paramPlayer.PlayerForceId == 0) fullType = new UnitFullType(UnitType.RemiliaEgyptianKoakuma, GiantType.None, 0); if(paramPlayer.PlayerCivId == 2 && paramPlayer.PlayerForceId == 2) fullType = new UnitFullType(UnitType.MoriyaHebi, GiantType.None, 3); if (!actionParams.MapData.AddUnitData(paramGrid.Id, actionParams.CityData.Id,fullType ,out var _)) return false; paramCity.SetCityRenderer(paramMap); return true; } return false; } public override bool CheckCan(CommonActionParams actionParams) { if (actionParams.CityData == null) return false; //如果没有升级行动的点数,退出 if (actionParams.CityData.CityLevelUpPoint <= 0) return false; //用于处理连续升级的情况 var addition = actionParams.CityData.CityLevelUpPoint - 1; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Explorer) return actionParams.CityData.Level == 3 + addition; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Workshop) return actionParams.CityData.Level == 3 + addition; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWall) return actionParams.CityData.Level == 4 + addition; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWealth) return actionParams.CityData.Level == 4 + addition; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Population) return actionParams.CityData.Level == 5 + addition; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Expand) return actionParams.CityData.Level == 5 + addition; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Park) return actionParams.CityData.Level > 5 + addition; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.BigGuy) return actionParams.CityData.Level > 5 + addition; return false; } public override bool CheckShow(CommonActionParams actionParams,out ShowType showType) { showType = ShowType.None; if (actionParams.CityData == null) return false; //如果没有升级行动的点数,退出 if (actionParams.CityData.CityLevelUpPoint <= 0) return false; var addition = actionParams.CityData.CityLevelUpPoint - 1; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Explorer) return actionParams.CityData.Level == 3 + addition; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Workshop) return actionParams.CityData.Level == 3 + addition; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWall) return actionParams.CityData.Level == 4 + addition; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWealth) return actionParams.CityData.Level == 4 + addition; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Population) return actionParams.CityData.Level == 5 + addition; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Expand) return actionParams.CityData.Level == 5 + addition; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Park) return actionParams.CityData.Level > 5 + addition; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.BigGuy) return actionParams.CityData.Level > 5 + addition; return false; } public override ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; } } // 小兵移动 public class UnitMoveAction : ActionLogicBase { public UnitMoveAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams) { //Step #0 存储服务于anim的数据 GridData originGrid = null; GridData targetGrid = null; UnitData unit = null; originGrid = actionParams.UnitData.Grid(actionParams.MapData); targetGrid = actionParams.GridData; unit = actionParams.UnitData; if (unit == null) return false; if (!unit.IsAlive()) { LogSystem.LogError($"unit is dead , cannot move!"); return false; } //提前记录player,因为有可能移动后unit就死了 PlayerData player = unit.Player(actionParams.MapData); //Step #1记录路径 确定MoveType var path1 = new List(); //TODO 这里有风险,movepath依赖一个在时序上完全无关的 movecostinfo的计算 Main.UnitLogic.CalcUnitMoveInfo(actionParams.MapData, unit.Id); MoveAttackType moveAttackType = Main.UnitLogic.GetMovePath(actionParams.MapData, originGrid.Pos.V2(), targetGrid.Pos.V2(), out path1); MoveType moveType = moveAttackType switch { MoveAttackType.MoveTeleport => MoveType.SkillMove, _ => MoveType.ActiveMove }; //Step #2 处理移动数据 Main.UnitLogic.MoveToLogic(actionParams.MapData, actionParams.UnitData, actionParams.GridData, moveType, path1); //Step #3 将移动动画加入队列 bool need = Main.MapData == actionParams.MapData; //如果数据出错 不播放动画 if (originGrid == null || targetGrid == null || unit == null) need = false; //如果整个路径都在视野外,不播放动画 if (!Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(originGrid.Id) && !Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(targetGrid.Id)) need = false; if (need) { //Step #2-1 处理闪现类动画 if (moveAttackType == MoveAttackType.MoveTeleport) { MapRenderer.Instance.ROUnitMap.TryGetValue(unit.Id, out var uintRenderer); var fragment = FragmentFactory.Create(FragmentType.MoveTeleport,FragmentDataFactory.Create(FragmentType.Move,uintRenderer,originGrid,targetGrid,path1)); PresentationManager.EnqueueTask(new FragmentSequencerTask(fragment)); } //Step #2-2 将移动动画加入队列 if (moveAttackType == MoveAttackType.Move) { MapRenderer.Instance.ROUnitMap.TryGetValue(unit.Id, out var uintRenderer); var fragment = FragmentFactory.Create(FragmentType.Move,FragmentDataFactory.Create(FragmentType.Move,uintRenderer,originGrid,targetGrid,path1)); PresentationManager.EnqueueTask(new FragmentSequencerTask(fragment)); } } //Step #4 更新Sight的数据,同时将Sight相关动画加入演出队列 //更新路径视野 foreach (var pathnode in path1) //需要传入player,因为可能unitData已经死了 actionParams.PlayerData.Sight.UpdateSightByPath(actionParams.UnitData,player,pathnode,actionParams.MapData); return true; } public override bool CheckCan(CommonActionParams actionParams) { // TODO 需要完整更新CheckCan var unit = actionParams.UnitData; var map = actionParams.MapData; var player = actionParams.PlayerData; var grid = actionParams.GridData; if (unit is null || map is null || grid is null || player is null) return false; var unitPlayer = unit.Player(map); if (unitPlayer != player) return false; //判断是否只能在我方领土上移动(目前仅用于suwako) if (unit.IsLimitMoveToSelfTerrain(map) && grid.Player(map) != unit.Player(map)) return false; return true; } public override bool CheckShow(CommonActionParams actionParams,out ShowType showType) { showType = ShowType.None; return false; } public override ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; } public override bool CameraControl(CommonActionParams actionParams) { var main = GameObject.Find("Main").GetComponent
(); if (actionParams.GridData != null && main != null && MapRenderer.Instance.CameraController != null && actionParams.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(actionParams.GridData.Id)) MapRenderer.Instance.CameraController?.CameraFocusOnGrid(actionParams.GridData); return true; } } public class UnitPassiveMoveAction : ActionLogicBase { public UnitPassiveMoveAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams) { //Step #0 存储服务于anim的数据 GridData originGrid = null; GridData targetGrid = null; UnitData unit = null; originGrid = actionParams.UnitData.Grid(actionParams.MapData); targetGrid = actionParams.GridData; unit = actionParams.UnitData; //提前记录player,因为unit可能在移动后直接死了 PlayerData player = unit.Player(actionParams.MapData); //Step #1 处理移动数据 Main.UnitLogic.MoveToLogic(actionParams.MapData, actionParams.UnitData, actionParams.GridData,MoveType.PassiveMove); //记录路径 var path1 = new List(); path1.Add(originGrid.Pos.V2()); path1.Add(targetGrid.Pos.V2()); //Main.UnitLogic.GetMovePath(actionParams.MapData, originGrid.Pos.V2(), targetGrid.Pos.V2(), out path1); //Step #2 将移动动画加入队列 bool need = Main.MapData == actionParams.MapData; //如果数据出错 不播放动画 if (originGrid == null || targetGrid == null || unit == null) need = false; //如果数据出错 不播放动画 if (!Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(originGrid.Id) && !Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(targetGrid.Id)) need = false; if (need) { MapRenderer.Instance.ROUnitMap.TryGetValue(unit.Id, out var uintRenderer); var fragment = FragmentFactory.Create(FragmentType.Move,FragmentDataFactory.Create(FragmentType.Move,uintRenderer,originGrid,targetGrid,path1)); //FragmentManager.Instance.AddFragment(fragment); PresentationManager.EnqueueTask(new FragmentSequencerTask(fragment)); } //Step #3 更新Sight的数据,同时将Sight相关动画加入演出队列 //更新路径视野 foreach (var pathnode in path1) actionParams.PlayerData.Sight.UpdateSightByPath(actionParams.UnitData,player,pathnode,actionParams.MapData); return true; } public override bool CheckCan(CommonActionParams actionParams) { return true; } public override bool CheckShow(CommonActionParams actionParams,out ShowType showType) { showType = ShowType.None; return false; } } public class UnitAttackAction : ActionLogicBase { public UnitAttackAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams) { //Step #0 为anim做数据准备 GridData originGrid = null; GridData targetGrid = null; CityData originCity = null; CityData targetCity = null; UnitRenderer originUnitRenderer = null; UnitRenderer targetUnitRenderer = null; ProjectileType originUnitProjectileType = ProjectileType.None; ProjectileType targetUnitProjectileType = ProjectileType.None; PlayerData originPlayer = null; //如果不是AI预测相关的行为 if (actionParams.MapData == Main.MapData) { originGrid = actionParams.UnitData.Grid(Main.MapData); targetGrid = actionParams.TargetUnitData.Grid(Main.MapData); originCity = actionParams.UnitData.City(Main.MapData); targetCity = actionParams.TargetUnitData.City(Main.MapData); originPlayer = actionParams.UnitData.Player(Main.MapData); MapRenderer.Instance.ROUnitMap.TryGetValue(actionParams.UnitData.Id, out originUnitRenderer); MapRenderer.Instance.ROUnitMap.TryGetValue(actionParams.TargetUnitData.Id, out targetUnitRenderer); originUnitProjectileType = actionParams.UnitData.GetProjectileType(actionParams.MapData,targetGrid); targetUnitProjectileType = actionParams.TargetUnitData.GetProjectileType(actionParams.MapData,targetGrid); } //Step #2 处理逻辑计算,提前存储anim使用到的数据 Main.UnitLogic.Attack(actionParams.MapData, actionParams.UnitData, actionParams.TargetUnitData, out var attackDmg,out var counterDmg,out var fragmentType); //Step #3 处理攻击动画 //如果是AI预测行为,return if (actionParams.MapData != Main.MapData) return true; //如果数据出错,return if (originGrid == null || targetGrid == null || originUnitRenderer == null || targetUnitRenderer == null) return false; //如果在视野,播放动画 if (Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(originGrid.Id) || Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(targetGrid.Id)) { var data = fragmentType switch { FragmentType.Attack or FragmentType.AttackAndCounter or FragmentType.MoveKill or FragmentType.NotMoveKill or FragmentType.AttackAndCounterDie => FragmentDataFactory.Create(fragmentType, originUnitRenderer, targetUnitRenderer, originGrid, targetGrid, originUnitProjectileType, targetUnitProjectileType, attackDmg, counterDmg,originCity,targetCity), _ => null }; var fragment = FragmentFactory.Create(fragmentType,data); //FragmentManager.Instance.AddFragment(fragment); PresentationManager.EnqueueTask(new FragmentSequencerTask(fragment)); _duration = fragment.Duration; } //Step #4 处理视野变化(move kill) //如果MoveKill,要给unit所在的player更新sight,如果学者攻击,也是会更新sight if(fragmentType == FragmentType.MoveKill) //传入originPlayer, 避免unit已经死了,无法通过unit拿到player的情况 actionParams.UnitData.Player(actionParams.MapData)?.Sight.UpdateSightByPath(actionParams.UnitData,originPlayer,targetGrid.Pos.V2(),actionParams.MapData); //Step #5 更新攻击前后两个格子的显示,比如学者攻击了在城市里的角色,那么城市里会有fire //更正!这一步不能在这里做,要在fragment里做!! //originGrid.Renderer(actionParams.MapData)?.SetUpdateGrid(); //targetGrid.Renderer(actionParams.MapData)?.SetUpdateGrid(); return true; } public override bool CheckCan(CommonActionParams actionParams) { if (!actionParams.UnitData.IsAlive() || !actionParams.TargetUnitData.IsAlive()) return false; if (actionParams.UnitData.Id == actionParams.TargetUnitData.Id) return false; if (!actionParams.UnitData.CanAttackAll(actionParams.MapData) && actionParams.MapData.IsLeagueUnitByUnit(actionParams.UnitData.Id, actionParams.TargetUnitData.Id)) return false; if (actionParams.UnitData.IsLimitSelfAttack(actionParams.MapData)) return false; if (!actionParams.MapData.GetPlayerDataByUnitId(actionParams.UnitData.Id, out _)) return false; if (!actionParams.MapData.GetPlayerDataByUnitId(actionParams.TargetUnitData.Id, out _)) return false; if (!actionParams.MapData.GetCityDataByUnitId(actionParams.UnitData.Id, out _)) return false; if (!actionParams.MapData.GetCityDataByUnitId(actionParams.TargetUnitData.Id, out _)) return false; //单独处理: 学者无法攻击英雄 if (actionParams.UnitData.GetSkill(SkillType.CONVERT, out var _) && actionParams.TargetUnitData.UnitFullType.UnitType == UnitType.Giant) return false; return true; } public override bool CheckShow(CommonActionParams actionParams,out ShowType showType) { showType = ShowType.None; return false; } public override ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; } public override bool CameraControl(CommonActionParams actionParams) { var main = GameObject.Find("Main").GetComponent
(); if(actionParams.GridData != null && main != null && MapRenderer.Instance.CameraController != null && actionParams.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(actionParams.GridData.Id)) MapRenderer.Instance.CameraController?.CameraFocusOnGrid(actionParams.GridData); return true; } } public class UnitAttackAllyAction : ActionLogicBase { public UnitAttackAllyAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams) { //Step #0 为anim做数据准备 GridData originGrid = null; GridData targetGrid = null; UnitRenderer originUnitRenderer = null; UnitRenderer targetUnitRenderer = null; //如果不是AI预测相关的行为 if (actionParams.MapData == Main.MapData) { originGrid = actionParams.UnitData.Grid(Main.MapData); targetGrid = actionParams.TargetUnitData.Grid(Main.MapData); MapRenderer.Instance.ROUnitMap.TryGetValue(actionParams.UnitData.Id, out originUnitRenderer); MapRenderer.Instance.ROUnitMap.TryGetValue(actionParams.TargetUnitData.Id, out targetUnitRenderer); } //Step #1 处理所有攻击友军的逻辑 UnitData unit1 = actionParams.UnitData; UnitData unit2 = actionParams.TargetUnitData; CityData city1 = unit1.City(actionParams.MapData); MapData mapData = actionParams.MapData; SkillType animSkillData = SkillType.NONE; bool NotProjectile = false; bool unit1Die = false; //处理Eirin的友军攻击 if (unit1.GetSkill(SkillType.EIRINFRENCHATTACK, out var _)) { animSkillData = SkillType.EIRINFRENCHATTACK; unit1.ClearAPMPCP(); int recover = 5; if (unit1.GetSkill(SkillType.EIRINFRENCHBUFF, out var _) && unit2.UnitFullType.UnitType == UnitType.Giant) recover = 15; var before = unit1.Health; Main.UnitLogic.RecoverHealth(mapData, unit1, unit2, recover); unit2.AddSkill(SkillType.KAGUYAFRENCHSYNERGY,1, mapData); //如果溢出 if (unit1.Health - before < recover) { unit2.AddSkill(SkillType.MOVERANGEUP,1, mapData); } //Step #2 处理所有skill的 OnHealOther生命周期 unit1.OnHealOther(actionParams.MapData,unit2,HealType.AttackAllyHeal); } else //处理Kaguya的友军攻击 if (unit1.GetSkill(SkillType.KAGUYAFRENCHATTACK, out var _) || unit1.GetSkill(SkillType.KAGUYAFRENCHATTACKPRO, out var _) ) { animSkillData = SkillType.KAGUYAFRENCHATTACK; var lv = unit1.GetSkill(SkillType.KAGUYAFRENCHATTACKPRO, out var _) ? 9 : 1; unit1.ClearAPMPCP(); unit2.AddSkill(SkillType.KAGUYAFRENCHFOREVERBUFF, mapData); if (unit2.GetSkill(SkillType.KAGUYAFRENCHFOREVERBUFF, out var skill)) skill.AddLevel(mapData, unit1, unit2, lv); //Step #2 处理所有skill的 OnHealOther生命周期 unit1.OnHealOther(actionParams.MapData,unit2,HealType.AttackAllyHeal); } else //处理Patchouli的友军施法 if (unit1.GetSkill(SkillType.PATCHOULIEARTH, out var tskill)) { animSkillData = SkillType.PATCHOULIEARTH; var lv = tskill.Level; int recover = lv * 5; unit1.ClearAPMPCP(); Main.UnitLogic.RecoverHealth(mapData, unit1, unit2, recover); tskill.ReduceLevel(mapData, unit1, lv); unit1.HeroTask(mapData)?.OnReduceSkillLevels(mapData,SkillType.PATCHOULIEARTH,(uint)lv); //如果同事存在金石,也要消耗掉金石头 if (unit1.GetSkill(SkillType.PATCHOULIMETAL, out var tskill2)) { var lv2 = tskill2.Level; tskill2.ReduceLevel(mapData, unit1, lv2); unit1.HeroTask(mapData)?.OnReduceSkillLevels(mapData,SkillType.PATCHOULIMETAL,(uint)lv2); } //Step #2 处理所有skill的 OnHealOther生命周期 unit1.OnHealOther(actionParams.MapData,unit2,HealType.AttackAllyHeal); } else //处理Koakuma的友军施法 if (unit1.GetSkill(SkillType.KOAKUMADEVOTION, out var skill)) { var t = skill as KoakumaDevotionSkill; animSkillData = SkillType.KOAKUMADEVOTION; int recover = 5; unit1.ClearAPMPCP(); Main.UnitLogic.RecoverHealth(mapData, unit1, unit2, recover); if (t?.FirstDevotion ?? false) { //unit1.AP = 1; t.FirstDevotion = false; } unit1.OnHealOther(actionParams.MapData,unit2,HealType.AttackAllyHeal); var grid = unit1.Grid(mapData); var info = Main.UnitLogic.DamageSettlement(mapData,unit1,unit1,5,DamageType.KillSelf); grid?.Renderer(mapData)?.InstantUpdateGrid(); if (info.IsKill) unit1.Renderer(mapData)?.Die(); } else //处理SuwakoHebi的合并 if (unit1.GetSkill(SkillType.SUWAKOHEBI, out var _)) { NotProjectile = true; //unit2.UnitFullType.UnitLevel++; var unitFullType = unit2.UnitFullType; var health = unit2.Health + unit1.Health; unitFullType.UnitLevel++; Main.UnitLogic.UnitTypeTransform(mapData,unit2,unitFullType); unit2.Health = health; Main.UnitLogic.UnitDie(actionParams.MapData,unit1,0); } //处理sanae的友军攻击 if (unit1.GetSkill(SkillType.SANAEWIND, out var _)) { animSkillData = SkillType.SANAEWIND; int recover = 4; unit1.ClearAPMPCP(); Main.UnitLogic.RecoverHealth(mapData, unit1, unit2, recover); unit1.OnHealOther(actionParams.MapData,unit2,HealType.AttackAllyHeal); } //Step #3 处理动画 //如果是AI预测行为,return if (actionParams.MapData != Main.MapData) return true; //如果数据出错,return if (originGrid == null || targetGrid == null || originUnitRenderer == null || targetUnitRenderer == null) return false; //如果不在视野,return if (!Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(originGrid.Id) && !Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(targetGrid.Id)) return true; //投射物类的动画 if (!NotProjectile) { var data = FragmentDataFactory.CreateAttackAllyData(FragmentType.AttackAlly, originUnitRenderer, targetUnitRenderer, originGrid, targetGrid, animSkillData,unit1Die,city1); var fragment = FragmentFactory.Create(FragmentType.AttackAlly,data); PresentationManager.EnqueueTask(new FragmentSequencerTask(fragment)); _duration = fragment.Duration; } //非投射物动画(目前仅suwako hebi 的合并 else { targetUnitRenderer.InstantUpdateUnit(showoff: true); originUnitRenderer.InstantUpdateUnit(showoff: true); targetGrid.Renderer(Main.MapData)?.PlayVFX(new GridVFXParams(GridVFXType.Fog)); originGrid.Renderer(Main.MapData)?.PlayVFX(new GridVFXParams(GridVFXType.Fog)); //因为没有走包装好的fragmenData 所以由手动重置周围单位的高亮状态 MapRenderer.Instance.UpdateAroundHighlight(Main.MapData,originGrid); } return true; } public override bool CheckCan(CommonActionParams actionParams) { if (actionParams.UnitData.Id == actionParams.TargetUnitData.Id) return false; if (!actionParams.UnitData.IsAlive() || !actionParams.TargetUnitData.IsAlive()) return false; if (!actionParams.MapData.IsLeagueUnitByUnit(actionParams.UnitData.Id, actionParams.TargetUnitData.Id)) return false; if (!actionParams.MapData.GetPlayerDataByUnitId(actionParams.UnitData.Id, out _)) return false; if (!actionParams.MapData.GetPlayerDataByUnitId(actionParams.TargetUnitData.Id, out _)) return false; if (!actionParams.MapData.GetCityDataByUnitId(actionParams.UnitData.Id, out _)) return false; if (!actionParams.MapData.GetCityDataByUnitId(actionParams.TargetUnitData.Id, out _)) return false; if (!actionParams.MapData.GetGridDataByUnitId(actionParams.UnitData.Id, out var unitGrid)) return false; if (!actionParams.MapData.GetGridDataByUnitId(actionParams.TargetUnitData.Id, out var targetUnitGrid)) return false; if (actionParams.MapData.GridMap.CalcDistance(unitGrid, targetUnitGrid) > actionParams.UnitData.GetAttackRange(actionParams.MapData)) return false; if (!actionParams.UnitData.IsCanAttackAlly()) return false; if (!actionParams.UnitData.IsCanAttackTargetAlly(actionParams.MapData, actionParams.TargetUnitData)) return false; return true; } public override bool CheckShow(CommonActionParams actionParams,out ShowType showType) { showType = ShowType.None; return false; } public override ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; } public override bool CameraControl(CommonActionParams actionParams) { var main = GameObject.Find("Main").GetComponent
(); if(actionParams.GridData != null && main != null && MapRenderer.Instance.CameraController != null && actionParams.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(actionParams.GridData.Id)) MapRenderer.Instance.CameraController?.CameraFocusOnGrid(actionParams.GridData); return true; } } public class UnitAttackGroundAction : ActionLogicBase { public UnitAttackGroundAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams) { //Step #0 为anim做数据准备 GridData originGrid = actionParams.UnitData.Grid(Main.MapData); GridData targetGrid = actionParams.GridData; UnitRenderer originUnitRenderer = null; GridRenderer targetGridRenderer = null; bool isTrueMap = actionParams.MapData == Main.MapData; //如果不是AI预测相关的行为,获取两个格子的Renderer if (isTrueMap) { MapRenderer.Instance.ROUnitMap.TryGetValue(actionParams.UnitData.Id, out originUnitRenderer); targetGridRenderer = targetGrid.Renderer(Main.MapData); } //Step #1 处理所有攻击友军的逻辑 UnitData unit1 = actionParams.UnitData; //UnitData unit2 = actionParams.TargetUnitData; CityData city1 = unit1.City(actionParams.MapData); //MapData mapData = actionParams.MapData; SkillType animSkillData = SkillType.NONE; UnitData suwakoUnit = null; //处理SUWAKO的地面攻击 if (unit1.GetSkill(SkillType.SUWAKOATTACK, out var _)) { animSkillData = SkillType.SUWAKOATTACK; unit1.ClearAPMPCP(); var fullType = new UnitFullType() { UnitType = UnitType.MoriyaHebi, GiantType = GiantType.None, UnitLevel = 1 }; // TODO 这里的延迟产生单位形象,后续要加入presentationlist actionParams.MapData.AddUnitData(targetGrid.Id, city1.Id, fullType, out suwakoUnit, 0.2f); } //Step #3 处理动画 //如果是AI预测行为,return if (!isTrueMap) return true; //如果数据出错,return if (originGrid == null || targetGrid == null || originUnitRenderer == null || targetGridRenderer == null) return false; //如果不在视野,return if (!Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(originGrid.Id) && !Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(targetGrid.Id)) return true; var data = new FragmentAttackGroundData(FragmentType.AttackGround, originUnitRenderer, targetGridRenderer, originGrid, targetGrid, animSkillData,city1); var fragment = FragmentFactory.Create(FragmentType.AttackGround,data); PresentationManager.EnqueueTask(new FragmentSequencerTask(fragment)); _duration = fragment.Duration; //处理SUWAKO的地面攻击 刷新白蛇周围的视野 if (unit1.GetSkill(SkillType.SUWAKOATTACK, out var _) && suwakoUnit != null) { actionParams.PlayerData.Sight.UpdateSightByPath(suwakoUnit,actionParams.PlayerData,suwakoUnit.Grid(actionParams.MapData)?.Pos.V2() ?? Vector2Int.zero,actionParams.MapData); } suwakoUnit?.Grid(actionParams.MapData)?.Renderer(actionParams.MapData)?.InstantUpdateGrid(); return true; } public override bool CheckCan(CommonActionParams actionParams) { //Step #1 确定数据正确性 if (actionParams.MapData == null || actionParams.PlayerData == null || actionParams.UnitData == null || actionParams.GridData == null) return false; //Step #2 player操作的unit 必须属于player if (actionParams.UnitData.Player(actionParams.MapData) != actionParams.PlayerData) return false; //Step #3 unit是否能够攻击targetGrid if (!actionParams.UnitData.IsCanAttackTargetGrid(actionParams.MapData,actionParams.GridData)) return false; return true; } public override bool CheckShow(CommonActionParams actionParams,out ShowType showType) { showType = ShowType.None; return false; } public override ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; } public override bool CameraControl(CommonActionParams actionParams) { var main = GameObject.Find("Main").GetComponent
(); if(actionParams.GridData != null && main != null && MapRenderer.Instance.CameraController != null && actionParams.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(actionParams.GridData.Id)) MapRenderer.Instance.CameraController?.CameraFocusOnGrid(actionParams.GridData); return true; } } public class StartWonderAction : ActionLogicBase { public StartWonderAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams) { return false; } public override bool CheckCan(CommonActionParams actionParams) { return false; } public override bool CheckShow(CommonActionParams actionParams,out ShowType showType) { showType = ShowType.None; return false; } } //TODO 没有填写Skill public class UnitSkillAction : ActionLogicBase { public UnitSkillAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams) { return false; } public override bool CheckCan(CommonActionParams actionParams) { return false; } public override bool CheckShow(CommonActionParams actionParams,out ShowType showType) { showType = ShowType.None; return false; } } public class LearnTechAction : ActionLogicBase { public LearnTechAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams) { if (actionParams.MainObjectType != MainObjectType.Player) return false; if (actionParams.PlayerData == null) return false; int cost = Main.PlayerLogic.GetTechCost(actionParams.MapData, actionParams.PlayerData, _actionId.TechType); Main.PlayerLogic.ResearchTech(actionParams.MapData,actionParams.PlayerData,_actionId.TechType,cost); //发出学习科技的通知 if(actionParams.PlayerData.IsSelfPlayer()) EventManager.Publish(new ShowUINotifyCommon(){UINotifyCommonType = UINotifyCommonType.Tech}); return true; } public override bool CheckCan(CommonActionParams actionParams) { //鲁棒性判断,不是玩家执行这个操作就退出 if (actionParams.MainObjectType != MainObjectType.Player) return false; if (actionParams.PlayerData == null) return false; if (actionParams.PlayerData.TechTree.CheckIfHasTech(_actionId.TechType)) return false; //如果科技不在该玩家的tech pool里,return if (!Table.Instance.PlayerDataAssets.GetPlayerInfo(actionParams.PlayerData, out var playerInfo)) return false; if (!playerInfo.TechPool.Contains(_actionId.TechType)) return false; //如果没有父科技 var techInfo = Table.Instance.TechDataAssets.GetTechInfo(_actionId.TechType); if (!actionParams.PlayerData.TechTree.CheckIfHasTech(techInfo.FatherTechList)) return false; //判断钱够不够 int cost = Main.PlayerLogic.GetTechCost(actionParams.MapData, actionParams.PlayerData, _actionId.TechType); if(cost > actionParams.PlayerData.PlayerCoin + actionParams.PlayerData.PlayerTechPoint) return false; return true; } public override bool CheckShow(CommonActionParams actionParams,out ShowType showType) { showType = ShowType.None; return false; } } public class PlayerTurnStartAction : ActionLogicBase { public PlayerTurnStartAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams) { if (!CheckCan(actionParams)) return false; actionParams.MapData.OnTurnStart(actionParams.PlayerData.Id); return true; } public override bool CheckCan(CommonActionParams actionParams) { if (actionParams.PlayerData == null) return false; if (actionParams.MapData.CurPlayer != null && actionParams.MapData.CurPlayer.Id == actionParams.PlayerData.Id) return false; return true; } public override bool CheckShow(CommonActionParams actionParams,out ShowType showType) { showType = ShowType.None; return false; } } public class PlayerTurnEndAction : ActionLogicBase { public PlayerTurnEndAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams) { if (!CheckCan(actionParams)) return false; actionParams.MapData.OnTurnEnd(actionParams.PlayerData.Id); return true; } public override bool CheckCan(CommonActionParams actionParams) { if (actionParams.PlayerData == null) return false; if (actionParams.MapData.CurPlayer == null) return false; if (actionParams.MapData.CurPlayer.Id != actionParams.PlayerData.Id) return false; return true; } public override bool CheckShow(CommonActionParams actionParams,out ShowType showType) { showType = ShowType.None; return false; } } public class AIParamControlAction : ActionLogicBase { public AIParamControlAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams) { if (_actionId.AIParamType is AIParamControlType.APClear or AIParamControlType.AllClear) { actionParams.UnitData.AP = 0; } if (_actionId.AIParamType is AIParamControlType.CPClear or AIParamControlType.AllClear) { actionParams.UnitData.CP = 0; } if (_actionId.AIParamType is AIParamControlType.MPClear or AIParamControlType.AllClear) { actionParams.UnitData.MP = 0; } if (_actionId.AIParamType == AIParamControlType.AIMoney) { if (!CheckAIMoney(actionParams)) return false; // AI 难度加钱 int tt = 0; if (actionParams.PlayerData.Turn < 10) tt = (int)actionParams.MapData.MapConfig.AIDiff; actionParams.PlayerData.AddCoin((int)actionParams.PlayerData.Turn / 5 * (int)Main.MapData.MapConfig.AIDiff + tt); return true; } return true; } public override bool CheckCan(CommonActionParams actionParams) { if (_actionId.AIParamType == AIParamControlType.AIMoney)return CheckAIMoney(actionParams); if (actionParams.UnitData == null) return false; if (_actionId.AIParamType == AIParamControlType.MPClear) return actionParams.UnitData.MP > 0; if (_actionId.AIParamType == AIParamControlType.CPClear) return actionParams.UnitData.CP > 0; if (_actionId.AIParamType == AIParamControlType.APClear) return actionParams.UnitData.AP > 0; if (_actionId.AIParamType == AIParamControlType.AllClear) return actionParams.UnitData.MP > 0 || actionParams.UnitData.CP > 0 || actionParams.UnitData.AP > 0; return false; } public override bool CheckShow(CommonActionParams actionParams,out ShowType showType) { showType = ShowType.None; return false; } private bool CheckAIMoney(CommonActionParams actionParams) { if (actionParams.PlayerData == null) return false; if (actionParams.MapData.Net.Mode == NetMode.Multi) { if (actionParams.MapData.CheckIsRealPlayer(actionParams.PlayerData.Id))return false; } else { if (actionParams.MapData.PlayerMap.SelfPlayerData.Id == actionParams.PlayerData.Id) return false; } return true; } } }