/* * @Author: 白哉 * @Description: 行为逻辑类 * @Date: 2025年04月10日 星期四 11:04:44 * @Modify: */ using System; using System.Collections.Generic; using System.Linq; using Logic.Action; using RuntimeData; using TH1_Core.Events; using TH1_Core.Managers; using TH1_Logic.Core; using TH1Renderer; using Unity.VisualScripting.Antlr3.Runtime.Tree; using UnityEngine; //这里是所有BuildAction派生子类的实现模块 namespace TH1_Logic.Action { public enum PlayerActionType { None, OfferAlly, AcceptAlly, RefuseAlly, BreakAlly, Embassy, SelectHero, FinishHeroTask, Max } //UnitAction单位行动逻辑类 public class PlayerActionAction : ActionLogicBase { public PlayerActionAction(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) { return false; } protected bool PlayerActionCheckBaseInfo(CommonActionParams actionParam) { //鲁棒性判断,必须包含playerData,表明是哪个玩家正在操作哪个单位 if (actionParam.PlayerData == null) return false; return true; } } //UnitAction单位行动逻辑类 public class PlayerActionDiplomacy : PlayerActionAction { public PlayerActionDiplomacy(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams) { //Step #1 鲁棒性判断 if (actionParams.PlayerData == null) return false; if (actionParams.MainObjectType != MainObjectType.Player) return false; if (actionParams.TargetPlayerData == null) return false; if (!CheckCan(actionParams)) return false; MapData map = actionParams.MapData; PlayerData player = actionParams.PlayerData; PlayerData targetPlayer = actionParams.TargetPlayerData; if (!map.GetCapitalCityDataByPlayerId(actionParams.TargetPlayerData.Id, out var targetCity)) return false; if (!map.GetCapitalCityDataByPlayerId(actionParams.PlayerData.Id, out var city)) return false; if (!map.GetGridDataByCityId(targetCity.Id, out var targetGrid)) return false; actionParams.PlayerData.GetCountryDiplomacyInfo(actionParams.TargetPlayerData.Id, out var dipInfo); actionParams.TargetPlayerData.GetCountryDiplomacyInfo(actionParams.PlayerData.Id,out var dipInfo2); //Step #2 处理大使馆 if (_actionId.PlayerActionType == PlayerActionType.Embassy) { //Step #1建立大使馆, dipInfo.IsEmbassy = true; //如果是真人玩家 在其他首都建立大使馆,更新对应城市的视觉,播放大使馆建立特效 if (actionParams.MapData == Main.MapData && player.Id == Main.MapData.PlayerMap.SelfPlayerId) { targetCity.SetCityRenderer(actionParams.MapData); targetGrid.Renderer(actionParams.MapData)?.PlayVFX(new GridVFXParams(GridVFXType.Treasure)); } //如果是真人玩家 AI在真人玩家的首都建立大使馆,更新对应城市的视觉, if (actionParams.MapData == Main.MapData && targetPlayer.Id == Main.MapData.PlayerMap.SelfPlayerId) { city.SetCityRenderer(actionParams.MapData); } //Step #2 如果对方还没有meet我,加入meetlist if(!targetPlayer.MeetPlayers.Contains(player.Id)) Main.PlayerLogic.AddMeetPlayer(map,targetPlayer,player); //Step #3 更新大使馆周围一格的视野,会自动处理视觉部分 var gidList = map.GridMap.GetAroundGridIdList(1,targetGrid,true ); Main.PlayerLogic.UpdateSight(map,player,gidList); //step #4 扣钱 player.PlayerWealth -= GetCost(); //Step #5 如果是真人玩家发起,弹出一个announce,并关闭当前info if (player.Id == Main.MapData.PlayerMap.SelfPlayerId) { var announcement = new ShowUIAnnounceDiplomacy { PlayerActionType = PlayerActionType.Embassy,PlayerId = player.Id,TargetPlayerId = targetPlayer.Id }; EventManager.Publish(announcement); EventManager.Publish(new HideUIInfoDiplomacy()); } //Step #6 如果是其他玩家发起但是目标是真人玩家,弹出一个announce,并关闭当前info if (targetPlayer.Id == Main.MapData.PlayerMap.SelfPlayerId) { var announcement = new ShowUIAnnounceDiplomacy { PlayerActionType = PlayerActionType.Embassy,PlayerId = player.Id,TargetPlayerId = targetPlayer.Id }; EventManager.Publish(announcement); EventManager.Publish(new HideUIInfoDiplomacy()); } return true; } //Step #3 处理申请结盟 if (_actionId.PlayerActionType == PlayerActionType.OfferAlly) { //Step #1 让对方收到我方邮件 dipInfo2.IsLeagueRequest = true; //Step #2 如果对方还没有meet我,加入meetlist if(!targetPlayer.MeetPlayers.Contains(player.Id)) Main.PlayerLogic.AddMeetPlayer(map,targetPlayer,player); //Step #3 如果是真人玩家发起,弹出一个notify,并关闭当前info if (Main.MapData == actionParams.MapData && player.Id == Main.MapData.PlayerMap.SelfPlayerId) { EventManager.Publish(new ShowUINotifyCommon(){UINotifyCommonType = UINotifyCommonType.DiplomacyOfferAlly}); EventManager.Publish(new HideUIInfoDiplomacy()); } //Step #4 如果是真人玩家收到,那么要到下回合开始的时候才会触发 return true; } //Step #4 处理accept结盟 if (_actionId.PlayerActionType == PlayerActionType.AcceptAlly) { //Step #1 关闭我方的对方结盟信件请求标记,登记为盟友 dipInfo.IsLeagueRequest = false; //如果我方也给对方发邮件,也关闭 dipInfo2.IsLeagueRequest = false; dipInfo.DiplomacyState = DiplomacyState.League; dipInfo2.DiplomacyState = DiplomacyState.League; //Step #2 如果target是真map真人玩家 弹出一个presentationUI 提示,达成盟友,更新双方首都的cityinfo if (map == Main.MapData && targetPlayer.Id == map.PlayerMap.SelfPlayerId) { var announcement = new ShowUIAnnounceDiplomacy { PlayerActionType = PlayerActionType.AcceptAlly,PlayerId = player.Id,TargetPlayerId = targetPlayer.Id }; EventManager.Publish(announcement); city.SetCityRenderer(actionParams.MapData); targetCity.SetCityRenderer(actionParams.MapData); } //Step #3 如果是真map,我方是真人玩家,更新双方首都的cityinfo if (map == Main.MapData && player.Id == map.PlayerMap.SelfPlayerId) { city.SetCityRenderer(actionParams.MapData); targetCity.SetCityRenderer(actionParams.MapData); } //Step #4 如果是真map,双方有一个是真人玩家,就要处理的视觉情况 if (map == Main.MapData && (player.Id == map.PlayerMap.SelfPlayerId) || (targetPlayer.Id == map.PlayerMap.SelfPlayerId)) { foreach (var tunit in map.UnitMap.UnitList) { if(!map.GetPlayerDataByUnitId(tunit.Id,out var uplayer))continue; if (uplayer.Id == map.PlayerMap.SelfPlayerId) continue; if (uplayer.Id == targetPlayer.Id || uplayer.Id == player.Id) tunit.Renderer(map)?.InstantUpdateUnit(true); } city.SetCityRenderer(actionParams.MapData); targetCity.SetCityRenderer(actionParams.MapData); EventManager.Publish(new HideUIInfoDiplomacy()); } return true; } //Step #5 处理refuse结盟 if (_actionId.PlayerActionType == PlayerActionType.RefuseAlly) { //Step #1 关闭对方的结盟请求标记 dipInfo.IsLeagueRequest = false; //Step #2 如果target是真map真人玩家 弹出一个presentationUI 提示,明确拒绝对方 if (map == Main.MapData && targetPlayer.Id == map.PlayerMap.SelfPlayerId) { var announcement = new ShowUIAnnounceDiplomacy { PlayerActionType = PlayerActionType.RefuseAlly,PlayerId = player.Id ,TargetPlayerId = targetPlayer.Id }; EventManager.Publish(announcement); } return true; } //Step #6 处理break结盟 if (_actionId.PlayerActionType == PlayerActionType.BreakAlly) { //Step #1 设置双方的外交状态为背盟 dipInfo.DiplomacyState = DiplomacyState.LeagueRupture; dipInfo2.DiplomacyState = DiplomacyState.LeagueRupture; var disbandList = new List(); //Step #2 所有单位跳过本回合,所有对方领土的单位自动解散 foreach (var unit in map.UnitMap.UnitList) { if(!map.GetPlayerDataByUnitId(unit.Id,out var uplayer))continue; if(uplayer.Id != player.Id) continue; if (!map.GetGridDataByUnitId(unit.Id, out var ugrid)) continue; var gridHasPlayer = map.GetPlayerDataByTerritoryGridId(ugrid.Id, out var ugridPlayer); //如果是对方领土上的己方unit,强制解散 if (gridHasPlayer && ugridPlayer.Id == targetPlayer.Id) { //加入解散列表。不能就地解散因为会影响到map.UnitMap.UnitList disbandList.Add(unit); } else { unit.ClearAPMPCP(); unit.Renderer(map)?.InstantUpdateUnit(true); } } foreach (var unit in disbandList) { var action = ActionLogicFactory.GetActionLogic(new CommonActionId() { ActionType = CommonActionType.UnitAction, UnitActionType = UnitActionType.ForceDisband }); var param = new CommonActionParams() { MainObjectType = MainObjectType.Unit, MapData = map, UnitData = unit, PlayerData = player }; action?.CompleteExecute(param); } //Step #3 如果target是真map真人玩家 弹出一个presentationUI 提示,明确背叛对方,更新双方cityinfo if (map == Main.MapData && targetPlayer.Id == map.PlayerMap.SelfPlayerId) { var announcement = new ShowUIAnnounceDiplomacy { PlayerActionType = PlayerActionType.BreakAlly,PlayerId = player.Id,TargetPlayerId = targetPlayer.Id }; EventManager.Publish(announcement); } //Step #4 如果是真map,双方有一个是真人玩家,就要处理的视觉情况 if (map == Main.MapData && (player.Id == map.PlayerMap.SelfPlayerId) || (targetPlayer.Id == map.PlayerMap.SelfPlayerId)) { foreach (var tunit in map.UnitMap.UnitList) { if(!map.GetPlayerDataByUnitId(tunit.Id,out var uplayer))continue; if (uplayer.Id == map.PlayerMap.SelfPlayerId) continue; if (uplayer.Id == targetPlayer.Id || uplayer.Id == player.Id) tunit.Renderer(map)?.InstantUpdateUnit(true); } city.SetCityRenderer(actionParams.MapData); targetCity.SetCityRenderer(actionParams.MapData); EventManager.Publish(new HideUIInfoDiplomacy()); } return true; } return false; } public override bool CheckCan(CommonActionParams actionParams) { //Step #1 鲁棒性判断 if (actionParams.PlayerData == null || !actionParams.PlayerData.Alive) return false; if (actionParams.MainObjectType != MainObjectType.Player) return false; if (actionParams.TargetPlayerData == null || !actionParams.TargetPlayerData.Alive ) return false; if (!actionParams.PlayerData.MeetPlayers.Contains(actionParams.TargetPlayerData.Id)) return false; //Step #2 判断钱够不够 if (GetCost() > actionParams.PlayerData.PlayerWealth) return false; //Step #3 如果不具备科技 return if (!actionParams.PlayerData.TechTree.CheckActionCan(_actionId)) return false; //Step #4 处理大使馆 if (_actionId.PlayerActionType == PlayerActionType.Embassy) { //如果对方没有原始首都,不可建立大使馆 actionParams.MapData.GetCapitalCityDataByPlayerId(actionParams.TargetPlayerData.Id,out var city); if (!Main.CityLogic.CheckCradleCapital(actionParams.MapData, actionParams.TargetPlayerData, city)) return false; //如果已经在对方建立了大使馆,不可再次建立大使馆 actionParams.PlayerData.GetCountryDiplomacyInfo(actionParams.TargetPlayerData.Id, out var dipInfo); if (dipInfo.IsEmbassy) return false; return true; } //Step #5 判断能否申请结盟 if (_actionId.PlayerActionType == PlayerActionType.OfferAlly) { actionParams.PlayerData.GetCountryDiplomacyInfo(actionParams.TargetPlayerData.Id, out var dipInfo); //如果刚解除结盟或者已经结盟 return if (dipInfo.DiplomacyState == DiplomacyState.League || dipInfo.DiplomacyState == DiplomacyState.LeagueRupture) return false; //如果对方已经有一个来自我方的结盟请求 actionParams.TargetPlayerData.GetCountryDiplomacyInfo(actionParams.PlayerData.Id,out var dipInfo2); if (dipInfo2.IsLeagueRequest) return false; return true; } //Step #6 && #7 判断能否refuse / accept 结盟 if (_actionId.PlayerActionType == PlayerActionType.RefuseAlly || _actionId.PlayerActionType == PlayerActionType.AcceptAlly) { actionParams.PlayerData.GetCountryDiplomacyInfo(actionParams.TargetPlayerData.Id, out var dipInfo); //如果刚解除结盟或者已经结盟 return if (dipInfo.DiplomacyState == DiplomacyState.League || dipInfo.DiplomacyState == DiplomacyState.LeagueRupture) return false; //如果对方没有结盟请求 //actionParams.TargetPlayerData.DiplomacyData.GetCountryDiplomacyInfo(actionParams.PlayerData.Id,out var dipInfo2); if (!dipInfo.IsLeagueRequest) return false; return true; } //Step #8 判断能否break结盟 if (_actionId.PlayerActionType == PlayerActionType.BreakAlly) { actionParams.PlayerData.GetCountryDiplomacyInfo(actionParams.TargetPlayerData.Id, out var dipInfo); //如果没有结盟 return if (dipInfo.DiplomacyState != DiplomacyState.League) return false; //如果对方率先break,return actionParams.TargetPlayerData.GetCountryDiplomacyInfo(actionParams.PlayerData.Id,out var dipInfo2); if (dipInfo2.DiplomacyState == DiplomacyState.LeagueRupture) return false; return true; } return false; } public override bool CheckShow(CommonActionParams actionParams) { //Step #1 鲁棒性判断 if (actionParams.PlayerData == null) return false; if (actionParams.MainObjectType != MainObjectType.Player) return false; if (actionParams.TargetPlayerData == null) return false; actionParams.PlayerData.GetCountryDiplomacyInfo(actionParams.TargetPlayerData.Id, out var dipInfo); //Step #2 如果与对方已经结盟,不能显示结盟按钮 if(dipInfo.DiplomacyState == DiplomacyState.League && _actionId.PlayerActionType == PlayerActionType.OfferAlly) return false; //Step #2 如果未与结盟,不能显示接触结盟按钮 if(dipInfo.DiplomacyState != DiplomacyState.League && _actionId.PlayerActionType == PlayerActionType.BreakAlly) return false; return true; } public override ActionShowState CheckShowState(CommonActionParams actionParams) { //Step #1 鲁棒性判断 if (actionParams.PlayerData == null) return ActionShowState.None; if (actionParams.MainObjectType != MainObjectType.Player) return ActionShowState.None; if (actionParams.TargetPlayerData == null) return ActionShowState.None; MapData map = actionParams.MapData; PlayerData player = actionParams.PlayerData; PlayerData targetPlayer = actionParams.TargetPlayerData; if (!map.GetCapitalCityDataByPlayerId(actionParams.TargetPlayerData.Id, out var city)) return ActionShowState.None; if (!map.GetGridDataByCityId(city.Id, out var grid)) return ActionShowState.None; actionParams.PlayerData.GetCountryDiplomacyInfo(actionParams.TargetPlayerData.Id, out var dipInfo); actionParams.TargetPlayerData.GetCountryDiplomacyInfo(actionParams.PlayerData.Id,out var dipInfo2); //Step #2 计算结盟按钮的情况 if (_actionId.PlayerActionType == PlayerActionType.OfferAlly) { //如果没有科技 if (!actionParams.PlayerData.TechTree.CheckActionCan(_actionId)) return ActionShowState.Unavailable; //如果已经发送过,还没被回应 if(dipInfo2.IsLeagueRequest || dipInfo.DiplomacyState == DiplomacyState.LeagueRupture) return ActionShowState.Unavailable; //如果已经结盟 if (dipInfo.DiplomacyState == DiplomacyState.League ) return ActionShowState.Finished; //其他情况一律是available return ActionShowState.Available; } //Step #3 计算breakAlly按钮的情况 if (_actionId.PlayerActionType == PlayerActionType.BreakAlly) { return ActionShowState.Available; } //Step #4 计算embassy按钮的情况 if (_actionId.PlayerActionType == PlayerActionType.Embassy) { //如果没有科技 if (!actionParams.PlayerData.TechTree.CheckActionCan(_actionId)) return ActionShowState.Unavailable; //如果对方已经丢失原始首都 if (!map.GetCapitalCityDataByPlayerId(targetPlayer.Id, out var targetCapital)) return ActionShowState.None; if (!Main.CityLogic.CheckCradleCapital(map, targetPlayer, targetCapital)) return ActionShowState.Unavailable; //如果钱不够 if (player.PlayerWealth < GetCost()) return ActionShowState.Expensive; //如果已经建立了大使馆 if (dipInfo.IsEmbassy) return ActionShowState.Finished; //其他情况一律是available return ActionShowState.Available; } return ActionShowState.None; } } //如果有空的槽位,那么将空的槽位设置为选择的特定hero。 //[actionId参数]只要一个giantType即可 //[param参数]只要player即可 public class PlayerActionSelectHero : PlayerActionAction { public PlayerActionSelectHero(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams) { var player = actionParams.PlayerData; var heroD = player.PlayerHeroData; return heroD.AddHero(_actionId.GiantType); } public override bool CheckCan(CommonActionParams actionParams) { //Step #1 基础鲁棒性检查 if (!PlayerActionCheckBaseInfo(actionParams)) return false; var player = actionParams.PlayerData; var heroD = player.PlayerHeroData; //Step #2 检查英雄类型属于当前玩家阵营 if (!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType.Giant, _actionId.GiantType, 0, out var info)) return false; if (info.GiantCivId != actionParams.PlayerData.PlayerCivId || info.GiantForceId != actionParams.PlayerData.PlayerForceId) return false; //Step #3 检查当前玩家的HeroData,是否已经出了英雄,且拥有空的槽位 if (heroD.HeroCount >= heroD.MaxHeroCount) return false; if (heroD.HasHero(_actionId.GiantType)) return false; return true; } } //立即完成一个英雄的升级任务 //[actionId参数]只要一个giantType即可 //[param参数]只要player即可 public class PlayerActionFinishHeroTask : PlayerActionAction { public PlayerActionFinishHeroTask(CommonActionId id) : base(id) { } protected override bool Execute(CommonActionParams actionParams) { var player = actionParams.PlayerData; var heroD = player.PlayerHeroData; var cost = heroD.GetHeroFinishTaskCost(_actionId.GiantType); var can = heroD.FinishHeroTask(_actionId.GiantType); if (can) { //如果是玩家,拿钱扣款 if (actionParams.PlayerData == actionParams.MapData.PlayerMap.SelfPlayerData) { actionParams.MapData.PlayerMap.SelfPlayerData.PlayerWealth -= cost; } } return can; } public override bool CheckCan(CommonActionParams actionParams) { //Step #1 基础鲁棒性检查 if (!PlayerActionCheckBaseInfo(actionParams)) return false; var player = actionParams.PlayerData; var heroD = player.PlayerHeroData; //Step #2 检查英雄类型属于当前玩家阵营 if (!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType.Giant, _actionId.GiantType, 0, out var info)) return false; if (info.GiantCivId != actionParams.PlayerData.PlayerCivId || info.GiantForceId != actionParams.PlayerData.PlayerForceId) return false; //Step #3 检查player是否拥有该英雄 if (!heroD.HasHero(_actionId.GiantType)) return false; //Step #4 如果是玩家,检查金钱是否够,决定扣款,TODO AI目前不扣款,后面要扣款 if (actionParams.PlayerData == actionParams.MapData.PlayerMap.SelfPlayerData) { var cost = heroD.GetHeroFinishTaskCost(_actionId.GiantType); if (cost > actionParams.MapData.PlayerMap.SelfPlayerData.PlayerWealth) return false; } return true; } } }