1696 lines
81 KiB
C#
1696 lines
81 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using RuntimeData;
|
||
using Logic.Action;
|
||
using Logic.Audio;
|
||
using Logic.Config;
|
||
using Logic.CrashSight;
|
||
using Logic.Pool;
|
||
using Logic.Skill;
|
||
using TH1_Anim;
|
||
using TH1_Anim.Fragments;
|
||
using TH1_Core.Events;
|
||
using TH1_Core.Managers;
|
||
using TH1_Logic.Action;
|
||
using TH1_Logic.Collect;
|
||
using TH1_Logic.Core;
|
||
using TH1_Presentation.Sequencer.Task;
|
||
using TH1Renderer;
|
||
|
||
|
||
namespace Logic
|
||
{
|
||
public class PlayerLogic : IPlayerLogic
|
||
{
|
||
private Main _main;
|
||
// 缓存枚举值,只在类加载时获取一次
|
||
private static readonly WonderTypeEnum[] _cachedWonderTypes =
|
||
(WonderTypeEnum[])System.Enum.GetValues(typeof(WonderTypeEnum));
|
||
|
||
// 复用的临时集合
|
||
private HashSet<uint> _tmpTerritoryBuf;
|
||
private List<GridData> _tmpAroundBuf;
|
||
|
||
public PlayerLogic(Main main)
|
||
{
|
||
_main = main;
|
||
}
|
||
|
||
public void UpdateWonder(MapData mapData, PlayerData player,WonderTypeEnum specificWonder = WonderTypeEnum.None)
|
||
{
|
||
bool isMainSelfPlayer = mapData == Main.MapData && player == mapData.PlayerMap.SelfPlayerData;
|
||
int cachedMaxCityLevel = -1;
|
||
int cachedConnectedCityCount = -1;
|
||
bool cachedHasAllTech = false;
|
||
bool hasCachedHasAllTech = false;
|
||
bool cachedOneTowerInSight = false;
|
||
bool hasCachedOneTowerInSight = false;
|
||
bool cachedAllTowerInSight = false;
|
||
bool hasCachedAllTowerInSight = false;
|
||
|
||
foreach (WonderTypeEnum wonder in _cachedWonderTypes)
|
||
{
|
||
//如果指定了特定奇观,那么只判断对应的奇观
|
||
if (specificWonder != WonderTypeEnum.None && wonder != specificWonder) continue;
|
||
if (wonder == WonderTypeEnum.None) continue;
|
||
|
||
var wonderState = player.Wonder.GetWonderState(wonder);
|
||
|
||
//part #1 如果是未开启的奇观,判断是否需要发出WonderStart提示
|
||
if (wonderState == WonderState.NO_HINT)
|
||
{
|
||
//step #1 确认是否拥有科技
|
||
if (!TryGetStartWonderTechAtom(wonder, out var startWonderTechAtom)) continue;
|
||
if (!player.TechTree.CheckIfHasTechAtom(startWonderTechAtom)) continue;
|
||
|
||
//step #2 确认EYE POWER PARK的特殊条件
|
||
bool checkSpecial = true;
|
||
switch (wonder)
|
||
{
|
||
case WonderTypeEnum.EYE:
|
||
if (!hasCachedOneTowerInSight)
|
||
{
|
||
cachedOneTowerInSight = CheckOneTowerInSight(mapData, player);
|
||
hasCachedOneTowerInSight = true;
|
||
}
|
||
checkSpecial = cachedOneTowerInSight;
|
||
break;
|
||
case WonderTypeEnum.POWER:
|
||
checkSpecial = player.TotalKill > 0;
|
||
break;
|
||
case WonderTypeEnum.PARK:
|
||
if (cachedMaxCityLevel < 0)
|
||
{
|
||
cachedMaxCityLevel = GetMaxCityLevel(mapData, player);
|
||
}
|
||
checkSpecial = cachedMaxCityLevel > 2;
|
||
break;
|
||
}
|
||
if (!checkSpecial) continue;
|
||
|
||
//step #3 设置奇观状态为已开启
|
||
|
||
player.Wonder.SetWonderState(wonder, WonderState.HAVE_HINT);
|
||
wonderState = WonderState.HAVE_HINT;
|
||
//如果是和平奇怪,还要把技术调整为0
|
||
if (wonder == WonderTypeEnum.PEACE)
|
||
player.TurnNoAttack = 0;
|
||
|
||
//step #4 如果是player是真人玩家,发出界面通知事件
|
||
if (isMainSelfPlayer)
|
||
{
|
||
var announcement = new ShowUIAnnounceMajorEvent
|
||
{
|
||
EventType = UIAnnounceMajorEventType.WonderStart,
|
||
Param1 = (int)wonder
|
||
};
|
||
EventManager.Publish(announcement);
|
||
}
|
||
|
||
}
|
||
//part #2 如果是已经wonderStart的奇观,判断是否需要发出WonderComplete提示
|
||
if (wonderState == WonderState.HAVE_HINT)
|
||
{
|
||
//step #1 确认奇观有没有完成
|
||
bool checkWonderDone;
|
||
switch (wonder)
|
||
{
|
||
case WonderTypeEnum.PEACE:
|
||
checkWonderDone = player.TurnNoAttack >= 5;
|
||
break;
|
||
case WonderTypeEnum.KNOWLEDGE:
|
||
if (!hasCachedHasAllTech)
|
||
{
|
||
cachedHasAllTech = player.TechTree.HasAllTech(player);
|
||
hasCachedHasAllTech = true;
|
||
}
|
||
checkWonderDone = cachedHasAllTech;
|
||
break;
|
||
case WonderTypeEnum.TRADE:
|
||
if (cachedConnectedCityCount < 0)
|
||
{
|
||
cachedConnectedCityCount = GetConnectedCityCount(mapData, player);
|
||
}
|
||
checkWonderDone = cachedConnectedCityCount >= 5;
|
||
break;
|
||
case WonderTypeEnum.WEALTH:
|
||
checkWonderDone = player.PlayerCoin >= 100;
|
||
break;
|
||
case WonderTypeEnum.EYE:
|
||
if (!hasCachedAllTowerInSight)
|
||
{
|
||
cachedAllTowerInSight = CheckAllTowerInSight(mapData, player);
|
||
hasCachedAllTowerInSight = true;
|
||
}
|
||
checkWonderDone = cachedAllTowerInSight;
|
||
break;
|
||
case WonderTypeEnum.POWER:
|
||
checkWonderDone = player.TotalKill >= 10;
|
||
break;
|
||
case WonderTypeEnum.PARK:
|
||
if (cachedMaxCityLevel < 0)
|
||
{
|
||
cachedMaxCityLevel = GetMaxCityLevel(mapData, player);
|
||
}
|
||
checkWonderDone = cachedMaxCityLevel > 5;
|
||
break;
|
||
default:
|
||
checkWonderDone = false;
|
||
break;
|
||
}
|
||
if (!checkWonderDone) continue;
|
||
//step #2 设置状态
|
||
player.Wonder.SetWonderState(wonder, WonderState.FINISH_NOT_BUILD);
|
||
|
||
//step #3 如果是player是真人玩家,发出界面通知事件
|
||
if (isMainSelfPlayer)
|
||
{
|
||
var announcement = new ShowUIAnnounceMajorEvent
|
||
{
|
||
EventType = UIAnnounceMajorEventType.WonderEnd,
|
||
Param1 = (int)wonder
|
||
};
|
||
EventManager.Publish(announcement);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private static bool TryGetStartWonderTechAtom(WonderTypeEnum wonder, out TechAtom techAtom)
|
||
{
|
||
switch (wonder)
|
||
{
|
||
case WonderTypeEnum.PEACE:
|
||
techAtom = TechAtom.StartWonderPEACE;
|
||
return true;
|
||
case WonderTypeEnum.KNOWLEDGE:
|
||
techAtom = TechAtom.StartWonderKNOWLEDGE;
|
||
return true;
|
||
case WonderTypeEnum.TRADE:
|
||
techAtom = TechAtom.StartWonderTRADE;
|
||
return true;
|
||
case WonderTypeEnum.WEALTH:
|
||
techAtom = TechAtom.StartWonderWEALTH;
|
||
return true;
|
||
case WonderTypeEnum.POWER:
|
||
techAtom = TechAtom.StartWonderPOWER;
|
||
return true;
|
||
case WonderTypeEnum.PARK:
|
||
techAtom = TechAtom.StartWonderPARK;
|
||
return true;
|
||
case WonderTypeEnum.EYE:
|
||
techAtom = TechAtom.StartWonderEYE;
|
||
return true;
|
||
default:
|
||
techAtom = TechAtom.None;
|
||
return false;
|
||
}
|
||
}
|
||
|
||
public void Update(MapData mapData)
|
||
{
|
||
if (mapData == null)
|
||
return;
|
||
|
||
//TODO 放到GameLogic
|
||
//每帧判断每个玩家的奇观达成情况
|
||
foreach (var player in mapData.PlayerMap.PlayerDataList)
|
||
{
|
||
//单次调用内即可处理同一帧开启+完成奇观
|
||
UpdateWonder(mapData, player);
|
||
}
|
||
|
||
|
||
//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.IsSurvival)
|
||
{
|
||
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);
|
||
//action.ExecuteWithoutFullActionPeriod(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);
|
||
//action.ExecuteWithoutFullActionPeriod(param);
|
||
}
|
||
|
||
// 投降
|
||
public void Surrender(MapData map, uint playerId)
|
||
{
|
||
if (!map.PlayerMap.GetPlayerDataByPlayerID(playerId, out var player)) return;
|
||
var actionId = new CommonActionId { ActionType = CommonActionType.PlayerSurrender };
|
||
var action = ActionLogicFactory.GetActionLogic(actionId);
|
||
var param = new CommonActionParams(Main.MapData, playerData:player);
|
||
param.RefreshParams();
|
||
if (!action.CheckCan(param)) return;
|
||
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.AIParamControl , AIParamType = AIParamControlType.AIMoney};
|
||
var action = new AIParamControlAction(actionId);
|
||
var param = new CommonActionParams(Main.MapData, playerData:player);
|
||
param.RefreshParams();
|
||
action.CompleteExecute(param);
|
||
//action.ExecuteWithoutFullActionPeriod(param);
|
||
}
|
||
|
||
//更新pid下所有领土的所有格子的buildinglevel
|
||
public void UpdateTerritoryAllBuildingLevel(MapData mapData, uint pid)
|
||
{
|
||
var ter = mapData.GetPlayerTerritoryGridIdSet(pid);
|
||
mapData.PlayerMap.GetPlayerDataByPlayerID(pid, out var player);
|
||
//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_LogicView(mapData, grid);
|
||
//Main.CityLogic.UpdateGrid_ViewOnly(mapData,grid);
|
||
|
||
if (player != null)
|
||
{
|
||
foreach (var item in player.MomentData.Items)
|
||
{
|
||
item.OnNewResourceGet(mapData, player, grid.Resource, grid.buildingLevel);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//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_LogicView(mapData, grid);
|
||
//Main.CityLogic.UpdateGrid_ViewOnly(mapData,grid);
|
||
if (player != null)
|
||
{
|
||
foreach (var item in player.MomentData.Items)
|
||
{
|
||
item.OnNewResourceGet(mapData, player, grid.Resource, grid.buildingLevel);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// unit 占领了位于 grid 的村庄,返回一个CityData
|
||
public CityData OccupyVillage_LogicOnly(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.TechTree.CheckIfHasTechAtom(TechAtom.KaguyaFrenchNapoleonicCode))
|
||
Main.PlayerLogic.SetCityTerritoryGridSp(mapData,cityData,GridSpType.KaguyaGrid);
|
||
|
||
return cityData;
|
||
}
|
||
|
||
// unit 占领了city
|
||
public void OccupyCity_LogicView(MapData mapData, UnitData unitData, CityData cityData)
|
||
{
|
||
var gridData = cityData.Grid(mapData);
|
||
if (gridData == null) return;
|
||
|
||
bool momentBeOccupied = false;
|
||
bool momentBeOccupiedCaptain = false;
|
||
bool momentOccupyLv5 = false;
|
||
bool momentOccupyLv6 = false;
|
||
bool momentOccupyCaptain = false;
|
||
bool momentOccupyOurCaptain = false;
|
||
bool momentOccupyOurCity = false;
|
||
|
||
//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;
|
||
if (mapData == Main.MapData && oldPid == mapData.PlayerMap.SelfPlayerId)
|
||
{
|
||
momentBeOccupied = true;
|
||
if(playerData2.CradleCityId == cityData.Id)
|
||
momentBeOccupiedCaptain = true;
|
||
}
|
||
|
||
if (mapData == Main.MapData && newPid == mapData.PlayerMap.SelfPlayerId)
|
||
{
|
||
if(cityData.Level >= 6)
|
||
momentOccupyLv6 = true;
|
||
else
|
||
momentOccupyLv5 = true;
|
||
if(playerData2.CradleCityId == cityData.Id)
|
||
momentOccupyCaptain = true;
|
||
if(playerData.PlayerNamerData.CheckIsCityNameSelfBuild(cityData.Name))
|
||
momentOccupyOurCity = true;
|
||
if (playerData.CradleCityId == cityData.Id)
|
||
momentOccupyOurCaptain = true;
|
||
}
|
||
|
||
|
||
bool lostEmbassy = Main.CityLogic.CheckCradleCapital(mapData, playerData2, cityData);
|
||
// 修改城市和玩家的所属关系
|
||
if (!mapData.SetCityIdToPlayerId(cityData.Id, playerData.Id))
|
||
{
|
||
LogSystem.LogError("占领失败!");
|
||
return;
|
||
}
|
||
|
||
//Step #3 播放grid的fog特效,关闭fire特效,更新城市的造型,
|
||
gridData.Renderer(mapData)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Fog));
|
||
gridData.Renderer(mapData)?.InstantUpdateGrid();
|
||
|
||
gridData.Renderer(mapData)?.InstantUpdateCityBuilding(cityData.Level,cityData.Civ(mapData));
|
||
|
||
//Step #3.5 如果玩家有视野,播放音效
|
||
if(gridData.InMainSight())
|
||
AudioManager.Instance.PlayAudio("SFX/UNIT_capture");
|
||
|
||
|
||
//Step #4 转移小兵的编制,要在处理完城市和玩家所属关系后才能转移小兵编制,不然出局的玩家清理本城市小兵的时候会出错
|
||
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);
|
||
//更新城市的cityinfo
|
||
//gridData.CityOnGrid(mapData)?.CityInfoRenderer(mapData)?.InstantUpdateCityInfo();
|
||
|
||
//Step #5 撤销所有国家在 player2 建立的大使馆
|
||
if (lostEmbassy)
|
||
{
|
||
foreach (var info in playerData2.DiplomacyData.Info) info.IsEmbassy = false;
|
||
}
|
||
|
||
|
||
//Step #6 处理占领城市的特效(所有领土会升起一面旗帜
|
||
using var pooledGridList = THCollectionPool.GetHashSetHandle<uint>(out var gridList);
|
||
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)?.PlayVFXInSight(t);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
//Step #7 更新该城镇3范围内的所有单元格(包括可交互物体的glow以及边界的更新)
|
||
if (!mapData.GetGridDataByCityId(cityData.Id, out var grid))
|
||
return;
|
||
_tmpAroundBuf ??= new List<GridData>();
|
||
_tmpAroundBuf.Clear();
|
||
mapData.GridMap.GetAroundGridData(3, 3, grid, _tmpAroundBuf);
|
||
foreach (var tg in _tmpAroundBuf)
|
||
tg.Renderer(mapData)?.InstantUpdateGrid(true);
|
||
|
||
using var pooledTerritoryList = THCollectionPool.GetListHandle<uint>(out var list);
|
||
list.AddRange(cityData.Territory.TerritoryArea);
|
||
//更新player的视野
|
||
Main.PlayerLogic.UpdateSight_LogicView(mapData, playerData, list);
|
||
|
||
//Step #8 更新两个国家的所有levelbuilding情况,修正城市经验
|
||
UpdateTerritoryAllBuildingLevel(mapData,oldPid);
|
||
UpdateTerritoryAllBuildingLevel(mapData,newPid);
|
||
|
||
//Step #10 更新所有国家的联通情况,修正城市经验
|
||
UpdateAllPlayerConnected(mapData);
|
||
|
||
//Step #11 更新特殊占领技能
|
||
if(playerData.TechTree.CheckIfHasTechAtom(TechAtom.KaguyaFrenchNapoleonicCode))
|
||
Main.PlayerLogic.SetCityTerritoryGridSp(mapData,cityData,GridSpType.KaguyaGrid);
|
||
else
|
||
Main.PlayerLogic.ClearCityTerritoryGridSp(mapData,cityData,GridSpType.KaguyaGrid);
|
||
|
||
//Step #12 处理Moment
|
||
if (momentOccupyOurCaptain)
|
||
{
|
||
EventManager.Publish(new ShowUINotifyMoment()
|
||
{
|
||
MomentSubType = MomentSubType.BattleOccupyOurCaptain,
|
||
Empire = Main.MapData.PlayerMap.SelfPlayerData.Empire,
|
||
});
|
||
}
|
||
else if (momentOccupyCaptain)
|
||
{
|
||
EventManager.Publish(new ShowUINotifyMoment()
|
||
{
|
||
MomentSubType = MomentSubType.BattleOccupyCaptain,
|
||
Empire = Main.MapData.PlayerMap.SelfPlayerData.Empire,
|
||
});
|
||
}
|
||
|
||
else if (momentOccupyOurCity)
|
||
{
|
||
EventManager.Publish(new ShowUINotifyMoment()
|
||
{
|
||
MomentSubType = MomentSubType.BattleOccupyOurCity,
|
||
Empire = Main.MapData.PlayerMap.SelfPlayerData.Empire,
|
||
});
|
||
}
|
||
else if (momentOccupyLv6)
|
||
{
|
||
EventManager.Publish(new ShowUINotifyMoment()
|
||
{
|
||
MomentSubType = MomentSubType.BattleOccupyBigCity,
|
||
Empire = Main.MapData.PlayerMap.SelfPlayerData.Empire,
|
||
});
|
||
}
|
||
else if (momentOccupyLv5)
|
||
{
|
||
EventManager.Publish(new ShowUINotifyMoment()
|
||
{
|
||
MomentSubType = MomentSubType.BattleOccupyCity,
|
||
Empire = Main.MapData.PlayerMap.SelfPlayerData.Empire,
|
||
});
|
||
}
|
||
else if (momentBeOccupiedCaptain)
|
||
{
|
||
EventManager.Publish(new ShowUINotifyMoment()
|
||
{
|
||
MomentSubType = MomentSubType.BattleCaptainLost,
|
||
Empire = Main.MapData.PlayerMap.SelfPlayerData.Empire,
|
||
});
|
||
}
|
||
else if (momentBeOccupied)
|
||
{
|
||
EventManager.Publish(new ShowUINotifyMoment()
|
||
{
|
||
MomentSubType = MomentSubType.BattleCityLost,
|
||
Empire = Main.MapData.PlayerMap.SelfPlayerData.Empire,
|
||
});
|
||
}
|
||
|
||
}
|
||
|
||
|
||
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<GridData> GetPlayerResourceNearbyList(MapData mapData, PlayerData playerData, GridData gridData, ResourceType resourceType)
|
||
{
|
||
var aroundGridList = new List<GridData>();
|
||
_tmpAroundBuf ??= new List<GridData>();
|
||
_tmpAroundBuf.Clear();
|
||
mapData.GridMap.GetAroundGridDataSet_NOCENTER(1, 1, gridData, _tmpAroundBuf);
|
||
|
||
//var territoryGidSet = mapData.GetPlayerTerritoryGridIdSet(playerData.Id);
|
||
foreach (var grid in _tmpAroundBuf)
|
||
{
|
||
//如果不是玩家的领土
|
||
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<GridData> GetPlayerFeatureNearbyList(MapData mapData, PlayerData playerData, GridData gridData, TerrainFeature feature)
|
||
{
|
||
var aroundGridList = new List<GridData>();
|
||
_tmpAroundBuf ??= new List<GridData>();
|
||
_tmpAroundBuf.Clear();
|
||
mapData.GridMap.GetAroundGridDataSet_NOCENTER(1, 1, gridData, _tmpAroundBuf);
|
||
var territoryGidSet = mapData.GetPlayerTerritoryGridIdSet(playerData.Id);
|
||
|
||
foreach (var grid in _tmpAroundBuf)
|
||
{
|
||
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 GetAverageCityLevel(MapData map, PlayerData player)
|
||
{
|
||
int cityCount = 0;
|
||
int cityLv = 0;
|
||
foreach (var city in map.CityMap.CityList)
|
||
{
|
||
if (map.GetPlayerDataByCityId(city.Id, out var p1) && p1 == player)
|
||
{
|
||
cityCount++;
|
||
cityLv += city.Level;
|
||
}
|
||
}
|
||
|
||
if (cityCount == 0) return 0;
|
||
return cityLv / cityCount;
|
||
}
|
||
|
||
//获取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;
|
||
using var pooledCityList = THCollectionPool.GetListHandle<CityData>(out var cityList);
|
||
mapData.GetCityDataListByPlayerId(playerData.Id, cityList);
|
||
using var pooledConnectList = THCollectionPool.GetHashSetHandle<uint>(out var connectList);
|
||
//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,然后去除非盟友的有主海域,去除所有土地,这是所有港口可以计算最短路的格子,用来计算通路用的
|
||
using var pooledWaterRoadGidSet = THCollectionPool.GetHashSetHandle<uint>(out var waterRoadGidSet);
|
||
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;
|
||
|
||
}
|
||
|
||
|
||
//按照dis = 1 到5 依次处理每一对port(首先将所有距离=1的port pair连接了,然后是2,然后3...
|
||
for (int dis = 1; dis <= 5; dis++)
|
||
{
|
||
//#1-3每个己方领土内的港口进行floodfill 标记抵达其他港口的最短路
|
||
foreach (var portCandidate in gridSet)
|
||
{
|
||
if (portCandidate.Resource != ResourceType.Port) continue;
|
||
|
||
//Debug.Log($"candidatePort is {portCandidate.Id}");
|
||
|
||
// 记录前驱节点
|
||
using var pooledPrev = THCollectionPool.GetDictionaryHandle<uint, uint>(out var prev);
|
||
using var pooledDist = THCollectionPool.GetDictionaryHandle<uint, int>(out var dist);
|
||
using var pooledVisited = THCollectionPool.GetHashSetHandle<uint>(out var visited);
|
||
|
||
// 初始港口格子
|
||
uint startId = portCandidate.Id;
|
||
dist[startId] = 0;
|
||
visited.Add(startId);
|
||
|
||
// BFS 队列
|
||
Queue<uint> queue = new Queue<uint>();
|
||
queue.Enqueue(startId);
|
||
|
||
// 计算从该港口出发能辐射的5个距离内的bfs情况
|
||
while (queue.Count > 0)
|
||
{
|
||
uint currentId = queue.Dequeue();
|
||
mapData.GridMap.GetGridDataByGid(currentId, out var curGrid);
|
||
int currentDist = dist[currentId];
|
||
|
||
// 最长只扩展到距离为dis的格子
|
||
if (currentDist >= dis)
|
||
continue;
|
||
|
||
// 获取相邻格子
|
||
_tmpAroundBuf ??= new List<GridData>();
|
||
_tmpAroundBuf.Clear();
|
||
mapData.GridMap.GetAroundGridDataSetByOrder(1, 1, curGrid, _tmpAroundBuf);
|
||
foreach (var neighbor in _tmpAroundBuf)
|
||
{
|
||
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);
|
||
}
|
||
}
|
||
|
||
foreach (var targetPort in gridSet)
|
||
{
|
||
|
||
|
||
if (targetPort.Resource != ResourceType.Port) continue;
|
||
//先把目标港口的watermark设置为true
|
||
if (playerData.PlayerForceId < targetPort.WaterRoadForceId.Length)
|
||
targetPort.WaterRoadForceId[playerData.PlayerForceId] = true;
|
||
//只处理最短距离为dis的port pair
|
||
if (!dist.TryGetValue(targetPort.Id, out var disValue) || disValue != dis) continue;
|
||
|
||
//如果step步以内已经可达targetPort,那么也不需要新增最短路
|
||
int step = 6;
|
||
using var pooledVisitedSet = THCollectionPool.GetHashSetHandle<uint>(out var visitedSet);
|
||
using var pooledStartSet = THCollectionPool.GetHashSetHandle<uint>(out var startSet);
|
||
using var pooledNextSet = THCollectionPool.GetHashSetHandle<uint>(out var nextSet);
|
||
startSet.Add(portCandidate.Id);
|
||
while(step > 0)
|
||
{
|
||
foreach (var tmpStartId in startSet)
|
||
visitedSet.Add(tmpStartId);
|
||
foreach (var tmpStartId in startSet)
|
||
{
|
||
mapData.GridMap.GetGridDataByGid(tmpStartId, out var tmpStartGrid);
|
||
_tmpAroundBuf.Clear();
|
||
mapData.GridMap.GetAroundGridData(1, 1, tmpStartGrid, _tmpAroundBuf);
|
||
foreach(var tmpAroundGrid in _tmpAroundBuf)
|
||
if (playerData.PlayerForceId < tmpAroundGrid.WaterRoadForceId.Length
|
||
&& tmpAroundGrid.WaterRoadForceId[playerData.PlayerForceId]
|
||
&& !visitedSet.Contains(tmpAroundGrid.Id))
|
||
nextSet.Add(tmpAroundGrid.Id);
|
||
}
|
||
|
||
var swap = startSet;
|
||
startSet = nextSet;
|
||
nextSet = swap;
|
||
nextSet.Clear();
|
||
step--;
|
||
}
|
||
|
||
//如果仅仅依靠当前的waterRoadMark ,就能在5格内访问到targetPort,那么跳出
|
||
if (visitedSet.Contains(targetPort.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)?.InstantUpdateGrid(true);
|
||
_tmpAroundBuf.Clear();
|
||
mapData.GridMap.GetAroundGridDataSetByOrder(1, 1, grid, _tmpAroundBuf);
|
||
foreach (var nearbyGrid in _tmpAroundBuf)
|
||
nearbyGrid.Renderer(mapData)?.InstantUpdateGrid(true);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//#1-5 从首都出发,进行floodfill,计算哪些城市可以被抵达。是否联通,只需要判断两个格子是否都具有road属性即可(不过有些文明要特殊判断)
|
||
using var pooledCn = THCollectionPool.GetHashSetHandle<uint>(out var cn);
|
||
//floodfill算一遍从首都出发的连通性
|
||
if (!mapData.GetCapitalCityDataByPlayerId(playerData.Id, out var capital)) return;
|
||
if (!mapData.GetGridDataByCityId(capital.Id, out var capitalGrid)) return;
|
||
|
||
cn.Add(capitalGrid.Id);
|
||
Queue<uint> li = new Queue<uint>();
|
||
li.Enqueue(capitalGrid.Id);
|
||
while (li.Count > 0)
|
||
{
|
||
var head = li.Dequeue();
|
||
|
||
if (!mapData.GridMap.GetGridDataByGid(head, out var headGrid)) continue;
|
||
_tmpAroundBuf ??= new List<GridData>();
|
||
_tmpAroundBuf.Clear();
|
||
mapData.GridMap.GetAroundGridDataSet_NOCENTER(1, 1, headGrid, _tmpAroundBuf);
|
||
foreach (var aroundGrid in _tmpAroundBuf)
|
||
{
|
||
//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 先处理moriya 的联通判断moriyaroad的情况
|
||
else if (playerData.TechTree.CheckIfHasTechAtom(TechAtom.MoriyaRoad))
|
||
{
|
||
if (aroundGrid.Feature != TerrainFeature.Road &&
|
||
(aroundGrid.Feature != TerrainFeature.Mountain || !aroundGrid.HasBuilding())) continue;
|
||
}
|
||
//Step #2-3 再处理其他常规的联通判断
|
||
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_LogicView(mapData,playerData,city.Grid(mapData),city,expDelta);
|
||
|
||
//Step #6 更新联通动画
|
||
if((city.Grid(mapData)?.IsMainMap() ?? false) && (city.Player(mapData)?.IsSelfPlayer()??false)){
|
||
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,mapData,null))
|
||
grid.Renderer(mapData)?.InstantUpdateGrid(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,mapData))
|
||
grid.Renderer(mapData)?.InstantUpdateGrid(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.IsSurvival || !p2.IsSurvival) 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(p2.VisibleUnit(map,p1,out var unit) && unit.Player(map,out var unitPlayer) && !p1.MeetPlayers.Contains(unitPlayer.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)
|
||
{
|
||
if (p1.MeetPlayers.Contains(p2.Id)) return;
|
||
//step #1 meetlist增加
|
||
p1.MeetPlayers.Add(p2.Id);
|
||
foreach (var kv in p1.PlayerHeroData.HeroTaskDict) kv.Value.OnMeetOtherPlayers(map, p1);
|
||
//step #2 加钱
|
||
var coin = GetFirstMeetCoin(map,p2);
|
||
p1.AddCoin_LogicOnly(coin);
|
||
|
||
//step #3 如果我方拥有大使馆科技,获得对方原始首都的视野
|
||
if (p1.TechTree.CheckIfHasTech(TechType.Diplomacy))
|
||
{
|
||
if(map.GetGridIdByCityId(p2.CradleCityId, out var cradleGid))
|
||
{
|
||
using var pooledGidList = THCollectionPool.GetListHandle<uint>(out var gidList);
|
||
gidList.Add(cradleGid);
|
||
UpdateSight_LogicView(map, p1, gidList);
|
||
}
|
||
}
|
||
|
||
//step #5
|
||
//如果是玩家,出发ui提示。加钱的操作要在ui提示关闭的时候由ui来出发
|
||
//只在真实 Main.MapData 上弹,避免 AI 预测/模拟的虚假 MapData 误触发
|
||
if (map == Main.MapData && 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;
|
||
//水面格(浅海/深海)只有Bridge才算有road加成,避免LandAndWater单位在带road属性的水格上错误吃到加成
|
||
if (gridDataA.Terrain is TerrainType.ShallowSea or TerrainType.DeepSea
|
||
&& gridDataA.Resource != ResourceType.Bridge)
|
||
OriginHasRoad = false;
|
||
if (gridDataB.Terrain is TerrainType.ShallowSea or TerrainType.DeepSea
|
||
&& gridDataB.Resource != ResourceType.Bridge)
|
||
TargetHasRoad = false;
|
||
//这里要特殊处理永远亭的bamboo move
|
||
if (unitData.GetSkill(SkillType.BAMBOOMOVE, out var _))
|
||
{
|
||
if (gridDataA.Vegetation == Vegetation.Trees) OriginHasRoad = true;
|
||
if (gridDataB.Vegetation == Vegetation.Trees) TargetHasRoad = true;
|
||
}
|
||
//这里要特殊处理Moriya 的moriyamove
|
||
if (unitData.GetSkill(SkillType.MORIYAROAD, out var _))
|
||
{
|
||
if (gridDataA.Feature == TerrainFeature.Mountain && gridDataA.HasBuilding()) OriginHasRoad = true;
|
||
if (gridDataB.Feature == TerrainFeature.Mountain && gridDataB.HasBuilding()) 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.GetGridDataByCityId(city.Id, out var grid)) return false;
|
||
if (!grid.RealUnit(map, 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.SpendTechPoint(cost);
|
||
//playerData.PlayerTechPoint -= cost;
|
||
}
|
||
else
|
||
{
|
||
playerData.SpendCoin(cost - playerData.PlayerTechPoint);
|
||
playerData.SpendTechPoint(playerData.PlayerTechPoint);
|
||
//playerData.PlayerTechPoint = 0;
|
||
}
|
||
|
||
playerData.TechTree.LearnTech(techType, playerData);
|
||
// Collect 调用
|
||
CollectManager.Instance.LearnTechsCollect(mapData, playerData, 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)?.InstantUpdateGrid(true);
|
||
|
||
|
||
//竹林驿站科技特殊处理城市联通情况 TODO 临时写法
|
||
if (techType == TechType.KaguyaRoad || techType == TechType.KanakoRoads)
|
||
Main.PlayerLogic.UpdateAllPlayerConnected(mapData);
|
||
|
||
var techInfo = Table.Instance.TechDataAssets.GetTechInfo(techType);
|
||
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;
|
||
using var pooledCondition = THCollectionPool.GetHashSetHandle<UnitFullType>(out var condition);
|
||
if (!forAll)
|
||
{
|
||
condition.UnionWith(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_Legacy(atomInfo.AddSkillType, mapData, true, -1, false, -1, false,
|
||
SpecialAddSkillType.Force, 0);
|
||
//TODO 森林防御刷新视觉的临时写法
|
||
if (atomInfo.AddSkillType is SkillType.FORESTDEFENSE or SkillType.WATERDEFENSE
|
||
or SkillType.OCEANDEFENSE or SkillType.MOUNTAINDEFENSE)
|
||
unit.Renderer(mapData)?.RenderUpdateUnitDefense();
|
||
}
|
||
}
|
||
}
|
||
//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.InGameBubbleManager.CloseAllBubble();
|
||
playerData.TurnNoAttack++;
|
||
}
|
||
|
||
public int GetPlayerTechPointPerTurn(MapData mapData, uint playerId)
|
||
{
|
||
int ret = 0;
|
||
mapData.PlayerMap.GetPlayerDataByPlayerID(playerId, out var player);
|
||
foreach(var cityData in mapData.CityMap.CityList)
|
||
if (mapData.CityToPlayerDict[cityData.Id] == playerId)
|
||
ret += Main.CityLogic.GetCityTechPointPerTurn(mapData,cityData);
|
||
|
||
//处理kanako的特殊能力
|
||
if (player != null && player.PlayerHeroData.HasHero(GiantType.GermanyKanako))
|
||
ret += (int)player.PlayerHeroData.GetHeroLevel(GiantType.GermanyKanako);
|
||
|
||
return ret;
|
||
}
|
||
|
||
public int GetPlayerCulturePointPerTurn(MapData mapData, uint playerId)
|
||
{
|
||
int ret = 0;
|
||
foreach(var cityData in mapData.CityMap.CityList)
|
||
if (mapData.CityToPlayerDict[cityData.Id] == playerId)
|
||
ret += Main.CityLogic.GetCityCulturePointPerTurn(mapData,cityData);
|
||
return ret;
|
||
}
|
||
|
||
public int GetPlayerMountainPoint(MapData mapData, uint playerId)
|
||
{
|
||
int ret = 0;
|
||
if (!mapData.PlayerMap.GetPlayerDataByPlayerID(playerId, out var player)) return ret;
|
||
if (!player.TechTree.CheckIfHasTechAtom(TechAtom.CreateMountain)) return ret;
|
||
ret += 1;
|
||
int aca = 0;
|
||
int pro = 0;
|
||
|
||
foreach (var g in mapData.GridMap.GridList)
|
||
{
|
||
if (g.Player(mapData) != player) continue;
|
||
if (g.Resource == ResourceType.Academy) aca++;
|
||
if (g.Feature == TerrainFeature.Mountain) pro++;
|
||
}
|
||
|
||
if (player.TechTree.CheckIfHasTechAtom(TechAtom.AcademyCreateMountain)) ret += aca;
|
||
if(player.TechTree.CheckIfHasTechAtom(TechAtom.CreateMountainPro)) ret += pro / 3;
|
||
|
||
//处理kanako的特殊能力
|
||
if (player.PlayerHeroData.HasHero(GiantType.GermanyKanako))
|
||
ret += (int)player.PlayerHeroData.GetHeroLevel(GiantType.GermanyKanako) + 1;
|
||
|
||
return ret;
|
||
}
|
||
|
||
public int GetPlayerCoinPerTurn(MapData mapData, uint playerId)
|
||
{
|
||
int ret = 0;
|
||
foreach(var cityData in mapData.CityMap.CityList)
|
||
if (mapData.CityToPlayerDict[cityData.Id] == playerId)
|
||
ret += Main.CityLogic.GetCityCoinPerTurn(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.CheckIfHasTechAtom(TechAtom.TechIndustry))
|
||
ret += GetPlayerTechPointPerTurn(mapData, playerId) / 2;
|
||
|
||
//计算外交收入
|
||
foreach (var t in player.MeetPlayers)
|
||
{
|
||
if (!mapData.PlayerMap.GetPlayerDataByPlayerID(t, out var tplayer)) continue;
|
||
if (!tplayer.IsSurvival) continue;
|
||
ret += GetEmbassyCoin(mapData,player, tplayer);
|
||
}
|
||
|
||
//文化值转化为金币
|
||
if (player.CanConvertCultureToGold(mapData))
|
||
ret += GetPlayerCulturePointPerTurn(mapData, playerId);
|
||
|
||
return ret;
|
||
}
|
||
|
||
|
||
|
||
//进入回合结算 #ono #nextturn #start #startturn
|
||
public void StartNextTurn(MapData mapData, PlayerData playerData)
|
||
{
|
||
Debug.Log($"[Bubble] StartNextTurn called for player {playerData.Id}, Turn={playerData.Turn}");
|
||
if (mapData != Main.MapData)
|
||
{
|
||
LogSystem.LogError("PlayerLogic StartNextTurn can't start next turn,mapData is not Real MAPDATA !!!");
|
||
return;
|
||
}
|
||
|
||
//每回合提示
|
||
Debug.Log($"[Bubble] Checking SelfPlayerId: {mapData.PlayerMap.SelfPlayerId}, playerId: {playerData.Id}, match={playerData.Id == mapData.PlayerMap.SelfPlayerId}");
|
||
if (playerData.Id == mapData.PlayerMap.SelfPlayerId)
|
||
{
|
||
Debug.Log("[Bubble] Calling TurnStartSetBubble...");
|
||
MapRenderer.Instance.InGameBubbleManager.TurnStartSetBubble(mapData,playerData);
|
||
//如果不是第0回合,要显示回合开始提示
|
||
if (playerData.Turn != 0)
|
||
{
|
||
EventManager.Publish(new UpdateUITopTopBar() { UpdateType = UpdateTopBarType.UpdateTurn });
|
||
}
|
||
//UIManager.Instance.TopBarUI.SetShowTurnHint((int)playerData.Turn + 1);
|
||
}
|
||
|
||
//加钱/科技点/文化值的模块
|
||
//如果是0回合不用放动画 不用加钱 ,直接return
|
||
if (playerData.Turn != 0) {
|
||
//暂时在这里触发金币动画。实际上不应该的,TODO 迭代这里的动画触发逻辑
|
||
|
||
//增加科技点
|
||
playerData.AddTechPoint(GetPlayerTechPointPerTurn(mapData, playerData.Id));
|
||
|
||
//增加文化点
|
||
playerData.AddCulturePoint(GetPlayerCulturePointPerTurn(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;
|
||
}
|
||
|
||
// Temple每2回合自动升1级,最高5级
|
||
if (grid.Resource is ResourceType.Temple or ResourceType.KingTemple
|
||
or ResourceType.ForestTemple or ResourceType.WaterTemple
|
||
or ResourceType.MountainTemple)
|
||
{
|
||
if (grid.buildingLevel < 5
|
||
&& playerData.Turn >= grid.BuildTime + 2
|
||
&& (playerData.Turn - grid.BuildTime) % 2 == 0)
|
||
{
|
||
grid.buildingLevel++;
|
||
Main.CityLogic.UpdateGrid_ViewOnly(mapData, grid);
|
||
}
|
||
}
|
||
}
|
||
|
||
var addCoin = GetPlayerCoinPerTurn(mapData, playerData.Id);
|
||
|
||
playerData.AddCoin_LogicOnly(addCoin);
|
||
|
||
|
||
//如果是真人玩家,要播放动画
|
||
if (playerData.IsSelfPlayer())
|
||
{
|
||
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.GetCityCoinPerTurn(mapData, city);
|
||
else
|
||
money = GetEmbassyCoin(mapData, playerData, tmpPlayer);
|
||
if(money <= 0)continue;
|
||
MapRenderer.Instance.ProjectileManager.CreateCoinProjectile(startPos,money);
|
||
}
|
||
EventManager.Publish(new UpdateUITopTopBar() { UpdateType = UpdateTopBarType.UpdateCoin });
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//处理收到的外交请求,必须是真人玩家
|
||
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.IsSurvival) 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);
|
||
}
|
||
|
||
public bool GetAllSight()
|
||
{
|
||
var selfp = Main.MapData.PlayerMap.SelfPlayerData;
|
||
foreach (var t in Main.MapData.GridMap.GridList)
|
||
{
|
||
if (selfp.Sight.SightGidSet.Add(t.Id))
|
||
{
|
||
t.Renderer(Main.MapData)?.FirstShowGrid();
|
||
/*t.Renderer(Main.MapData)?.SetUpdateGrid();
|
||
if(t.CityOnGrid(Main.MapData,out var city))
|
||
t.Renderer(Main.MapData)?.SetUpdateCityBuilding(city.Level,
|
||
Table.Instance.TransCivIdToCivEnum(city.Player(Main.MapData).PlayerCivId));*/
|
||
}
|
||
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
//TODO 目前UpdateSight在MapRenderer初始化之前就使用了。要处理
|
||
// 更新视野 ,viewNextFrame表示这次的动画是否排在下一帧才注册,dur表示更新雾效的时候间隔时间是0.01s(开局用)还是0.05f(默认)
|
||
public int UpdateSight_LogicView(MapData mapData,PlayerData playerData, List<uint> gidList,bool viewNextFrame = false,float dur = 0.05f)
|
||
{
|
||
if (playerData == null)
|
||
{
|
||
Debug.Log("playerData Null !!!!");
|
||
return 0;
|
||
}
|
||
|
||
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)),viewNextFrame);
|
||
|
||
}
|
||
|
||
//尝试判断gridData有没有带来新的meetplayerList
|
||
TryAddMeetPlayer(mapData, playerData, gridData);
|
||
|
||
|
||
//处理发现tower的情况
|
||
if (gridData.Resource == ResourceType.Tower)
|
||
{
|
||
Main.CityLogic.GridGiveCityExp_LogicView(mapData,playerData,gridData,city,1);
|
||
//更新奇观情况,可能弹出奇观通知
|
||
UpdateWonder(mapData,playerData);
|
||
|
||
}
|
||
}
|
||
|
||
//更新视野后,要更新联通情况
|
||
Main.PlayerLogic.UpdateCityConnect(mapData,playerData);
|
||
return count;
|
||
}
|
||
|
||
//ViewNextFrame表示View相关的内容要放在下一帧执行
|
||
public int UpdateSightByRadius_LogicView(MapData mapData, PlayerData playerData, GridData gridData, int radius,bool ViewNextFrame = false)
|
||
{
|
||
return UpdateSight_LogicView(mapData,playerData,mapData.GridMap.GetAroundGridIdList(radius,gridData,true),ViewNextFrame);
|
||
}
|
||
|
||
public void DebugGetAllSight(MapData mapData, PlayerData playerData)
|
||
{
|
||
using var pooledGidList = THCollectionPool.GetListHandle<uint>(out var gidList);
|
||
foreach(var gridData in mapData.GridMap.GridList)
|
||
gidList.Add(gridData.Id);
|
||
UpdateSight_LogicView(mapData,playerData,gidList);
|
||
}
|
||
|
||
//如果我方拥有大使馆科技,更新所有meetlist的cradlecity位置
|
||
public void UpdateDiplomacySight(MapData map, PlayerData player)
|
||
{
|
||
while (true)
|
||
{
|
||
var count = player.MeetPlayers.Count;
|
||
for (int i = 0; i < count; i++)
|
||
{
|
||
var playerId = player.MeetPlayers[i];
|
||
if (player.Id == playerId) continue;
|
||
if (!map.PlayerMap.GetPlayerDataByPlayerID(playerId, out var player2)) continue;
|
||
if (!map.GetGridDataByCityId(player2.CradleCityId, out var grid)) continue;
|
||
using var pooledGidList = THCollectionPool.GetListHandle<uint>(out var gidList);
|
||
gidList.Add(grid.Id);
|
||
UpdateSight_LogicView(map, player, gidList);
|
||
}
|
||
|
||
if (count != player.MeetPlayers.Count) continue;
|
||
break;
|
||
}
|
||
}
|
||
|
||
//返回某个玩家学习某个科技的真实价格
|
||
public int GetTechCost(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.IsAlive()) 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)
|
||
{
|
||
if (!originPlayer.GetCountryDiplomacyInfo(targetPlayer.Id, out var player1ToPlayer2)) return;
|
||
|
||
if (!targetPlayer.GetCountryDiplomacyInfo(originPlayer.Id, out var player2ToPlayer1)) return;
|
||
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 (map == Main.MapData
|
||
&& (originPlayer.Id == Main.MapData.PlayerMap.SelfPlayerId ||
|
||
targetPlayer.Id == Main.MapData.PlayerMap.SelfPlayerId))
|
||
{
|
||
var announce = new ShowUIAnnounceDiplomacy(){PlayerActionType = PlayerActionType.BreakEmbassy,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 (map == Main.MapData
|
||
&& (originPlayer.Id == Main.MapData.PlayerMap.SelfPlayerId ||
|
||
targetPlayer.Id == Main.MapData.PlayerMap.SelfPlayerId))
|
||
{
|
||
var announce = new ShowUIAnnounceDiplomacy(){PlayerActionType = PlayerActionType.BreakEmbassy,PlayerId = targetPlayer.Id,TargetPlayerId = originPlayer.Id};
|
||
EventManager.Publish(announce);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|