/* * @Author: 白哉 * @Description: 行为逻辑类 * @Date: 2025年04月10日 星期四 11:04:44 * @Modify: */ using System; using System.Collections.Generic; using System.Linq; using Logic.AI; using Logic.CrashSight; using MemoryPack; using RuntimeData; using TH1_Logic.Action; using TH1_Logic.Core; using TH1_Logic.Steam; using UnityEngine; using TH1Renderer; public enum GridMiscActionType{None,GrowForest,ClearForest,BurnForest,Destroy,UpgradeTemple,GrowForestOutside} namespace Logic.Action { // 行为类型枚举 public enum CommonActionType { Gain, Build, StartWonder, BuildWonder, TrainUnit, GridMisc, UnitAction, CityLevelUpAction, UnitSkill, LearnTech, UnitMove, UnitAttack, PlayerAction } public enum ActionShowState { None, Available, Unavailable, Expensive, Finished } // 通用行为参数类 [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() { } 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; 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 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; } } // 通用行为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; [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(); 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; 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 += $"ActionType : {ActionType}\n"; log += $"WonderType : {WonderType}\n"; log += $"ResourceType : {ResourceType}\n"; log += $"FeatureType : {FeatureType}\n"; log += $"TerrainType : {TerrainType}\n"; log += $"UnitType : {UnitType}\n"; log += $"GiantType : {GiantType}\n"; log += $"Vegetation : {Vegetation}\n"; log += $"UnitActionType : {UnitActionType}\n"; log += $"CityLevelUpActionType : {CityLevelUpActionType}\n"; log += $"GridMiscActionType : {GridMiscActionType}\n"; log += $"SkillType : {SkillType}\n"; log += $"TechType : {TechType}\n"; log += $"PlayerActionType : {PlayerActionType}\n"; log += $"PlayerId : {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 Refresh() { if (ActionLogicDict != null) return; ActionLogicDict = new Dictionary(); CommonActionId commonActionId; commonActionId = new CommonActionId { ActionType = CommonActionType.UnitMove }; ActionLogicDict[commonActionId] = new UnitMoveAction(commonActionId); commonActionId = new CommonActionId { ActionType = CommonActionType.UnitAttack }; ActionLogicDict[commonActionId] = new UnitAttackAction(commonActionId); for (int i = (int)PlayerActionType.OfferAlly; i < (int)PlayerActionType.Max; i++) { commonActionId = new CommonActionId { ActionType = CommonActionType.PlayerAction, PlayerActionType = (PlayerActionType)i, }; ActionLogicDict[commonActionId] = new PlayerActionAction(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, }; if(resourceType is ResourceType.Sawmill or ResourceType.Windmill or ResourceType.Mine or ResourceType.Farm or ResourceType.Forge or ResourceType.LumberHut or ResourceType.Port or ResourceType.Bridge or ResourceType.Market or ResourceType.Academy or ResourceType.Military) ActionLogicDict[commonActionId] = new BuildAction(commonActionId); else if (resourceType is ResourceType.ForestTemple or ResourceType.WaterTemple or ResourceType.Temple or ResourceType.MountainTemple or ResourceType.KingTemple) ActionLogicDict[commonActionId] = new BuildActionBuildTemple(commonActionId); else if (resourceType == ResourceType.Preserve) ActionLogicDict[commonActionId] = new BuildActionBuildPreserve(commonActionId); else if (resourceType == ResourceType.NavalBase) ActionLogicDict[commonActionId] = new BuildActionBuildNavalBase(commonActionId); else if (resourceType == ResourceType.KaguyaFrenchYard) ActionLogicDict[commonActionId] = new BuildActionBuildKaguyaFrenchYard(commonActionId); } //登记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 }; if (gridMiscActionType == GridMiscActionType.UpgradeTemple) ActionLogicDict[commonActionId] = new GridMiscActionUpgradeTemple(commonActionId); else if (gridMiscActionType == GridMiscActionType.GrowForestOutside) ActionLogicDict[commonActionId] = new GridMiscActionGrowTreeOutside(commonActionId); else ActionLogicDict[commonActionId] = new GridMiscAction(commonActionId); } //登记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 }; ActionLogicDict[commonActionId] = new TrainUnitActionTrainGiant(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.GiantUpgrade: 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; 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 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 PlayerActionAction(commonActionId); } 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) { actionList = new List(); var actionDict = GetActionLogicDict(); foreach (var action in actionDict.Values) { if (!action.CheckShow(param)) continue; actionList.Add(action); } 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; 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 abstract bool ExecuteViewBefore(CommonActionParams actionParams); public abstract bool ExecuteViewAfter(CommonActionParams actionParams); // 完整的执行调用, 供外部使用 public virtual bool CompleteExecute(CommonActionParams actionParams, bool isMoment) { var ret = Execute(actionParams, isMoment); AfterExecute(actionParams, isMoment); return ret; } // 实际的执行逻辑 protected abstract bool Execute(CommonActionParams actionParams, bool isMoment); // 执行后逻辑 protected virtual void AfterExecute(CommonActionParams actionParams, bool isMoment) { //更新所有人的外交好感情况。临时用的。必须真map才做,AI预测的不做,性能爆炸了 if (actionParams.MapData == Main.MapData) { foreach (var pData in actionParams.MapData.PlayerMap.PlayerDataList) pData.RefreshFeelingValue(actionParams.MapData); } } public abstract bool CheckCan(CommonActionParams actionParams); public abstract bool CheckShow(CommonActionParams actionParams); public abstract ActionShowState CheckShowState(CommonActionParams actionParams); 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, bool isMoment) { if(!actionParams.MapData.GetCityDataByTerritoryGid(actionParams.GridData.Id,out var city)) return false; //给city增加3点exp if (!Table.Instance.GridAndResourceDataAssets.GetWonderInfoByType(_actionId.WonderType,actionParams.PlayerData, out var wonderInfo)) return false; if (actionParams.PlayerData == null) return false; var player = actionParams.PlayerData; //临时做法,用来播放VFX,获取Main,理应向MapData写入一个VFX的RenderMark的 var main = GameObject.Find("Main").GetComponent
(); if (actionParams.MapData == Main.MapData && actionParams.PlayerData.Id == actionParams.MapData.PlayerMap.SelfPlayerData.Id) { var v1 = Table.Instance.GridToWorld(actionParams.GridData); actionParams.MapData.GetGridDataByCityId(city.Id, out var g2); var v2 = Table.Instance.GridToWorld(g2); Timer.Instance.TimerRegister(Main.CityLogic, () => { int score = wonderInfo.Exp * 5; MapRenderer.Instance.ROGridMap[g2.Id].SetBounceAnim(); score += 50 * Main.CityLogic.CityUpdateExp(actionParams.MapData,city,wonderInfo.Exp); if (actionParams.PlayerData.Id == actionParams.MapData.PlayerMap.SelfPlayerData.Id) { var faithPanel = GameObject.Find("UICanvas/TopBarPanel/FaithPanel/Icon").transform; var endPos = faithPanel.position; MapRenderer.Instance.ProjectileManager.CreateProjectile(v2,endPos,ProjectileType.Faith,ProjectileMoveType.CoinParabola,score); } }, Table.Instance.AnimDataAssets.ProjectileCityExpMoveTime,"ActionLogic_BuildWonder_Execute_728"); //播放雾效和丢出cityexp & 丢出信仰分 的动画 actionParams.GridData.VFXRenderMarkFog = true; MapRenderer.Instance.ProjectileManager.CreateProjectileMulti(v1,v2,ProjectileType.CityExp,ProjectileMoveType.CityExpHighParabola,wonderInfo.Exp); if (actionParams.PlayerData.Id == actionParams.MapData.PlayerMap.SelfPlayerData.Id) { var faithPanel = GameObject.Find("UICanvas/TopBarPanel/FaithPanel/Icon").transform; var endPos = faithPanel.position; MapRenderer.Instance.ProjectileManager.CreateProjectile( v1, endPos, ProjectileType.Faith, ProjectileMoveType.CoinParabola, 300); } } else Main.CityLogic.CityUpdateExp(actionParams.MapData,city,wonderInfo.Exp); actionParams.GridData.ResourceUnderBuilding = actionParams.GridData.Resource; actionParams.GridData.Resource = ResourceType.Wonder; actionParams.GridData.Wonder = wonderInfo.Wonder; player.Wonder.SetWonderState(wonderInfo.WonderType,WonderState.FINISH_BUILD); actionParams.GridData.RenderMark = true; 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.PlayerWealth) return false; return false; } public override bool CheckShow(CommonActionParams actionParam) { return CheckCan(actionParam); } public override ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; } public override bool ExecuteViewBefore(CommonActionParams actionParams) { return false; } public override bool ExecuteViewAfter(CommonActionParams actionParams) { return false; } } // Gain 收获资源逻辑类 public class GainResourceAction : ActionLogicBase { public GainResourceAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams, bool isMoment) { if (!CheckCan(actionParams)) return false; CityData cityData = actionParams.CityData; if (cityData == null) actionParams.MapData.GetCityDataByTerritoryGid(actionParams.GridData.Id,out cityData); //扣钱,收获资产,把资产送往city actionParams.PlayerData.PlayerWealth -= GetCost(); //如果是玩家,执行一整套播放动画的逻辑 //临时做法,用来播放VFX,获取Main,理应向MapData写入一个VFX的RenderMark的 if (Main.MapData == actionParams.MapData && actionParams.PlayerData.Id == actionParams.MapData.PlayerMap.SelfPlayerData.Id) { var v1 = Table.Instance.GridToWorld(actionParams.GridData); actionParams.MapData.GetGridDataByCityId(cityData.Id, out var g2); var v2 = Table.Instance.GridToWorld(g2); //播放城市增加exp的动画 Timer.Instance.TimerRegister(Main.CityLogic, () => { int score = Table.Instance.QueryActionExp(_actionId) * 5; MapRenderer.Instance.ROGridMap[g2.Id].SetBounceAnim(); score += 50 * Main.CityLogic.CityUpdateExp(actionParams.MapData,cityData,Table.Instance.QueryActionExp(_actionId)); if (actionParams.PlayerData.Id == actionParams.MapData.PlayerMap.SelfPlayerData.Id) { var faithPanel = GameObject.Find("UICanvas/TopBarPanel/FaithPanel/Icon").transform; var endPos = faithPanel.position; MapRenderer.Instance.ProjectileManager.CreateProjectile(v2,endPos,ProjectileType.Faith,ProjectileMoveType.CoinParabola,score); } }, Table.Instance.AnimDataAssets.ProjectileCityExpMoveTime,"ActionLogic_Gain_ExpAnim"); //播放雾效和丢出cityexp的动画 actionParams.GridData.VFXRenderMarkFog = true; MapRenderer.Instance.ProjectileManager.CreateProjectile(v1,v2,ProjectileType.CityExp,ProjectileMoveType.CityExpHighParabola); } //否则执行常规 else { Main.CityLogic.CityUpdateExp(actionParams.MapData,cityData,Table.Instance.QueryActionExp(_actionId)); } //消除水果 actionParams.GridData.Resource = ResourceType.None; actionParams.GridData.RenderMark = true; //更新所有建筑的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.PlayerWealth) 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) { 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; } public override bool ExecuteViewBefore(CommonActionParams actionParams) { return false; } public override bool ExecuteViewAfter(CommonActionParams actionParams) { return false; } } //CityLevelUp 行动逻辑类 public class CityLevelUpActionAction : ActionLogicBase { public CityLevelUpActionAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams, bool isMoment) { //鲁棒性判断 if (actionParams.CityData == null) return false; if (!actionParams.MapData.GetGridDataByCityId(actionParams.CityData.Id, out var gridData)) return false; if (actionParams.CityData.CityLevelUpPoint <= 0) return false; if (!actionParams.MapData.GetPlayerDataByCityId(actionParams.CityData.Id, out var playerData)) return false; actionParams.CityData.CityLevelUpPoint --; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Explorer) { // 1. 锁定玩家输入 Main main = GameObject.FindObjectOfType
(); main.InputLogic.LockInput(); //Debug.Log("玩家输入已锁定"); // 2. 创建临时探索者图像,3秒后自动销毁 MapRenderer.Instance.CreateTemporaryExplorer(gridData, 3f); actionParams.CityData.CityInfoRenderMark = true; return true; } if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Workshop) { actionParams.CityData.Workshop = true; actionParams.CityData.CityInfoRenderMark = true; return true; } if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWealth) { playerData.PlayerWealth += 5; actionParams.CityData.CityInfoRenderMark = true; return true; } if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWall) { actionParams.CityData.CityWall = true; gridData.RenderMark = true; //如果city上有单位,也要更新单位的渲染 if (actionParams.MapData.GetUnitDataByGid(gridData.Id, out var unit)) unit.RenderMark = true; return true; } if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Expand) { Main.CityLogic.CityLevelUpActionExpand(actionParams.MapData,actionParams.CityData); actionParams.CityData.CityInfoRenderMark = true; //要更新玩家所有城市所有格子的levelbuilding Main.PlayerLogic.UpdateTerritoryAllBuildingLevel(actionParams.MapData,playerData.Id); //更新所有国家的联通情况 Main.PlayerLogic.UpdateAllPlayerConnected(actionParams.MapData); //更新特殊占领技能 if(playerData.GetSkill(SkillType.KaguyaFrenchNapoleonicCode,out var _)) Main.PlayerLogic.SetCityTerritoryGridSp(actionParams.MapData,actionParams.CityData,GridSpType.KaguyaGrid); return true; } if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Population) { Main.CityLogic.CityUpdateExp(actionParams.MapData,actionParams.CityData,3); actionParams.CityData.CityInfoRenderMark = true; return true; } if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Park) { actionParams.CityData.ParkCount++; actionParams.CityData.CityInfoRenderMark = true; return true; } if (_actionId.CityLevelUpActionType == CityLevelUpActionType.BigGuy) { if(actionParams.MapData.GetUnitDataByGid(gridData.Id,out var unitData)) Main.UnitLogic.PassiveMoveAway(actionParams.MapData, unitData); actionParams.MapData.AddUnitData(gridData.Id,actionParams.CityData.Id,UnitType.BigGuy); actionParams.CityData.CityInfoRenderMark = true; return true; } return false; } public override bool CheckCan(CommonActionParams actionParams) { if (actionParams.CityData == null) return false; //如果没有升级行动的点数,退出 if (actionParams.CityData.CityLevelUpPoint <= 0) return false; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Explorer) return actionParams.CityData.Level == 3; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Workshop) return actionParams.CityData.Level == 3; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWall) return actionParams.CityData.Level == 4; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWealth) return actionParams.CityData.Level == 4; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Population) return actionParams.CityData.Level == 5; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Expand) return actionParams.CityData.Level == 5; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Park) return actionParams.CityData.Level > 5; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.BigGuy) return actionParams.CityData.Level > 5; return false; } public override bool CheckShow(CommonActionParams actionParams) { if (actionParams.CityData == null) return false; //如果没有升级行动的点数,退出 if (actionParams.CityData.CityLevelUpPoint <= 0) return false; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Explorer) return actionParams.CityData.Level == 3; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Workshop) return actionParams.CityData.Level == 3; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWall) return actionParams.CityData.Level == 4; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWealth) return actionParams.CityData.Level == 4; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Population) return actionParams.CityData.Level == 5; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Expand) return actionParams.CityData.Level == 5; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Park) return actionParams.CityData.Level > 5; if (_actionId.CityLevelUpActionType == CityLevelUpActionType.BigGuy) return actionParams.CityData.Level > 5; return false; } public override ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; } public override bool ExecuteViewBefore(CommonActionParams actionParams) { return false; } public override bool ExecuteViewAfter(CommonActionParams actionParams) { return false; } } // 小兵移动,目前只用于 AI 的行为 public class UnitMoveAction : ActionLogicBase { public UnitMoveAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams, bool isMoment) { if (actionParams.MapData.GetGridDataByUnitId(actionParams.UnitData.Id, out var unitGrid)) { var distance = actionParams.MapData.GridMap.CalcDistance(unitGrid, actionParams.GridData); } Main.UnitLogic.MoveTo(actionParams.MapData, actionParams.UnitData, actionParams.GridData, MoveType.ActiveMove); return true; } public override bool CheckCan(CommonActionParams actionParams) { return true; } public override bool CheckShow(CommonActionParams actionParams) { 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 override float GetAnimTime(CommonActionParams actionParams) { return Table.Instance.AnimDataAssets.MoveAnimTime + Table.Instance.AnimDataAssets.AIAfterMoveColdDownTime;// + Table.Instance.AnimDataAssets.AIBeforeAnimWaitTime; }*/ public override bool ExecuteViewBefore(CommonActionParams actionParams) { return false; } public override bool ExecuteViewAfter(CommonActionParams actionParams) { return false; } } // 小兵攻击,目前只用于 AI 的行为 public class UnitAttackAction : ActionLogicBase { public UnitAttackAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams, bool isMoment) { Main.UnitLogic.Attack(actionParams.MapData, actionParams.UnitData, actionParams.TargetUnitData, out _duration, isMoment); return true; } public override bool CheckCan(CommonActionParams actionParams) { 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; return true; } public override bool CheckShow(CommonActionParams actionParams) { 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 override float GetAnimTime(CommonActionParams actionParams) { var unit1 = actionParams.UnitData; if(actionParams.UnitData == null || !actionParams.MapData.UnitMap.GetUnitDataByUnitId(actionParams.TargetUnitId, out var unit2)) return 0.05f; return Main.UnitLogic.AttackAnimTime(actionParams.MapData, unit1, unit2) + Table.Instance.AnimDataAssets.AIAfterAttackColdDownTime;// + Table.Instance.AnimDataAssets.AIBeforeAnimWaitTime; }*/ public override bool ExecuteViewBefore(CommonActionParams actionParams) { return false; } public override bool ExecuteViewAfter(CommonActionParams actionParams) { return false; } } public class StartWonderAction : ActionLogicBase { public StartWonderAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams, bool isMoment) { return false; } public override bool CheckCan(CommonActionParams actionParams) { return false; } public override bool CheckShow(CommonActionParams actionParams) { return false; } public override ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; } public override bool ExecuteViewBefore(CommonActionParams actionParams) { return false; } public override bool ExecuteViewAfter(CommonActionParams actionParams) { return false; } } //TODO 没有填写Skill public class UnitSkillAction : ActionLogicBase { public UnitSkillAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams, bool isMoment) { return false; } public override bool CheckCan(CommonActionParams actionParams) { return false; } public override bool CheckShow(CommonActionParams actionParams) { return false; } public override ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; } public override bool ExecuteViewBefore(CommonActionParams actionParams) { return false; } public override bool ExecuteViewAfter(CommonActionParams actionParams) { return false; } } public class LearnTechAction : ActionLogicBase { public LearnTechAction(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams, bool isMoment) { if (actionParams.MainObjectType != MainObjectType.Player) return false; if (actionParams.PlayerData == null) return false; int cost = Main.PlayerLogic.GetRealCost(actionParams.MapData, actionParams.PlayerData, _actionId.TechType); Main.PlayerLogic.ResearchTech(actionParams.MapData,actionParams.PlayerData,_actionId.TechType,cost); 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.FatherTechType)) return false; //判断钱够不够 if (GetCost() > actionParams.PlayerData.PlayerWealth) return false; int cost = Main.PlayerLogic.GetRealCost(actionParams.MapData, actionParams.PlayerData, _actionId.TechType); if(cost > actionParams.PlayerData.PlayerWealth) return false; return true; } public override bool CheckShow(CommonActionParams actionParams) { return false; } public override ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; } public override bool ExecuteViewBefore(CommonActionParams actionParams) { return false; } public override bool ExecuteViewAfter(CommonActionParams actionParams) { return false; } } }