using System.Collections.Generic; using UnityEngine; using RuntimeData; using Logic.Action; using Logic.Config; using Logic.CrashSight; 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 TH1Renderer; namespace Logic { public class PlayerLogic : IPlayerLogic { private Main _main; public PlayerLogic(Main main) { _main = main; } public void UpdateWonder(MapData mapData, PlayerData player) { foreach (WonderTypeEnum wonder in System.Enum.GetValues(typeof(WonderTypeEnum))) { //part #1 如果是未开启的奇观,判断是否需要发出WonderStart提示 if (player.Wonder.GetWonderState(wonder) == WonderState.NO_HINT) { //step #1 确认是否拥有科技 bool checkTechTree = player.TechTree.CheckActionCan(new CommonActionId() { ActionType = CommonActionType.StartWonder, WonderType = wonder }); if (!checkTechTree) continue; //step #2 确认EYE POWER PARK的特殊条件 bool checkSpecial = !(wonder == WonderTypeEnum.EYE && !CheckOneTowerInSight(mapData, player)); if (wonder == WonderTypeEnum.POWER && player.TotalKill <= 0) checkSpecial = false; if (wonder == WonderTypeEnum.PARK && GetMaxCityLevel(mapData,player) <= 2) checkSpecial = false; if (!checkSpecial) continue; //step #3 设置奇观状态为已开启 player.Wonder.SetWonderState(wonder, WonderState.HAVE_HINT); //step #4 如果是player是真人玩家,发出界面通知事件 if (player != mapData.PlayerMap.SelfPlayerData) continue; var announcement = new ShowUIAnnounceMajorEvent { EventType = UIAnnounceMajorEventType.WonderStart,Param1 = (int)wonder }; EventManager.Publish(announcement); } //part #2 如果是已经wonderStart的奇观,判断是否需要发出WonderComplete提示 else if (player.Wonder.GetWonderState(wonder) == WonderState.HAVE_HINT) { //step #1 确认奇观有没有完成 bool checkWonderDone = wonder switch { WonderTypeEnum.PEACE => player.TurnNoAttack >= 5, WonderTypeEnum.KNOWLEDGE => player.TechTree.HasAllTech(), WonderTypeEnum.TRADE => GetConnectedCityCount(mapData, player) >= 5, WonderTypeEnum.WEALTH => player.PlayerWealth >= 100, WonderTypeEnum.EYE => CheckAllTowerInSight(mapData, player), WonderTypeEnum.POWER => player.TotalKill >= 10, WonderTypeEnum.PARK => GetMaxCityLevel(mapData, player) > 5, _ => false }; if (!checkWonderDone) continue; if (WonderTypeEnum.POWER == wonder) { Debug.Log(mapData.PlayerMap.SelfPlayerData.Wonder.GetWonderState(WonderTypeEnum.KNOWLEDGE)); } //step #2 设置状态 player.Wonder.SetWonderState(wonder, WonderState.FINISH_NOT_BUILD); //step #3 如果是player是真人玩家,发出界面通知事件 if (player != mapData.PlayerMap.SelfPlayerData) continue; var announcement = new ShowUIAnnounceMajorEvent { EventType = UIAnnounceMajorEventType.WonderEnd, Param1 = (int)wonder }; EventManager.Publish(announcement); } } } public void Update(MapData mapData) { if (mapData == null) return; //TODO 放到GameLogic //每帧判断每个玩家的奇观达成情况 foreach (var player in mapData.PlayerMap.PlayerDataList) { foreach (WonderTypeEnum wonder in System.Enum.GetValues(typeof(WonderTypeEnum))) { //part #1 如果是未开启的奇观,判断是否需要发出WonderStart提示 if (player.Wonder.GetWonderState(wonder) == WonderState.NO_HINT) { //step #1 确认是否拥有科技 bool checkTechTree = player.TechTree.CheckActionCan(new CommonActionId() { ActionType = CommonActionType.StartWonder, WonderType = wonder }); if (!checkTechTree) continue; //step #2 确认EYE POWER PARK的特殊条件 bool checkSpecial = !(wonder == WonderTypeEnum.EYE && !CheckOneTowerInSight(mapData, player)); if (wonder == WonderTypeEnum.POWER && player.TotalKill <= 0) checkSpecial = false; if (wonder == WonderTypeEnum.PARK && GetMaxCityLevel(mapData,player) <= 2) checkSpecial = false; if (!checkSpecial) continue; //step #3 设置奇观状态为已开启 player.Wonder.SetWonderState(wonder, WonderState.HAVE_HINT); //step #4 如果是player是真人玩家,发出界面通知事件 if (player != mapData.PlayerMap.SelfPlayerData) continue; var announcement = new ShowUIAnnounceMajorEvent { EventType = UIAnnounceMajorEventType.WonderStart,Param1 = (int)wonder }; EventManager.Publish(announcement); } //part #2 如果是已经wonderStart的奇观,判断是否需要发出WonderComplete提示 else if (player.Wonder.GetWonderState(wonder) == WonderState.HAVE_HINT) { //step #1 确认奇观有没有完成 bool checkWonderDone = wonder switch { WonderTypeEnum.PEACE => player.TurnNoAttack >= 5, WonderTypeEnum.KNOWLEDGE => player.TechTree.HasAllTech(), WonderTypeEnum.TRADE => GetConnectedCityCount(mapData, player) >= 5, WonderTypeEnum.WEALTH => player.PlayerWealth >= 100, WonderTypeEnum.EYE => CheckAllTowerInSight(mapData, player), WonderTypeEnum.POWER => player.TotalKill >= 10, WonderTypeEnum.PARK => GetMaxCityLevel(mapData, player) > 5, _ => false }; if (!checkWonderDone) continue; if (WonderTypeEnum.POWER == wonder) { Debug.Log(mapData.PlayerMap.SelfPlayerData.Wonder.GetWonderState(WonderTypeEnum.KNOWLEDGE)); } //step #2 设置状态 player.Wonder.SetWonderState(wonder, WonderState.FINISH_NOT_BUILD); //step #3 如果是player是真人玩家,发出界面通知事件 if (player != mapData.PlayerMap.SelfPlayerData) continue; var announcement = new ShowUIAnnounceMajorEvent { EventType = UIAnnounceMajorEventType.WonderEnd, Param1 = (int)wonder }; EventManager.Publish(announcement); } } } //Part #2 判断当前这一帧,正在行动的玩家,meetlist的更新情况 var curPlayer = mapData.CurPlayer; if (curPlayer == null) return; //遍历所有unit,有没有玩家新看到的unit foreach (var unit in mapData.UnitMap.UnitList) { if (!mapData.GetGridDataByUnitId(unit.Id, out var grid)) continue; if (!mapData.GetPlayerDataByUnitId(unit.Id, out var player1)) continue; if (curPlayer.Sight.CheckIsInSight(grid.Id) && !curPlayer.MeetPlayers.Contains(player1.Id)) AddMeetPlayer(mapData,curPlayer,player1); } //遍历所有city,有没有玩家新看到的city foreach (var city in mapData.CityMap.CityList) { if (!mapData.GetGridDataByCityId(city.Id, out var grid)) continue; if (!mapData.GetPlayerDataByCityId(city.Id, out var player1)) continue; if (curPlayer.Sight.CheckIsInSight(grid.Id) && !curPlayer.MeetPlayers.Contains(player1.Id)) AddMeetPlayer(mapData,curPlayer,player1); } //Part #3 判断当前有没有玩家出局 foreach (var player in mapData.PlayerMap.PlayerDataList) { if (player.DieMark && !player.Alive) { player.DieMark = false; var announcement = new ShowUIAnnounceMajorEvent { EventType = UIAnnounceMajorEventType.CivLose,Param1 = (int)player.Id}; EventManager.Publish(announcement); //SetCenterMessageShow(UICenterMessageID.ForcesFallen,player); } } //判断玩家的胜负情况 //var selfp = mapData.PlayerMap.SelfPlayerData; //if (mapData.GetCityCount(selfp.Id) == 0) //selfp.Alive = false; } // 回合开始 public void StartPlayerTurn(MapData map, uint playerId) { if (!map.PlayerMap.GetPlayerDataByPlayerID(playerId, out var player)) return; var actionId = new CommonActionId { ActionType = CommonActionType.TurnStart }; var action = new PlayerTurnStartAction(actionId); var param = new CommonActionParams(Main.MapData, playerData:player); param.RefreshParams(); action.CompleteExecute(param); if (map.Net.Mode == NetMode.Multi && map.Net.Players.ContainsValue(playerId)) return; if (map.PlayerMap.SelfPlayerData.Id == playerId) return; AIAddMoney(map, playerId); } // 回合结束 public void EndPlayerTurn(MapData map, uint playerId) { if (!map.PlayerMap.GetPlayerDataByPlayerID(playerId, out var player)) return; var actionId = new CommonActionId { ActionType = CommonActionType.TurnEnd }; var action = new PlayerTurnEndAction(actionId); var param = new CommonActionParams(Main.MapData, playerData:player); param.RefreshParams(); action.CompleteExecute(param); } // AI 发钱 public void AIAddMoney(MapData map, uint playerId) { if (!map.PlayerMap.GetPlayerDataByPlayerID(playerId, out var player)) return; var actionId = new CommonActionId { ActionType = CommonActionType.AIMoney }; var action = new AIMoneyAction(actionId); var param = new CommonActionParams(Main.MapData, playerData:player); param.RefreshParams(); action.CompleteExecute(param); } //更新pid下所有领土的所有格子的buildinglevel public void UpdateTerritoryAllBuildingLevel(MapData mapData, uint pid) { var ter = mapData.GetPlayerTerritoryGridIdSet(pid); //step #1 更新我国所有领土的特殊建筑 (除了学院和市场) foreach (var gid in ter) { //step #1 获得gid的resource if (!mapData.GridMap.GetGridDataByGid(gid, out var grid)) continue; if (grid.Resource == ResourceType.None) continue; //TODO 将来要对resource管理分类 if(grid.Resource is ResourceType.Sawmill or ResourceType.Windmill or ResourceType.Forge or ResourceType.Preserve or ResourceType.KaguyaFrenchYard or ResourceType.EgyptianIrrigation) Main.CityLogic.UpdateGridBuildingData(mapData, grid); } //Step #2 更新那我国所有领土的学院和市场(必须再Step#1 全部做完再做,这里要明确分先后) foreach (var gid in ter) { //step #1 获得gid的resource if (!mapData.GridMap.GetGridDataByGid(gid, out var grid)) continue; if (grid.Resource == ResourceType.None) continue; //TODO 将来要对resource管理分类 if(grid.Resource is ResourceType.Academy or ResourceType.Market ) Main.CityLogic.UpdateGridBuildingData(mapData, grid); } } // unit 占领了位于 grid 的村庄,返回一个CityData public CityData OccupyVillage(MapData mapData, UnitData unitData, GridData gridData) { // 先拿到小兵所属的玩家 if (!mapData.GetPlayerDataByUnitId(unitData.Id, out var playerData)) return null; //新建城市 var cityData = mapData.AddCityData(gridData.Id, playerData.Id); //转移小兵的编制 if (!mapData.GetCityDataByUnitId(unitData.Id, out var oldCityData)) { LogSystem.LogError("UnitHasNoCityData"); return cityData; } mapData.SetUnitIdToCityId(unitData.Id, cityData.Id); oldCityData.SetCityRenderer(mapData); cityData.SetCityRenderer(mapData); //更新小兵的状态(可能会有城防) unitData.Renderer(mapData)?.InstantUpdateUnit(true); //更新该国家的所有level建筑 UpdateTerritoryAllBuildingLevel(mapData,playerData.Id); //更新所有国家的联通情况 UpdateAllPlayerConnected(mapData); //更新特殊占领技能 if(playerData.GetSkill(SkillType.KaguyaFrenchNapoleonicCode,out var _)) Main.PlayerLogic.SetCityTerritoryGridSp(mapData,cityData,GridSpType.KaguyaGrid); return cityData; } // unit 占领了city public void OccupyCity(MapData mapData, UnitData unitData, CityData cityData) { var gridData = cityData.Grid(mapData); if (gridData == null) return; //Step #1 处理logic, 先拿到小兵所属的玩家 if (!mapData.GetPlayerDataByUnitId(unitData.Id, out var playerData)) return; if (!mapData.GetPlayerDataByCityId(cityData.Id, out var playerData2)) return; //记录oldplayer和newplayer var oldPid = playerData2.Id; var newPid = playerData.Id; bool lostEmbassy = Main.CityLogic.CheckCradleCapital(mapData, playerData2, cityData); // 修改城市和玩家的所属关系 if (!mapData.SetCityIdToPlayerId(cityData.Id, playerData.Id)) { LogSystem.LogError("占领失败!"); return; } //Step #2 播放grid的fog特效,关闭fire特效,更新城市的造型 gridData.Renderer(mapData)?.PlayVFX(new GridVFXParams(GridVFXType.Fog)); gridData.Renderer(mapData)?.SetUpdateGrid(); gridData.Renderer(mapData)?.SetUpdateCityBuilding(cityData.Level,cityData.Civ(mapData)); //Step #3 转移小兵的编制,要在处理完城市和玩家所属关系后才能转移小兵编制,不然出局的玩家清理本城市小兵的时候会出错 if (!mapData.GetCityDataByUnitId(unitData.Id, out var oldCityData)) { LogSystem.LogError("UnitHasNoCityData"); return; } mapData.SetUnitIdToCityId(unitData.Id, cityData.Id); oldCityData.SetCityRenderer(mapData); oldCityData.SetCityRenderer(Main.MapData); cityData.SetCityRenderer(mapData); //更新小兵的状态(可能会有城防) unitData.Renderer(mapData)?.InstantUpdateUnit(true); //Step #4 撤销所有国家在 player2 建立的大使馆 if (lostEmbassy) { foreach (var info in playerData2.DiplomacyData.Info) info.IsEmbassy = false; } //Step #5 处理占领城市的特效(所有领土会升起一面旗帜 HashSet gridList = new HashSet(); cityData.Territory.GetAllTerritoryArea(gridList); foreach (var gd in gridList) { if (mapData.GridMap.GetGridDataByGid(gd, out var gdd)) { //设置gdd格子的VFXrendermark var t = new GridVFXParams(GridVFXType.Flag); t.CivId = playerData.PlayerCivId; gdd.Renderer(mapData)?.PlayVFX(t); } } //Step #6 更新该城镇3范围内的所有单元格(包括可交互物体的glow以及边界的更新) if (!mapData.GetGridDataByCityId(cityData.Id, out var grid)) return; var gridList2 = mapData.GridMap.GetAroundGridData(3, 3, grid); foreach (var tg in gridList2) tg.Renderer(mapData)?.SetUpdateGrid(true); List list = new List(cityData.Territory.TerritoryArea); //更新player的视野 Main.PlayerLogic.UpdateSight(mapData, playerData, list); //Step #7 更新两个国家的所有levelbuilding情况,修正城市经验 UpdateTerritoryAllBuildingLevel(mapData,oldPid); UpdateTerritoryAllBuildingLevel(mapData,newPid); //Step #8 更新所有国家的联通情况,修正城市经验 UpdateAllPlayerConnected(mapData); //Step #9 更新特殊占领技能 if(playerData.GetSkill(SkillType.KaguyaFrenchNapoleonicCode,out var _)) Main.PlayerLogic.SetCityTerritoryGridSp(mapData,cityData,GridSpType.KaguyaGrid); else Main.PlayerLogic.ClearCityTerritoryGridSp(mapData,cityData,GridSpType.KaguyaGrid); } public int GetMapUnitTypeCount(MapData mapData, UnitType unitType, GiantType giantType) { int ret = 0; foreach (var unit in mapData.UnitMap.UnitList) { if ((unit.UnitType == unitType && unit.GiantType == giantType) || (unit.CarryUnitType == unitType && unit.CarryGiantType == giantType)) ret++; } return ret; } // 获取玩家在某个格子周围 1 单位的拥有某个资源且属于该玩家领土的grid的全列表 public List GetPlayerResourceNearbyList(MapData mapData, PlayerData playerData, GridData gridData, ResourceType resourceType) { var aroundGridList = new List(); var aroundGrid = mapData.GridMap.GetAroundGridDataSet(1, 1, gridData); //var territoryGidSet = mapData.GetPlayerTerritoryGridIdSet(playerData.Id); foreach (var grid in aroundGrid) { //如果不是玩家的领土 if(mapData.GetPlayerDataByTerritoryGridId(grid.Id, out var player) && player.Id != playerData.Id) continue; if (grid.Resource != resourceType) continue; aroundGridList.Add(grid); } return aroundGridList; } // 获取玩家在某个格子周围 1 单位的某个地形的列表 public List GetPlayerFeatureNearbyList(MapData mapData, PlayerData playerData, GridData gridData, TerrainFeature feature) { var aroundGridList = new List(); var aroundGrid = mapData.GridMap.GetAroundGridDataSet(1, 1, gridData); var territoryGidSet = mapData.GetPlayerTerritoryGridIdSet(playerData.Id); foreach (var grid in aroundGrid) { if (!territoryGidSet.Contains(grid.Id)) continue; if (grid.Feature != feature) continue; aroundGridList.Add(grid); } return aroundGridList; } //---------------------------------------- city相关操作------- // 获取firstMeet金钱数额 public int GetFirstMeetCoin(MapData map, PlayerData player) { return player.PlayerScore / 1000 * 2 + 3; } //获取player目前拥有城市的最高等级 public int GetMaxCityLevel(MapData map, PlayerData player) { int citylv = 2; foreach (var city in map.CityMap.CityList) if (map.GetPlayerDataByCityId(city.Id, out var p1) && p1 == player && city.Level > citylv) citylv = city.Level; return citylv; } //获取player目前和首都联通的城市数量 public int GetConnectedCityCount(MapData map, PlayerData player) { int c = 0; foreach (var city in map.CityMap.CityList) if (map.GetPlayerDataByCityId(city.Id, out var p2) && p2 == player && city.IsConnectedCapital) c++; return c; } //更新所有玩家的connected情况 public void UpdateAllPlayerConnected(MapData mapData) { foreach(var player in mapData.PlayerMap.PlayerDataList) UpdateCityConnect(mapData,player); } // 这里的数据缓存到 GridMap 里面去 TODO 这个方法读的不是很懂 public void UpdateCityConnect(MapData mapData, PlayerData playerData) { //step #1 初始化,将联通的城市存于Hashset中 if (playerData == null) return; if (!mapData.GetCapitalCityDataByPlayerId(playerData.Id, out var capitalCity)) return; var cityList = new List(); mapData.GetCityDataListByPlayerId(playerData.Id, cityList); var connectList = new HashSet(); //Step #2 如果玩家还有原始首都,计算联通情况,否则所有城市都是不联通 if (playerData.CradleCityId == capitalCity.Id) { //算法总述 //注意一些事实: //首先,只有同一个playerId的港口之间,才会通过[公海、同盟海域]计算一个5格内的bfs最短路,然后标记在格子上 //其次,每个player的上述每一对港口,之间都会计算最短路 然后同时显示在玩家的渲染中 //再次,每一个player在计算的时候,都会受到sight的影响,如果同盟的港口之间是联通的,但是我方没有视野,就是视为不联通 //于是,算法如下(如果更新某个playerId的首都联通情况) //先整理出所有可计算港口连通性的格子:视野内,公海+己方领土+盟军领土 //先清除所有公海+己方领土+盟军领土的海域(要去掉桥梁和港口)的waterroad标记 gridData.WaterRoadMark[playerId] = false //遍历每个港口,将港口5格内bfs辐射连通性,所有抵达其他港口的最短路,要做如下标记: //gridData.WaterRoadMark[playerId] = true // 然后更新所有这次的公海+己方领土+盟军领土的海域 //如果是港口桥梁 或者有任意一个waterroadMark[x] = true 那么gridData.Feature = road。这里主要是因为 你的标记即使置为false了,也有可能别人用公海建立了海陆,还是要渲染的 //否则置为那么gridData.Feature = none //#1,记录港口之间的两两最短路 //#1-1首先处理初始变量,获取playerId的所有city和grid var citySet = mapData.GetCityDataSetByPlayerId(playerData.Id); var gridSet = mapData.GetGridDataSetByPlayerId(playerData.Id); //获取所有视野内的grid,然后去除非盟友的有主海域,去除所有土地,这是所有港口可以计算最短路的格子,用来计算通路用的 var waterRoadGidSet = new HashSet(); foreach (var gid in playerData.Sight.SightGidSet) if (mapData.GridMap.GetGridDataByGid(gid, out var grid) && grid.Terrain != TerrainType.Land) { //如果友军或者盟军海域 if(mapData.CheckGridIdBelongPlayerIdUnion(gid, playerData.Id)) waterRoadGidSet.Add(gid); //如果是公海 if(!mapData.GetPlayerDataByTerritoryGridId(gid,out var _)) waterRoadGidSet.Add(gid); } //#1-2清空所有waterRoadGidSet中的waterroad标记(仅关于playerforceId的那个标记)(除了port和bridge) foreach (var gid in waterRoadGidSet) { if (!mapData.GridMap.GetGridDataByGid(gid, out var grid)) continue; if (grid.Terrain == TerrainType.Land || grid.Resource == ResourceType.Port || grid.Resource == ResourceType.Bridge) continue; if (playerData.PlayerForceId < grid.WaterRoadForceId.Length) grid.WaterRoadForceId[playerData.PlayerForceId] = false; } //#1-3每个己方领土内的港口进行floodfill 标记抵达其他港口的最短路 foreach (var portCandidate in gridSet) { if (portCandidate.Resource != ResourceType.Port) continue; //Debug.Log($"candidatePort is {portCandidate.Id}"); // 记录前驱节点 var prev = new Dictionary(); var dist = new Dictionary(); var visited = new HashSet(); // 初始港口格子 uint startId = portCandidate.Id; dist[startId] = 0; visited.Add(startId); // BFS 队列 Queue queue = new Queue(); queue.Enqueue(startId); // 计算从该港口出发能辐射的5个距离内的bfs情况 while (queue.Count > 0) { uint currentId = queue.Dequeue(); mapData.GridMap.GetGridDataByGid(currentId, out var curGrid); int currentDist = dist[currentId]; // 最长只扩展到距离为5的格子 if (currentDist >= 5) continue; // 获取相邻格子 var neighbors = mapData.GridMap.GetAroundGridDataSetByOrder(1, 1, curGrid); foreach (var neighbor in neighbors) { uint nextId = neighbor.Id; // 条件限制: // 1. 在roadGidSet里(可以用Id判断) // 2. 未访问 // 3. Terrain != Land if (!waterRoadGidSet.Contains(neighbor.Id)) continue; if (visited.Contains(nextId)) continue; if (neighbor.Terrain == TerrainType.Land) continue; // 合法蔓延 dist[nextId] = currentDist + 1; prev[nextId] = currentId; visited.Add(nextId); queue.Enqueue(nextId); } } //将所有能辐射到的其他port拎出来,然后将抵达对方的最短路进行waterroad标记 foreach (var targetPort in gridSet) { if (targetPort.Resource != ResourceType.Port) continue; if(playerData.PlayerForceId < targetPort.WaterRoadForceId.Length) targetPort.WaterRoadForceId[playerData.PlayerForceId] = true; //Debug.Log($"targetPort is {targetPort.Id}"); //如果两个port不互相可达 if (!dist.ContainsKey(targetPort.Id)) continue; //注意,这里用targetId > candidateId的方式,来规避港口a->b算过之后,再算一遍b->a的情况 if (targetPort.Id <= portCandidate.Id) continue; //Debug.Log($"Start Shortest Path !!!! From {targetPort.Id} to {portCandidate.Id}"); uint traceId = targetPort.Id; //避免死循环的保险 int safe = 0; while (traceId != portCandidate.Id && safe < 10) { //Debug.Log($"Path Node #{safe + 1} is {traceId}"); if (mapData.GridMap.GetGridDataByGid(traceId, out var traceGrid)) if(playerData.PlayerForceId < traceGrid.WaterRoadForceId.Length) traceGrid.WaterRoadForceId[playerData.PlayerForceId] = true; // 回溯前驱节点 traceId = prev[traceId]; safe++; } if(playerData.PlayerForceId < portCandidate.WaterRoadForceId.Length) portCandidate.WaterRoadForceId[playerData.PlayerForceId] = true; } } //#1-4 根据所有WaterMark 对所有可使用海域(公海 己方海域 盟军海域) 算一遍terrainFeature foreach (var gid in waterRoadGidSet) { bool isRoad = false; if (!mapData.GridMap.GetGridDataByGid(gid, out var grid)) continue; for (int i = 0; i < grid.WaterRoadForceId.Length; i++) if (grid.WaterRoadForceId[i]) { //Debug.Log($"grid{grid.Id} is road because forceid{i}"); isRoad = true; break; } //保险补一句,bridge和port一定是road if (grid.Resource == ResourceType.Bridge || grid.Resource == ResourceType.Port) isRoad = true; //如果road情况发生变化,做调整 if (isRoad != (grid.Feature == TerrainFeature.Road)) { grid.Feature = isRoad ? TerrainFeature.Road : TerrainFeature.None; grid.Renderer(mapData)?.SetUpdateGrid(true); var neighbors = mapData.GridMap.GetAroundGridDataSetByOrder(1, 1, grid); foreach (var nearbyGrid in neighbors) nearbyGrid.Renderer(mapData)?.SetUpdateGrid(true); } } //#1-5 从首都出发,进行floodfill,计算哪些城市可以被抵达。是否联通,只需要判断两个格子是否都具有road属性即可(不过有些文明要特殊判断) var cn = new HashSet(); //floodfill算一遍从首都出发的连通性 if (!mapData.GetCapitalCityDataByPlayerId(playerData.Id, out var capital)) return; if (!mapData.GetGridDataByCityId(capital.Id, out var capitalGrid)) return; cn.Add(capitalGrid.Id); Queue li = new Queue(); li.Enqueue(capitalGrid.Id); while (li.Count > 0) { var head = li.Dequeue(); if (!mapData.GridMap.GetGridDataByGid(head, out var headGrid)) continue; foreach (var aroundGrid in mapData.GridMap.GetAroundGridDataSet(1, 1, headGrid)) { //Step #1如果不是我方领土或者中立领土,不行 if (mapData.GetPlayerDataByTerritoryGridId(aroundGrid.Id, out var _) && !mapData.CheckGridIdBelongPlayerIdUnion(aroundGrid.Id, playerData.Id)) continue; //Step #2联通检测。这里要处理特殊情况 //Step #2-1 先处理kaguya 的联通判断bamboomove的情况 if (playerData.TechTree.CheckIfHasTechAtom(TechAtom.KaguyaFrenchBambooMove)) { if (aroundGrid.Feature != TerrainFeature.Road && aroundGrid.Vegetation != Vegetation.Trees) continue; } //Step #2-2 再处理其他常规的联通判断 else { if (aroundGrid.Feature != TerrainFeature.Road) { continue; } } if (cn.Contains(aroundGrid.Id))continue; cn.Add(aroundGrid.Id); li.Enqueue(aroundGrid.Id); } } // 最终确定哪些城市联通,加入hashset foreach (var city in cityList) { if (city.IsCapital) continue; if (!mapData.GetGridDataByCityId(city.Id, out var gridData))continue; if (!cn.Contains(gridData.Id)) continue; connectList.Add(city.Id); } } //Step3 处理城市的联通变化 foreach (var city in cityList) { //Step #1 先计算经验值的差值 int expDelta = 0; //Step #2 处理首都的经验差值 if (city.IsCapital) { //先减去这之前联通城市的数量(值非0说明之前是原始首都) expDelta = - city.ConnectExp; //如果之前有联通属性(说明是其他国家的小弟),要把这1点经验减去 if (city.IsConnectedCapital) expDelta--; //如果是原始首都,再加上这次联通的城市数量 if (playerData.CradleCityId == city.Id) expDelta += connectList.Count; } //Step #3 处理常规城市的经验差值 else { //减去之前的联通城市带来的经验(值非0说明之前是原始首都) expDelta -= city.ConnectExp; //减去之前联通的经验(撤销联通) expDelta -= city.IsConnectedCapital ? 1: 0; //加上现在联通的经验(重新联通) expDelta += connectList.TryGetValue(city.Id,out var _)? 1 : 0; } //Step #4 设置城市的新数值(只有capital=cradle才有联通的概念) city.IsConnectedCapital = connectList.TryGetValue(city.Id, out var _); city.ConnectExp = Main.CityLogic.CheckCradleCapital(mapData,playerData,city) ? connectList.Count : 0; //Step #5 更新city的deltaExp //Main.CityLogic.CityUpdateExp(mapData, city, expDelta); Main.CityLogic.GridGiveCityExp(mapData,playerData,city.Grid(mapData),city,expDelta); //Step #6 更新联通动画 if (expDelta > 0) { for (int i = 0; i < expDelta; i++) { var dataExpUp = FragmentDataFactory.Create(FragmentType.CityConnectExpUp, city.GridRenderer(mapData), city.CityInfoRenderer(mapData),city.Level,city.LevelExp); PresentationManager.EnqueueTask(new FragmentSequencerTask(FragmentFactory.Create(FragmentType.CityConnectExpUp,dataExpUp))); } } else { for (int i = 0; i > expDelta; i--) { var dataExpDown = FragmentDataFactory.Create(FragmentType.CityConnectExpDown, city.GridRenderer(mapData), city.CityInfoRenderer(mapData),city.Level,city.LevelExp); PresentationManager.EnqueueTask(new FragmentSequencerTask(FragmentFactory.Create(FragmentType.CityConnectExpDown,dataExpDown))); } } } } // 目前是给kaguya_french专用的,用来刷新一个城市领土所有的土地,变为kaguya tile public void SetCityTerritoryGridSp(MapData mapData, CityData cityData,GridSpType spType) { var gidList = cityData.Territory.TerritoryArea; foreach (var gid in gidList) { if(!mapData.GridMap.GetGridDataByGid(gid, out var grid))continue; if (grid.AddSpType(spType)) grid.Renderer(mapData)?.SetUpdateGrid(true); } } // 目前是给kaguya_french专用的,用来刷新一个城市领土所有的土地,清除kaguya 的特殊gridSpType public void ClearCityTerritoryGridSp(MapData mapData, CityData cityData,GridSpType spType) { var gidList = cityData.Territory.TerritoryArea; foreach (var gid in gidList) { if(!mapData.GridMap.GetGridDataByGid(gid, out var grid))continue; if (grid.RemoveSpType(spType)) grid.Renderer(mapData)?.SetUpdateGrid(true); } } //--------------------------------------------- Grid相关操作 ------------------------------------------- //这个函数希望接管所有SetGridResource的接口,但是暂时没有用上,因为目前所有操作结束会更新所有格子的buildinglevel public bool SetGridResource(MapData map, PlayerData player, GridData gridData, ResourceType resourceType) { return true; } //-----------------------------------------------------外交相关--------------------------------------------------- //计算p1和p2互相建立大使馆,给p1玩家多少钱 public int GetEmbassyCoin(MapData map,PlayerData p1, PlayerData p2) { if(!p1.Alive || !p2.Alive) return 0; p1.GetCountryDiplomacyInfo(p2.Id,out var dip); if (dip == null) return 0; //如果是战争 直接return 0 if (dip.DiplomacyState == DiplomacyState.War) return 0; //如果被敌人占领首都,直接return 0 if (Main.PlayerLogic.CheckEnemyOnCaptain(map, p2)) return 0; p2.GetCountryDiplomacyInfo(p1.Id,out var dip2); var coin = 0; if (dip.IsEmbassy) coin += 2; if (dip2.IsEmbassy) coin += 2; if (dip.DiplomacyState == DiplomacyState.League) coin *= 2; return coin; } public void TryAddMeetPlayer(MapData map, PlayerData p1, GridData p2) { var unit = p2.Unit(map); var city = p2.CityOnGrid(map); if(unit != null && unit.Player(map) != null && !p1.MeetPlayers.Contains(unit.Player(map).Id)) AddMeetPlayer(map,p1,unit.Player(map)); if(city != null && city.Player(map) != null && !p1.MeetPlayers.Contains(city.Player(map).Id)) AddMeetPlayer(map,p1,city.Player(map)); } public void AddMeetPlayer(MapData map, PlayerData p1, PlayerData p2) { //step #1 meetlist增加 p1.MeetPlayers.Add(p2.Id); //step #2 加钱 var coin = GetFirstMeetCoin(map,p2); p1.PlayerWealth += coin; //step #3 如果我方拥有大使馆科技,获得对方原始首都的视野 if (p1.TechTree.CheckIfHasTech(TechType.Diplomacy)) { if(map.GetGridIdByCityId(p2.CradleCityId, out var cradleGid)) UpdateSight(map,p1,new List{cradleGid}); } //step #4 更新外交关系和好感度 p1.RefreshDiplomacyState(map); p1.RefreshFeelingValue(map); //step #5 //如果是玩家,出发ui提示。加钱的操作要在ui提示关闭的时候由ui来出发 if (p1 == map.PlayerMap.SelfPlayerData) { var announcement = new ShowUIAnnounceMajorEvent { EventType = UIAnnounceMajorEventType.FirstMeet,Param1 = (int)p2.Id,Param2 = coin}; EventManager.Publish(announcement); //UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.MeetNewPlayer,player1,grid); } } //-------- 查询 --------// public bool HasRoadForUnit(MapData mapData, GridData gridDataA,GridData gridDataB ,UnitData unitData) { if (gridDataA.Resource == ResourceType.Port || gridDataB.Resource == ResourceType.Port) return false; mapData.GetPlayerIdByUnitId(unitData.Id, out var unitPlayerId); bool GridAHasPlayer = mapData.GetPlayerDataByTerritoryGridId(gridDataA.Id, out var gridAPlayerData); bool GridBHasPlayer = mapData.GetPlayerDataByTerritoryGridId(gridDataB.Id, out var gridBPlayerData); if (GridAHasPlayer && !mapData.SameUnion(gridAPlayerData.Id , unitPlayerId)) return false; if (GridBHasPlayer && !mapData.SameUnion(gridBPlayerData.Id , unitPlayerId)) return false; var OriginHasRoad = gridDataA.Feature == TerrainFeature.Road; var TargetHasRoad = gridDataB.Feature == TerrainFeature.Road; //这里要特殊处理永远亭的bamboo move if (unitData.GetSkill(SkillType.BAMBOOMOVE, out var _)) { if (gridDataA.Vegetation == Vegetation.Trees) OriginHasRoad = true; if (gridDataB.Vegetation == Vegetation.Trees) TargetHasRoad = true; } return OriginHasRoad && TargetHasRoad; } public void ExamineTreasure(MapData mapData, int pid, int uid, Vector2Int tpos) { } //player[pid]命令unit[uid]挖掘位于grid[tpos]的宝藏 public void Disband(MapData mapData, int pid, int uid) { } //判断player的首都是否被敌人占领 public bool CheckEnemyOnCaptain(MapData map,PlayerData player) { if (!map.GetCapitalCityDataByPlayerId(player.Id, out var city)) return false; if (!map.GetGridIdByCityId(city.Id, out var gid)) return false; if (!map.GetUnitDataByGid(gid, out var unit)) return false; if (!map.GetPlayerDataByUnitId(unit.Id, out var player2)) return false; if (player2.Id == player.Id) return false; return true; } //---------------------------------------------- tech相关操作 ------------------------------------ public void ResearchTech(MapData mapData, PlayerData playerData, TechType techType,int cost) { //如果已经有了这个科技,直接退出 if (playerData.TechTree.CheckIfHasTech(techType)) return; if (playerData.PlayerTechPoint >= cost) { playerData.PlayerTechPoint -= cost; } else { playerData.PlayerWealth -= ( cost - playerData.PlayerTechPoint); playerData.PlayerTechPoint = 0; } playerData.TechTree.LearnTech(techType); //diplomacy科技特殊处理外交情况 if (techType == TechType.Diplomacy) UpdateDiplomacySight(mapData, playerData); foreach (var girdData in mapData.GridMap.GridList) if(mapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(girdData.Id)) girdData.Renderer(mapData)?.SetUpdateGrid(true); //竹林驿站科技特殊处理城市联通情况 if (techType == TechType.KaguyaRoad) Main.PlayerLogic.UpdateAllPlayerConnected(mapData); //TODO 迭代一个 action 和techtree的中间节点 techAtom 正在进行中 var techInfo = Table.Instance.TechDataAssets.GetTechInfo(techType); foreach(var action in techInfo.techActions) if (action.ActionType == CommonActionType.UnitSkill) { foreach(var unit in mapData.UnitMap.UnitList) if (mapData.GetPlayerDataByUnitId(unit.Id, out var player1) && player1 == playerData) { unit.AddSkill(action.SkillType); if(unit.GetSkill(action.SkillType,out var skill))skill.OnSkillAdd(unit,mapData); unit.Renderer(mapData)?.InstantUpdateUnit(true); } } //9月最新版方案,techAtom引入,根据techAtom来决定这次要不要给unit加skill foreach (var techAtom in techInfo.TechAtomList) { if (!Table.Instance.TechDataAssets.GetTechAtomInfo(techAtom, out var atomInfo)) continue; if (!atomInfo.IsAddSkill) continue; //是否给全员增加,还是有条件增加 bool forAll = atomInfo.AddSkillCondition.Count == 0; var condition = new HashSet(atomInfo.AddSkillCondition); foreach (var unit in mapData.UnitMap.UnitList) { if (!mapData.CheckUnitIdBelongPlayerId(unit.Id, playerData.Id)) continue; if (!forAll && !condition.Contains(unit.UnitFullType)) continue; unit.AddSkill(atomInfo.AddSkillType); if(unit.GetSkill(atomInfo.AddSkillType,out var skill))skill.OnSkillAdd(unit,mapData); } } } //player[pid]学习了tid科技 //-------基础操作------- public void UpdatePlayerStarsPerTurn(MapData mapData, int pid) { } //playerData点击了EndTurn public void EndThisTurn(MapData mapData, PlayerData playerData) { if(playerData.Id == mapData.PlayerMap.SelfPlayerId) MapRenderer.Instance.BubbleManager.TurnEndSetBubble(mapData,playerData); playerData.TurnNoAttack++; } public int GetPlayerTechPointPerTurn(MapData mapData, uint playerId) { int ret = 0; foreach(var cityData in mapData.CityMap.CityList) if (mapData.CityToPlayerDict[cityData.Id] == playerId) ret += Main.CityLogic.GetCityTechPointPerTurn(mapData,cityData); return ret; } public int GetPlayerStarsPerTurn(MapData mapData, uint playerId) { int ret = 0; foreach(var cityData in mapData.CityMap.CityList) if (mapData.CityToPlayerDict[cityData.Id] == playerId) ret += Main.CityLogic.GetCityStarsPerTurn(mapData,cityData); if (!mapData.PlayerMap.GetPlayerDataByPlayerID(playerId, out var player)) { LogSystem.LogError("PlayerLogic Get PlayerStarsPerTurn can't find player by playerId"); return ret; } //产业科技带来的techpoint 转化为金币的能力 if (player.TechTree.CheckIfHasTech(TechType.Philosophy)) ret += GetPlayerTechPointPerTurn(mapData, playerId) / 2; //计算外交收入 foreach (var t in player.MeetPlayers) { if (!mapData.PlayerMap.GetPlayerDataByPlayerID(t, out var tplayer)) continue; if (!tplayer.Alive) continue; ret += GetEmbassyCoin(mapData,player, tplayer); } return ret; } //进入回合结算 #ono #nextturn #start #startturn public void StartNextTurn(MapData mapData, PlayerData playerData) { if (mapData != Main.MapData) { LogSystem.LogError("PlayerLogic StartNextTurn can't start next turn,mapData is not Real MAPDATA !!!"); return; } //处理游戏Bubble的模块,仅针对玩家 if (playerData.Id == mapData.PlayerMap.SelfPlayerId && ConfigManager.Instance.Config.ShowReminder) { MapRenderer.Instance.BubbleManager.TurnStartSetBubble(mapData,playerData); //如果不是第0回合,要显示回合开始提示 if(playerData.Turn != 0) UIManager.Instance.TopBarUI.SetShowTurnHint((int)playerData.Turn); } //加钱的模块 //如果是0回合不用放动画 不用加钱 ,直接return if (playerData.Turn != 0) { //暂时在这里触发金币动画。实际上不应该的,TODO 迭代这里的动画触发逻辑 //增加科技点 playerData.PlayerTechPoint += GetPlayerTechPointPerTurn(mapData, playerData.Id); //增加英雄exp var allGrid = mapData.GetPlayerTerritoryGridIdSet(playerData.Id); foreach (var gid in allGrid) { if (!mapData.GridMap.GetGridDataByGid(gid, out var grid)) { LogSystem.LogError("Can't Find grid by gid in PlayerLogic StartNextTurn"); continue; } if (!Table.Instance.GridAndResourceDataAssets.GetResourceInfo(grid.Resource, out var info)) { LogSystem.LogError("Can't Find Resource Info for Resource Type in PlayerLogic StartNextTurn"); continue; } if(info.ChessType != ChessType.None) { uint x = (uint)info.ChessType; playerData.giantExp[x] += grid.buildingLevel; //Debug.Log(playerData.giantExp[x] + " + " + grid.buildingLevel); } } //如果不是selfplayer 不用放动画 if (playerData.Id != mapData.PlayerMap.SelfPlayerData.Id) { playerData.PlayerWealth += GetPlayerStarsPerTurn(mapData, playerData.Id); //增加所有神庙带来的英雄exp return; } else { //TODO 后面要改成追赶动画 //如果有产业科技,增加科技点转化的金币 if (playerData.TechTree.CheckIfHasTech(TechType.Philosophy)) playerData.PlayerWealth += GetPlayerTechPointPerTurn(mapData, playerData.Id) / 2; mapData.GetCapitalCityDataByPlayerId(playerData.Id, out var captain); //否则,一边播放动画,一边1块钱1块钱的增加wealth foreach (var city in mapData.CityMap.CityList) { if (!mapData.GetPlayerDataByCityId(city.Id, out var tmpPlayer)) continue; //要么是我方城市,要么是对方的原始首都 if (tmpPlayer.Id != playerData.Id && !Main.CityLogic.CheckCradleCapital(mapData,tmpPlayer,city))continue; if (!mapData.GetGridDataByCityId(city.Id,out var grid)) continue; var startPos = Table.Instance.GridToWorld(grid); var money = 0; if (tmpPlayer.Id == playerData.Id) money = Main.CityLogic.GetCityStarsPerTurn(mapData, city); else money = GetEmbassyCoin(mapData, playerData, tmpPlayer); if(money <= 0)continue; MapRenderer.Instance.ProjectileManager.CreateCoinProjectile(startPos,money); int k = 0; while (k < money) { Timer.Instance.TimerRegister(this, () => { playerData.PlayerWealth += 1; },Table.Instance.AnimDataAssets.ProjectileCoinMoveTime + k * 0.05f,"PlayerLogic_StartNextTurn"); k++; } } } } //处理收到的外交请求,必须是真人玩家 if (playerData.Id == mapData.PlayerMap.SelfPlayerId) { foreach (var player2Id in playerData.MeetPlayers) if(mapData.PlayerMap.GetPlayerDataByPlayerID(player2Id, out var player2)) { if(player2.Id == playerData.Id)continue; if (!player2.Alive) continue; playerData.GetCountryDiplomacyInfo(player2.Id, out var dipInfo); //找到一个联盟请求,弹出ui窗口 if (dipInfo.IsLeagueRequest) { EventManager.Publish(new ShowUIInteractionDiplomacyOfferAlly(){PlayerId = player2.Id}); } } } } //-------------------------------- 视野相关 --------------------------------------- //查询视野 public bool CheckOneTowerInSight(MapData mapData, PlayerData player) { return mapData.GridMap.GetGridDataByPos(0, 0, out var g1) && player.Sight.CheckIsInSight(g1.Id) || mapData.GridMap.GetGridDataByPos(0, (int)mapData.MapConfig.Height - 1, out var g2) && player.Sight.CheckIsInSight(g2.Id) || mapData.GridMap.GetGridDataByPos((int)mapData.MapConfig.Width - 1, 0, out var g3) && player.Sight.CheckIsInSight(g3.Id) || mapData.GridMap.GetGridDataByPos((int)mapData.MapConfig.Width - 1, (int)mapData.MapConfig.Height - 1, out var g4) && player.Sight.CheckIsInSight(g4.Id); } public bool CheckAllTowerInSight(MapData mapData, PlayerData player) { return mapData.GridMap.GetGridDataByPos(0, 0, out var g1) && player.Sight.CheckIsInSight(g1.Id) && mapData.GridMap.GetGridDataByPos(0, (int)mapData.MapConfig.Height - 1, out var g2) && player.Sight.CheckIsInSight(g2.Id) && mapData.GridMap.GetGridDataByPos((int)mapData.MapConfig.Width - 1, 0, out var g3) && player.Sight.CheckIsInSight(g3.Id) && mapData.GridMap.GetGridDataByPos((int)mapData.MapConfig.Width - 1, (int)mapData.MapConfig.Height - 1, out var g4) && player.Sight.CheckIsInSight(g4.Id); } //TODO 目前UpdateSight在MapRenderer初始化之前就使用了。要处理 // 更新视野 public int UpdateSight(MapData mapData,PlayerData playerData, List gidList,float dur = 0.05f) { var count = 0; foreach (var id in gidList) { if (!playerData.Sight.SightGidSet.Add(id)) continue; count++; if (!mapData.GridMap.GetGridDataByGid(id, out var gridData)) continue; if (!mapData.GetCapitalCityDataByPlayerId(playerData.Id, out var city)) continue; //如果是真人玩家,加入地块被新显示的播放队列 if (Main.MapData == mapData && playerData.IsSelfPlayer()) { var data = FragmentDataFactory.Create(FragmentType.GridUpdate, GridUpdateType.FogDisappear, gridData.Renderer(mapData),dur); PresentationManager.EnqueueTask(new FragmentSequencerTask(FragmentFactory.Create(FragmentType.GridUpdate, data))); } //尝试判断gridData有没有带来新的meetplayerList TryAddMeetPlayer(mapData, playerData, gridData); //处理发现tower的情况 if (gridData.Resource == ResourceType.Tower) { Main.CityLogic.GridGiveCityExp(mapData,playerData,gridData,city,1); //更新奇观情况,可能弹出奇观通知 UpdateWonder(mapData,playerData); } } //更新视野后,要更新联通情况 Main.PlayerLogic.UpdateCityConnect(mapData,playerData); return count; } public void UpdateSightByRadius(MapData mapData, PlayerData playerData, GridData gridData, int radius) { UpdateSight(mapData,playerData,mapData.GridMap.GetAroundGridIdList(radius,gridData,true)); } public void DebugGetAllSight(MapData mapData, PlayerData playerData) { var gidList = new List(); foreach(var gridData in mapData.GridMap.GridList) gidList.Add(gridData.Id); UpdateSight(mapData,playerData,gidList); } //如果我方拥有大使馆科技,更新所有meetlist的cradlecity位置 public void UpdateDiplomacySight(MapData map, PlayerData player) { foreach(var t in player.MeetPlayers) if (t != player.Id) { if(!map.PlayerMap.GetPlayerDataByPlayerID(t, out var player2))continue; if(!map.GetGridDataByCityId(player2.CradleCityId, out var grid))continue; UpdateSight(map,player,new List{grid.Id}); } } //返回某个玩家学习某个科技的真实价格 public int GetRealCost(MapData mapData,PlayerData playerData,TechType techType) { var techInfo = Table.Instance.TechDataAssets.GetTechInfo(techType); return techInfo.CostLevel * mapData.GetCityCount(playerData.Id) + 4; } //更新一个mapData里所有Player的Score public void CalcAllPlayerScore(MapData mapData) { if (mapData == null) return; // 先清空 foreach (var player in mapData.PlayerMap.PlayerDataList) player.PlayerScore = 0; //记录格子得分(视野) foreach (var player in mapData.PlayerMap.PlayerDataList) player.PlayerScore += player.Sight.SightGidSet.Count * 5; // 记录格子得分(领土) foreach (var city in mapData.CityMap.CityList) { if (!mapData.GetPlayerDataByCityId(city.Id, out var player)) continue; player.PlayerScore += city.Territory.TerritoryArea.Count * 20; player.PlayerScore += city.Level * 50 + city.LevelExp * 5; foreach(var gid in city.Territory.TerritoryArea) if (mapData.GridMap.GetGridDataByGid(gid, out var grid)) { if (grid.Resource is ResourceType.Temple or ResourceType.ForestTemple or ResourceType.MountainTemple or ResourceType.WaterTemple) player.PlayerScore += 50 + 50 * grid.buildingLevel; } } // 小兵得分(Cost*5) foreach (var unit in mapData.UnitMap.UnitList) { if (!unit.Alive) continue; if (!mapData.GetPlayerDataByUnitId(unit.Id, out var player)) continue; if (!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(unit.UnitType, unit.GiantType,unit.UnitLevel, out var info)) continue; player.PlayerScore += info.Cost * 5; } // 奇观得分(每完成一个+400) foreach (var player in mapData.PlayerMap.PlayerDataList) { foreach (var kv in player.Wonder.WonderInfoDict) { if (kv.Value == WonderState.FINISH_BUILD) player.PlayerScore += 400; } // 科技得分(100 * 等级) player.PlayerScore += player.TechTree.GetScore(); } } // 设置外交关系 public void SetDiplomacyLeague(MapData map, PlayerData originPlayer, PlayerData targetPlayer, DiplomacyState state) { originPlayer.GetCountryDiplomacyInfo(targetPlayer.Id, out var player1ToPlayer2); targetPlayer.GetCountryDiplomacyInfo(originPlayer.Id, out var player2ToPlayer1); player1ToPlayer2.DiplomacyState = state; player2ToPlayer1.DiplomacyState = state; if (state == DiplomacyState.War) { if (player1ToPlayer2.IsEmbassy) { player1ToPlayer2.IsEmbassy = false; //更新player2的首都cityinfo if (map.GetCapitalCityDataByPlayerId(targetPlayer.Id, out var city2)) city2.SetCityRenderer(map); //如果有一方是真人玩家,要发布UI通知 if (originPlayer.Id == Main.MapData.PlayerMap.SelfPlayerId || targetPlayer.Id == Main.MapData.PlayerMap.SelfPlayerId && map == Main.MapData) { var announce = new ShowUIAnnounceDiplomacy(){PlayerActionType = PlayerActionType.Embassy,PlayerId = originPlayer.Id,TargetPlayerId = targetPlayer.Id}; EventManager.Publish(announce); } } if (player2ToPlayer1.IsEmbassy) { player2ToPlayer1.IsEmbassy = false; //更新player1的首都cityinfo if (map.GetCapitalCityDataByPlayerId(originPlayer.Id, out var city1)) city1.SetCityRenderer(map); //如果有一方是真人玩家,要发布UI通知 if (originPlayer.Id == Main.MapData.PlayerMap.SelfPlayerId || targetPlayer.Id == Main.MapData.PlayerMap.SelfPlayerId && map == Main.MapData) { var announce = new ShowUIAnnounceDiplomacy(){PlayerActionType = PlayerActionType.Embassy,PlayerId = targetPlayer.Id,TargetPlayerId = originPlayer.Id}; EventManager.Publish(announce); } } } } } }