884 lines
44 KiB
C#
884 lines
44 KiB
C#
using System.Collections.Generic;
|
||
using System.Net;
|
||
using UnityEngine;
|
||
using RuntimeData;
|
||
using Logic.Action;
|
||
using Logic.CrashSight;
|
||
using TH1Renderer;
|
||
using Unity.VisualScripting;
|
||
|
||
namespace Logic
|
||
{
|
||
public class PlayerLogic : IPlayerLogic
|
||
{
|
||
private Main _main;
|
||
|
||
public PlayerLogic(Main main)
|
||
{
|
||
_main = main;
|
||
}
|
||
|
||
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)))
|
||
{
|
||
if (player.Wonder.GetWonderState(wonder) == WonderState.NO_HINT)
|
||
{
|
||
if (wonder == WonderTypeEnum.PEACE && player.TechTree.CheckIfHasTech(TechType.Meditation))
|
||
{
|
||
player.Wonder.SetWonderState(WonderTypeEnum.PEACE, WonderState.HAVE_HINT);
|
||
if (player == mapData.PlayerMap.SelfPlayerData)
|
||
UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.WonderStartPEACE, player);
|
||
}
|
||
|
||
if (wonder == WonderTypeEnum.KNOWLEDGE && player.TechTree.CheckIfHasTech(TechType.Philosophy))
|
||
{
|
||
player.Wonder.SetWonderState(WonderTypeEnum.KNOWLEDGE, WonderState.HAVE_HINT);
|
||
if (player == mapData.PlayerMap.SelfPlayerData)
|
||
UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.WonderStartKNOWLEDGE, player);
|
||
}
|
||
|
||
if (wonder == WonderTypeEnum.TRADE && player.TechTree.CheckIfHasTech(TechType.Roads))
|
||
{
|
||
player.Wonder.SetWonderState(WonderTypeEnum.TRADE, WonderState.HAVE_HINT);
|
||
if (player == mapData.PlayerMap.SelfPlayerData)
|
||
UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.WonderStartTRADE, player);
|
||
}
|
||
|
||
if (wonder == WonderTypeEnum.WEALTH && player.TechTree.CheckIfHasTech(TechType.Trade))
|
||
{
|
||
player.Wonder.SetWonderState(WonderTypeEnum.WEALTH, WonderState.HAVE_HINT);
|
||
if (player == mapData.PlayerMap.SelfPlayerData)
|
||
UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.WonderStartWEALTH, player);
|
||
}
|
||
|
||
if (wonder == WonderTypeEnum.EYE
|
||
&& (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)))
|
||
{
|
||
player.Wonder.SetWonderState(WonderTypeEnum.EYE, WonderState.HAVE_HINT);
|
||
if (player == mapData.PlayerMap.SelfPlayerData)
|
||
UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.WonderStartEYE, player);
|
||
}
|
||
|
||
if (wonder == WonderTypeEnum.POWER && player.TotalKill > 0)
|
||
{
|
||
player.Wonder.SetWonderState(WonderTypeEnum.POWER, WonderState.HAVE_HINT);
|
||
if (player == mapData.PlayerMap.SelfPlayerData)
|
||
UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.WonderStartPOWER, player);
|
||
}
|
||
|
||
if (wonder == WonderTypeEnum.PARK)
|
||
{
|
||
int citylv = 2;
|
||
foreach (var city in mapData.CityMap.CityList)
|
||
if (mapData.GetPlayerDataByCityId(city.Id, out var p1) && p1 == player && city.Level > citylv)
|
||
citylv = city.Level;
|
||
if (citylv > 2)
|
||
{
|
||
player.Wonder.SetWonderState(WonderTypeEnum.PARK, WonderState.HAVE_HINT);
|
||
if (player == mapData.PlayerMap.SelfPlayerData)
|
||
UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.WonderStartPARK, player);
|
||
}
|
||
}
|
||
}
|
||
else if (player.Wonder.GetWonderState(wonder) == WonderState.HAVE_HINT)
|
||
{
|
||
if (wonder == WonderTypeEnum.PEACE && player.TurnNoAttack >= 5)
|
||
{
|
||
player.Wonder.SetWonderState(WonderTypeEnum.PEACE, WonderState.FINISH_NOT_BUILD);
|
||
if (player == mapData.PlayerMap.SelfPlayerData)
|
||
UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.WonderFinishPEACE, player);
|
||
}
|
||
|
||
if (wonder == WonderTypeEnum.KNOWLEDGE && player.TechTree.HasAllTech())
|
||
{
|
||
player.Wonder.SetWonderState(WonderTypeEnum.KNOWLEDGE, WonderState.FINISH_NOT_BUILD);
|
||
if (player == mapData.PlayerMap.SelfPlayerData)
|
||
UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.WonderFinishKNOWLEDGE, player);
|
||
}
|
||
|
||
if (wonder == WonderTypeEnum.TRADE)
|
||
{
|
||
int c = 0;
|
||
foreach (var city in mapData.CityMap.CityList)
|
||
if (mapData.GetPlayerDataByCityId(city.Id, out var p2) && p2 == player && city.IsConnectedCapital)
|
||
c++;
|
||
if (c >= 5)
|
||
{
|
||
player.Wonder.SetWonderState(WonderTypeEnum.TRADE, WonderState.FINISH_NOT_BUILD);
|
||
if (player == mapData.PlayerMap.SelfPlayerData)
|
||
UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.WonderFinishTRADE, player);
|
||
}
|
||
}
|
||
|
||
if (wonder == WonderTypeEnum.WEALTH && player.PlayerWealth >= 100)
|
||
{
|
||
player.Wonder.SetWonderState(WonderTypeEnum.WEALTH, WonderState.FINISH_NOT_BUILD);
|
||
if (player == mapData.PlayerMap.SelfPlayerData)
|
||
UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.WonderFinishWEALTH, player);
|
||
}
|
||
|
||
if (wonder == WonderTypeEnum.EYE
|
||
&& (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)))
|
||
{
|
||
player.Wonder.SetWonderState(WonderTypeEnum.EYE, WonderState.FINISH_NOT_BUILD);
|
||
if (player == mapData.PlayerMap.SelfPlayerData)
|
||
UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.WonderFinishEYE, player);
|
||
}
|
||
|
||
if (wonder == WonderTypeEnum.POWER && player.TotalKill >= 10)
|
||
{
|
||
player.Wonder.SetWonderState(WonderTypeEnum.POWER, WonderState.FINISH_NOT_BUILD);
|
||
if (player == mapData.PlayerMap.SelfPlayerData)
|
||
UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.WonderFinishPOWER, player);
|
||
}
|
||
|
||
if (wonder == WonderTypeEnum.PARK)
|
||
{
|
||
int citylv = 2;
|
||
foreach (var city in mapData.CityMap.CityList)
|
||
if (mapData.GetPlayerDataByCityId(city.Id, out var p1) && p1 == player && city.Level > citylv)
|
||
citylv = city.Level;
|
||
if (citylv > 5)
|
||
{
|
||
player.Wonder.SetWonderState(WonderTypeEnum.PARK, WonderState.FINISH_NOT_BUILD);
|
||
if (player == mapData.PlayerMap.SelfPlayerData)
|
||
UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.WonderFinishPARK, player);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//判断当前这一帧,正在行动的玩家,meetlist的更新情况
|
||
var curPlayer = _main.GameLogic.CurPlayer;
|
||
if (curPlayer == null)
|
||
return;
|
||
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))
|
||
{
|
||
curPlayer.MeetPlayers.Add(player1.Id);
|
||
//如果是玩家,出发ui提示。加钱的操作要在ui提示关闭的时候由ui来出发
|
||
if (curPlayer == mapData.PlayerMap.SelfPlayerData)
|
||
{
|
||
|
||
UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.MeetNewPlayer,player1,grid);
|
||
}
|
||
//如果是AI,直接给player加钱
|
||
else
|
||
{
|
||
if(!mapData.GetCapitalCityDataByPlayerId(player1.Id,out var city))
|
||
continue;
|
||
curPlayer.PlayerWealth += city.Level * 2 - 1;
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
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))
|
||
{
|
||
curPlayer.MeetPlayers.Add(player1.Id);
|
||
//如果是玩家,出发ui提示。加钱的操作要在ui提示关闭的时候由ui来出发
|
||
if (curPlayer == mapData.PlayerMap.SelfPlayerData)
|
||
{
|
||
UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.MeetNewPlayer,player1,grid);
|
||
}
|
||
//如果是AI,直接给player加钱
|
||
else
|
||
{
|
||
if(!mapData.GetCapitalCityDataByPlayerId(player1.Id,out var capital))
|
||
continue;
|
||
curPlayer.PlayerWealth += capital.Level * 2 - 1;
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
|
||
//判断玩家的胜负情况
|
||
//var selfp = mapData.PlayerMap.SelfPlayerData;
|
||
//if (mapData.GetCityCount(selfp.Id) == 0)
|
||
//selfp.Alive = false;
|
||
|
||
}
|
||
|
||
|
||
// 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.CityInfoRenderMark = true;
|
||
cityData.CityInfoRenderMark = true;
|
||
//更新小兵的状态(可能会有城防)
|
||
unitData.RenderMark = true;
|
||
return cityData;
|
||
}
|
||
|
||
// unit 占领了city
|
||
public void OccupyCity(MapData mapData, UnitData unitData, CityData cityData)
|
||
{
|
||
// 先拿到小兵所属的玩家
|
||
if (!mapData.GetPlayerDataByUnitId(unitData.Id, out var playerData)) return;
|
||
|
||
|
||
|
||
|
||
// 修改城市和玩家的所属关系
|
||
if (!mapData.SetCityIdToPlayerId(cityData.Id, playerData.Id))
|
||
{
|
||
LogSystem.LogError("占领失败!");
|
||
return;
|
||
}
|
||
|
||
//转移小兵的编制,要在处理完城市和玩家所属关系后才能转移小兵编制,不然出局的玩家清理本城市小兵的时候会出错
|
||
if (!mapData.GetCityDataByUnitId(unitData.Id, out var oldCityData))
|
||
{
|
||
LogSystem.LogError("UnitHasNoCityData");
|
||
return;
|
||
}
|
||
mapData.SetUnitIdToCityId(unitData.Id, cityData.Id);
|
||
oldCityData.CityInfoRenderMark = true;
|
||
oldCityData.CityInfoRenderMark = true;
|
||
cityData.CityInfoRenderMark = true;
|
||
|
||
//更新小兵的状态(可能会有城防)
|
||
unitData.RenderMark = true;
|
||
|
||
//更新该城镇3范围内的所有单元格(包括可交互物体的glow以及边界的更新)
|
||
|
||
if (!mapData.GetGridDataByCityId(cityData.Id, out var grid))
|
||
return;
|
||
var gridList = mapData.GridMap.GetAroundGridData(3, 3, grid);
|
||
foreach (var tg in gridList)
|
||
tg.RenderMark = true;
|
||
|
||
|
||
}
|
||
|
||
//解散 or 丢失一个城镇
|
||
public void UpdatePlayerData(MapData mapData, PlayerData playerData)
|
||
{
|
||
List<CityData> cityList = new List<CityData>();
|
||
mapData.GetCityDataListByPlayerId(playerData.CradleCityId, cityList);
|
||
|
||
// 刷新是否存活
|
||
// TODO 原先的胜利失败表现方法已内置到 player map 内,renderer自己判断即可
|
||
if (cityList.Count == 0 &&playerData.Alive)
|
||
{
|
||
playerData.Alive = false;
|
||
//通知中央窗口提示谁已经死了
|
||
Debug.Log("NeedShow!!!");
|
||
UIManager.Instance.CenterMessageUI.SetCenterMessageShow(UICenterMessageID.ForcesFallen,playerData);
|
||
}
|
||
|
||
if (!mapData.GetCapitalCityDataByPlayerId(playerData.Id, out var capitalCity))
|
||
{
|
||
Main.CityLogic.SetCapital(mapData, cityList[0].Id);
|
||
}
|
||
|
||
}
|
||
|
||
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>();
|
||
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<GridData> GetPlayerFeatureNearbyList(MapData mapData, PlayerData playerData, GridData gridData, TerrainFeature feature)
|
||
{
|
||
var aroundGridList = new List<GridData>();
|
||
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;
|
||
}
|
||
|
||
|
||
|
||
// 仅从地形角度判断一个地方能不能建 bridge
|
||
public bool CheckTerrainCanBridge(MapData mapData, GridData gridData)
|
||
{
|
||
if (gridData.Terrain != TerrainType.ShallowSea) return false;
|
||
|
||
if (mapData.GridMap.GetUpGridData(gridData, 0, 1, out var upGridData) &&
|
||
mapData.GridMap.GetUpGridData(gridData, 0, -1, out var downGridData))
|
||
{
|
||
if (upGridData.Terrain == TerrainType.Land && downGridData.Terrain == TerrainType.Land) return true;
|
||
}
|
||
|
||
if (mapData.GridMap.GetUpGridData(gridData, 1, 0, out var rightGridData) &&
|
||
mapData.GridMap.GetUpGridData(gridData, -1, 0, out var leftGridData))
|
||
{
|
||
if (rightGridData.Terrain == TerrainType.Land && leftGridData.Terrain == TerrainType.Land) return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
|
||
|
||
// 解散小兵
|
||
public void Disband(MapData mapData, UnitData unitData, PlayerData playerData)
|
||
{
|
||
playerData.PlayerWealth +=
|
||
(Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(unitData.UnitType,unitData.GiantType,out var info)?info.Cost:0) / 2;
|
||
Main.UnitLogic.Die(mapData, unitData);
|
||
}
|
||
|
||
// 确认 bridge 是否需要镜像
|
||
public bool CheckBridgeMirror(MapData mapData, GridData gridData)
|
||
{
|
||
if (mapData.GridMap.IsInUpOrDownBorder(gridData)) return true;
|
||
if (!mapData.GridMap.GetUpGridData(gridData, 0, -1, out var downGrid)) return true;
|
||
if (!mapData.GridMap.GetUpGridData(gridData, 0, 1, out var upGrid)) return true;
|
||
if (downGrid.Terrain == TerrainType.Land && upGrid.Terrain == TerrainType.Land) return false;
|
||
return true;
|
||
}
|
||
|
||
//-------city相关操作-------
|
||
// 这里的数据缓存到 GridMap 里面去 TODO 这个方法读的不是很懂
|
||
public void UpdateCityConnect(MapData mapData, PlayerData playerData)
|
||
{
|
||
if (playerData == null) return;
|
||
|
||
//算法总述
|
||
//注意一些事实:
|
||
//首先,只有同一个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<uint>();
|
||
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<uint, uint>();
|
||
var dist = new Dictionary<uint, int>();
|
||
var visited = new HashSet<uint>();
|
||
|
||
// 初始港口格子
|
||
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];
|
||
|
||
// 最长只扩展到距离为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.RenderMark = true;
|
||
var neighbors = mapData.GridMap.GetAroundGridDataSetByOrder(1, 1, grid);
|
||
foreach (var nearbyGrid in neighbors)
|
||
nearbyGrid.RenderMark = true;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//#1-5 从首都出发,进行floodfill,计算哪些城市可以被抵达。是否联通,只需要判断两个格子是否都具有road属性即可。
|
||
var cn = new HashSet<uint>();
|
||
//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;
|
||
foreach (var aroundGrid in mapData.GridMap.GetAroundGridDataSet(1, 1, headGrid))
|
||
{
|
||
if (aroundGrid.Feature != TerrainFeature.Road) continue;
|
||
if (cn.Contains(aroundGrid.Id))continue;
|
||
cn.Add(aroundGrid.Id);
|
||
li.Enqueue(aroundGrid.Id);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
//遍历每个城市看看是否是可联通的
|
||
var cityList = new List<CityData>();
|
||
mapData.GetCityDataListByPlayerId(playerData.Id, cityList);
|
||
foreach (var city in cityList)
|
||
{
|
||
if (city == capital) continue;
|
||
if (!mapData.GetGridDataByCityId(city.Id, out var gridData))continue;
|
||
//如果没变化,continue
|
||
if (city.IsConnectedCapital == cn.Contains(gridData.Id)) continue;
|
||
city.IsConnectedCapital = cn.Contains(gridData.Id);
|
||
//有变化,那么要+1或者-1的cityexp
|
||
Main.CityLogic.CityUpdateExp(mapData, city, city.IsConnectedCapital ? 1:-1);
|
||
if (capital != null)
|
||
Main.CityLogic.CityUpdateExp(mapData, capital, city.IsConnectedCapital ? 1:-1);
|
||
|
||
|
||
city.CityInfoRenderMark = true;
|
||
capital.CityInfoRenderMark = true;
|
||
}
|
||
}
|
||
|
||
//-------- 查询 --------//
|
||
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 && gridAPlayerData.Id != unitPlayerId)
|
||
return false;
|
||
if (GridBHasPlayer && gridBPlayerData.Id != unitPlayerId)
|
||
return false;
|
||
return gridDataA.Feature == TerrainFeature.Road && gridDataB.Feature == TerrainFeature.Road;
|
||
|
||
}
|
||
|
||
//-------unit相关操作-------
|
||
public void CaptureCity(MapData mapData, PlayerData P, GridData T, UnitData U){}
|
||
//player[pid]使用unit[uid]占领了位于grid[pos]的无主村庄,或者有主城市
|
||
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) { }
|
||
|
||
//-------tech相关操作-------
|
||
|
||
public void ResearchTech(MapData mapData, PlayerData playerData, TechType techType,int cost)
|
||
{
|
||
playerData.PlayerWealth -= cost;
|
||
playerData.TechTree.LearnTech(techType);
|
||
foreach (var girdData in mapData.GridMap.GridList)
|
||
if(mapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(girdData.Id))
|
||
girdData.RenderMark = true;
|
||
|
||
//如果该科技有unitskill,将所有目前已经存在的unit都赋予这个skill
|
||
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);
|
||
unit.RenderMark = true;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
}
|
||
//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.HintManager.TurnEndSetHint(mapData,playerData);
|
||
//playerData.TurnNoAttack++;
|
||
//PlayerEndTurnLegacy(playerData);
|
||
}
|
||
|
||
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);
|
||
return ret;
|
||
}
|
||
|
||
|
||
|
||
//进入回合结算 #ono #nextturn #start #startturn
|
||
public void StartNextTurn(MapData mapData, PlayerData playerData)
|
||
{
|
||
|
||
//处理游戏Hint的模块,仅针对玩家
|
||
if(playerData.Id == mapData.PlayerMap.SelfPlayerId)
|
||
MapRenderer.Instance.HintManager.TurnStartSetHint(mapData,playerData);
|
||
|
||
//加钱的模块
|
||
//如果是0回合不用放动画 不用加钱 ,直接return
|
||
if (playerData.Turn != 0) {
|
||
//暂时在这里触发金币动画。实际上不应该的,TODO 迭代这里的动画触发逻辑
|
||
//如果不是selfplayer 不用放动画
|
||
if (playerData.Id != mapData.PlayerMap.SelfPlayerData.Id)
|
||
{
|
||
playerData.PlayerWealth += GetPlayerStarsPerTurn(mapData, playerData.Id);
|
||
return;
|
||
}
|
||
//否则,一边播放动画,一边1块钱1块钱的增加wealth
|
||
foreach (var city in mapData.CityMap.CityList)
|
||
{
|
||
if (!mapData.GetPlayerDataByCityId(city.Id, out var tmpPlayer))
|
||
continue;
|
||
if (tmpPlayer.Id != playerData.Id)
|
||
continue;
|
||
if (!mapData.GetGridDataByCityId(city.Id,out var grid))
|
||
continue;
|
||
var main = GameObject.Find("Main").GetComponent<Main>();
|
||
var startPos = Table.Instance.GridToWorld(grid);
|
||
var moneyPanel = GameObject.Find("UICanvas/TopBarPanel/MoneyPanel/Icon").transform;
|
||
var endPos = Camera.main.ScreenToWorldPoint(moneyPanel.position);
|
||
|
||
var money = Main.CityLogic.GetCityStarsPerTurn(mapData, city);
|
||
MapRenderer.Instance.ProjectileManager.CreateProjectileMulti(main,mapData,startPos,endPos,ProjectileType.Coin,ProjectileMoveType.CoinParabola,Main.CityLogic.GetCityStarsPerTurn(mapData,city),0.05f);
|
||
|
||
int k = 0;
|
||
while (k < money)
|
||
{
|
||
|
||
Timer.Instance.TimerRegister(this, () =>
|
||
{
|
||
playerData.PlayerWealth += 1;
|
||
},Table.Instance.AnimDataAssets.ProjectileCoinMoveTime + k * 0.05f);
|
||
k++;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
// 更新视野
|
||
public void UpdateSight(MapData mapData,PlayerData playerData, List<uint> gidList)
|
||
{
|
||
foreach (var id in gidList)
|
||
{
|
||
if (!playerData.Sight.SightGidSet.Add(id)) continue;
|
||
if (!mapData.GridMap.GetGridDataByGid(id, out var gridData)) continue;
|
||
if (!mapData.GetCapitalCityDataByPlayerId(playerData.Id, out var city)) continue;
|
||
//处理发现tower的情况
|
||
if (gridData.Resource == ResourceType.Tower)
|
||
{
|
||
|
||
if (playerData.Id == mapData.PlayerMap.SelfPlayerData.Id)
|
||
{
|
||
//临时做法,用来播放VFX,获取Main,理应向MapData写入一个VFX的RenderMark的
|
||
var main = GameObject.Find("Main").GetComponent<Main>();
|
||
var v1 = Table.Instance.GridToWorld(gridData);
|
||
mapData.GetGridDataByCityId(city.Id, out var g2);
|
||
var v2 = Table.Instance.GridToWorld(g2);
|
||
|
||
Timer.Instance.TimerRegister(Main.CityLogic, () =>
|
||
{
|
||
MapRenderer.Instance.ROGridMap[g2.Id].SetBounceAnim();
|
||
Main.CityLogic.CityUpdateExp(mapData,city,1);
|
||
},
|
||
Table.Instance.AnimDataAssets.ProjectileCityExpMoveTime);
|
||
|
||
MapRenderer.Instance.ProjectileManager.CreateProjectile(main,mapData,v1,v2,ProjectileType.CityExp,ProjectileMoveType.CityExpHighParabola);
|
||
}
|
||
else
|
||
{
|
||
Main.CityLogic.CityUpdateExp(mapData,city,1);
|
||
}
|
||
|
||
}
|
||
|
||
gridData.RenderMark = true;
|
||
if (mapData.GetUnitDataByGid(id, out var unitData))
|
||
unitData.RenderMark = true;
|
||
if (mapData.GetCityDataByGid(id, out var cityData))
|
||
{
|
||
cityData.CityInfoRenderMark = true;
|
||
cityData.RenderMark = true;
|
||
}
|
||
|
||
|
||
}
|
||
|
||
//更新视野后,要更新联通情况
|
||
Main.PlayerLogic.UpdateCityConnect(mapData,playerData);
|
||
}
|
||
|
||
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<uint>();
|
||
foreach(var gridData in mapData.GridMap.GridList)
|
||
gidList.Add(gridData.Id);
|
||
UpdateSight(mapData,playerData,gidList);
|
||
}
|
||
|
||
//返回某个玩家学习某个科技的真实价格
|
||
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;
|
||
}
|
||
|
||
// 城市得分(每级+50) + 奇观建筑(Temple等)
|
||
foreach (var city in mapData.CityMap.CityList)
|
||
{
|
||
if (!mapData.GetPlayerDataByCityId(city.Id, out var player)) continue;
|
||
player.PlayerScore += city.Level * 50;
|
||
|
||
if (mapData.GetGridDataByCityId(city.Id, 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, 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( PlayerData originPlayer, PlayerData targetPlayer, DiplomacyState state)
|
||
{
|
||
originPlayer.DiplomacyData.GetCountryDiplomacyInfo(targetPlayer.Id, out var player1ToPlayer2);
|
||
targetPlayer.DiplomacyData.GetCountryDiplomacyInfo(originPlayer.Id, out var player2ToPlayer1);
|
||
player1ToPlayer2.DiplomacyState = state;
|
||
player2ToPlayer1.DiplomacyState = state;
|
||
}
|
||
|
||
}
|
||
}
|