2025-07-11 19:06:30 +08:00

884 lines
44 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}
}
}