daixiawu 46e64be903 修复了bug
[版本 V0.7.2c]
发布日期:26.5.31

---------[bug修复与优化]-------------
1.修复了东风谷早苗掷签范围伤害击杀单位后图像残留的bug
2.修复了铃仙触发幻影齐射并击杀单位时可能产生图像残留的bug
3.修复了隐脉地块可能不显示的bug
4.优化了隐脉生成逻辑,且隐脉将不再会生成于水域或者山脉中
6.修复了探索者发现结界塔时城市经验动画播放错误的bug
8.优化了拖动地图时可能镜头强制移会起始点的bug
2026-05-31 19:07:11 +08:00

1007 lines
40 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.

/*
* @Author: 白哉
* @Description:
* @Date: 2025年04月03日 星期四 11:04:31
* @Modify:
*/
using System;
using System.Collections.Generic;
using Logic.Skill;
using MemoryPack;
using TH1_Logic.Core;
using TH1Renderer;
using UnityEngine;
using UnityEngine.Animations;
namespace RuntimeData
{
[MemoryPackable]
public partial class GridMapData
{
public List<GridData> GridList;
private Dictionary<uint, GridData> _posToGridDict;
private Dictionary<uint, GridData> _gridIdToGridDict;
private Dictionary<uint, int> _gridIdToIndexDict;
private MapConfig _mapCfg;
[MemoryPackConstructor]
public GridMapData()
{
GridList = new List<GridData>();
_posToGridDict = new Dictionary<uint, GridData>();
_gridIdToGridDict = new Dictionary<uint, GridData>();
_gridIdToIndexDict = new Dictionary<uint, int>();
}
public GridMapData(MapConfig mapCfg, MapIdGenerator idGenerator)
{
_mapCfg = mapCfg;
GridList = new List<GridData>();
_posToGridDict = new Dictionary<uint, GridData>();
_gridIdToGridDict = new Dictionary<uint, GridData>();
_gridIdToIndexDict = new Dictionary<uint, int>();
for (int x = 0; x < mapCfg.Width; x++)
{
for (int y = 0; y < mapCfg.Height; y++)
{
var gridData = new GridData(x, y, idGenerator,mapCfg);
GridList.Add(gridData);
_gridIdToGridDict[gridData.Id] = gridData;
_posToGridDict[gridData.Pos.PosId] = gridData;
}
}
for (int i = 0; i < GridList.Count; i++)
{
_gridIdToIndexDict[GridList[i].Id] = i;
}
}
public GridMapData(GridMapData copyData)
{
_mapCfg = copyData._mapCfg;
GridList = new List<GridData>();
_posToGridDict = new Dictionary<uint, GridData>();
_gridIdToGridDict = new Dictionary<uint, GridData>();
_gridIdToIndexDict = new Dictionary<uint, int>();
foreach (var grid in copyData.GridList)
{
var gridData = new GridData(grid);
GridList.Add(gridData);
_gridIdToGridDict[gridData.Id] = gridData;
_posToGridDict[gridData.Pos.PosId] = gridData;
}
for (int i = 0; i < GridList.Count; i++)
{
_gridIdToIndexDict[GridList[i].Id] = i;
}
}
public void DeepCopy(GridMapData copyData)
{
_mapCfg = copyData._mapCfg;
_posToGridDict.Clear();
_gridIdToGridDict.Clear();
_gridIdToIndexDict.Clear();
for (int i = 0; i < copyData.GridList.Count; i++)
{
var copyGrid = copyData.GridList[i];
if (i >= GridList.Count)
{
var gridData = new GridData(copyGrid);
GridList.Add(gridData);
_gridIdToGridDict[gridData.Id] = gridData;
_posToGridDict[gridData.Pos.PosId] = gridData;
}
else
{
GridList[i].DeepCopy(copyGrid);
_gridIdToGridDict[GridList[i].Id] = GridList[i];
_posToGridDict[GridList[i].Pos.PosId] = GridList[i];
}
}
for (int i = GridList.Count - 1; i >= copyData.GridList.Count; i--)
{
_gridIdToGridDict.Remove(GridList[i].Id);
_posToGridDict.Remove(GridList[i].Pos.PosId);
GridList.RemoveAt(i);
}
for (int i = 0; i < GridList.Count; i++)
{
_gridIdToIndexDict[GridList[i].Id] = i;
}
}
[MemoryPackOnDeserialized]
public void OnAfterMemoryPackDeserialize()
{
_posToGridDict ??= new Dictionary<uint, GridData>();
_gridIdToGridDict ??= new Dictionary<uint, GridData>();
_gridIdToIndexDict??= new Dictionary<uint, int>();
_posToGridDict.Clear();
_gridIdToGridDict.Clear();
_gridIdToIndexDict.Clear();
foreach (var grid in GridList)
{
_gridIdToGridDict[grid.Id] = grid;
_posToGridDict[grid.Pos.PosId] = grid;
}
for (int i = 0; i < GridList.Count; i++)
{
_gridIdToIndexDict[GridList[i].Id] = i;
}
}
public void BindMapConfig(MapConfig cfg)
{
_mapCfg = cfg;
}
public void OnTurnStart(MapData map)
{
foreach (var grid in GridList) grid.OnTurnStart(map);
}
public void OnTurnEnd(MapData map)
{
foreach (var grid in GridList) grid.OnTurnEnd(map);
}
public int GetGridIndexByGid(uint gid)
{
return _gridIdToIndexDict.GetValueOrDefault(gid, 0);
}
// 通过 gid 获取格子数据
public bool GetGridDataByGid(uint gid, out GridData data)
{
return _gridIdToGridDict.TryGetValue(gid, out data);
}
// 通过坐标获取格子数据
public bool GetGridDataByPos(int x, int y, out GridData gridData)
{
return _posToGridDict.TryGetValue(MapPosition.CalculatePosId(x, y), out gridData);
}
public bool GetGridDataByV2(Vector2 v2, out GridData gridData)
{
return GetGridDataByPos((int)v2.x, (int)v2.y, out gridData);
}
public bool GetGridDataByVector3Pos(Vector3 pos, out GridData gridData)
{
var p = Table.Instance.WorldToGrid(pos);
return _posToGridDict.TryGetValue(MapPosition.CalculatePosId(p.x, p.y), out gridData);
}
// 获取目标周围的所有格子(含center) - Buffer版本减少GC
public void GetAroundGridData(int xOffset, int yOffset, GridData gridData, List<GridData> buffer)
{
buffer.Clear();
if (gridData == null) return;
int radius = Mathf.Max(xOffset, yOffset);
for (int r = 0; r <= radius; r++)
{
for (int x = gridData.Pos.X - xOffset; x <= gridData.Pos.X + xOffset; x++)
{
for (int y = gridData.Pos.Y - yOffset; y <= gridData.Pos.Y + yOffset; y++)
{
if (!GetGridDataByPos(x, y, out var aroundGridData)) continue;
if (Mathf.Max(Mathf.Abs(x - gridData.Pos.X) , Mathf.Abs(y - gridData.Pos.Y)) != r) continue;
buffer.Add(aroundGridData);
}
}
}
}
// 获取目标周围的所有格子(含center) - 兼容版本(会分配新List)
public List<GridData> GetAroundGridData(int xOffset, int yOffset, GridData gridData)
{
var gridDataList = new List<GridData>();
GetAroundGridData(xOffset, yOffset, gridData, gridDataList);
return gridDataList;
}
// 获取目标周围的所有格子(不含center) - Buffer版本减少GC
public void GetAroundGridDataSet_NOCENTER(int xOffset, int yOffset, GridData gridData, List<GridData> buffer)
{
buffer.Clear();
for (int x = gridData.Pos.X - xOffset; x <= gridData.Pos.X + xOffset; x++)
{
for (int y = gridData.Pos.Y - yOffset; y <= gridData.Pos.Y + yOffset; y++)
{
if (!GetGridDataByPos(x, y, out var aroundGridData)) continue;
if (x == gridData.Pos.X && y == gridData.Pos.Y) continue;
buffer.Add(aroundGridData);
}
}
}
// 获取目标周围的所有格子(不含center) - 兼容版本(会分配新HashSet)
public HashSet<GridData> GetAroundGridDataSet_NOCENTER(int xOffset, int yOffset, GridData gridData)
{
HashSet<GridData> gridDataSet = new HashSet<GridData>();
for (int x = gridData.Pos.X - xOffset; x <= gridData.Pos.X + xOffset; x++)
{
for (int y = gridData.Pos.Y - yOffset; y <= gridData.Pos.Y + yOffset; y++)
{
if (!GetGridDataByPos(x, y, out var aroundGridData)) continue;
if (x == gridData.Pos.X && y == gridData.Pos.Y) continue;
gridDataSet.Add(aroundGridData);
}
}
return gridDataSet;
}
// 获取目标周围的所有格子,按照优先2468方向 - Buffer版本减少GC
public void GetAroundGridDataSetByOrder(int xOffset, int yOffset, GridData gridData, List<GridData> buffer)
{
buffer.Clear();
for (int i = 1; i <= 9; i++)
{
int dirForHuman = (i <= 4) ? (2 * i) : (2 * (i - 5) + 1);
int dirForComputer = dirForHuman - 1;
int x = gridData.Pos.X + dirForComputer % 3 - 1;
int y = gridData.Pos.Y + dirForComputer / 3 - 1;
if (!GetGridDataByPos(x, y, out var aroundGridData)) continue;
if (x == gridData.Pos.X && y == gridData.Pos.Y) continue;
buffer.Add(aroundGridData);
}
}
// 获取目标周围的所有格子,按照优先2468方向 - 兼容版本(会分配新List)
public List<GridData> GetAroundGridDataSetByOrder(int xOffset, int yOffset, GridData gridData)
{
var gridDataList = new List<GridData>();
GetAroundGridDataSetByOrder(xOffset, yOffset, gridData, gridDataList);
return gridDataList;
}
// 获取周围格子ID列表 - Buffer版本减少GC
public void GetAroundGridIdList(int radius, GridData gridData, List<uint> buffer, bool remainCenter = false)
{
buffer.Clear();
for (int r = 0; r <= radius; r++)
{
for (int x = gridData.Pos.X - radius; x <= gridData.Pos.X + radius; x++)
{
for (int y = gridData.Pos.Y - radius; y <= gridData.Pos.Y + radius; y++)
{
if (!GetGridDataByPos(x, y, out var aroundGridData)) continue;
if (Mathf.Max(Mathf.Abs(x - gridData.Pos.X) , Mathf.Abs(y - gridData.Pos.Y)) != r) continue;
if (!remainCenter && x == gridData.Pos.X && y == gridData.Pos.Y) continue;
buffer.Add(aroundGridData.Id);
}
}
}
}
// 获取周围格子ID列表 - 兼容版本(会分配新List)
public List<uint> GetAroundGridIdList(int radius, GridData gridData, bool remainCenter = false)
{
var gridIdList = new List<uint>();
GetAroundGridIdList(radius, gridData, gridIdList, remainCenter);
return gridIdList;
}
// 获取周围某个格子
public bool GetUpGridData(GridData gridData, int xOffset, int yOffset, out GridData upGridData)
{
return GetGridDataByPos(gridData.Pos.X + xOffset, gridData.Pos.Y + yOffset, out upGridData);
}
// 判断是否在左右边界
public bool IsInLeftOrRightBorder(GridData gridData)
{
return gridData.Pos.X == 0 || gridData.Pos.X == _mapCfg.Width - 1;
}
// 判断是否在上下边界
public bool IsInUpOrDownBorder(GridData gridData)
{
return gridData.Pos.Y == 0 || gridData.Pos.Y == _mapCfg.Height - 1;
}
//-------- 计算类方法 --------//
//计算切比雪夫距离
public int CalcDistance(GridData gridDataA, GridData gridDataB)
{
return Mathf.Max(Mathf.Abs(gridDataA.Pos.X - gridDataB.Pos.X),Mathf.Abs(gridDataA.Pos.Y - gridDataB.Pos.Y));
}
//计算曼哈顿距离
public int CalcManhattanDistance(GridData gridDataA, GridData gridDataB)
{
return Mathf.Abs(gridDataA.Pos.X - gridDataB.Pos.X) + Mathf.Abs(gridDataA.Pos.Y - gridDataB.Pos.Y);
}
public void RefreshConnectInfo()
{
}
public bool CalcBridgeMirror(GridData gridData)
{
var x = gridData.Pos.X;
var y = gridData.Pos.Y;
if (!GetGridDataByPos(x, y - 1, out var grid1)) return true;
if (!GetGridDataByPos(x, y + 1, out var grid2)) return true;
if (grid1.Terrain != TerrainType.Land) return true;
if (grid2.Terrain != TerrainType.Land) return true;
return false;
}
public GridData GetNextGrid(GridData first, GridData second)
{
int dx = second.Pos.X - first.Pos.X;
int dy = second.Pos.Y - first.Pos.Y;
// 将方向归一化为 -1, 0, 1八方向
int stepX = dx != 0 ? (dx > 0 ? 1 : -1) : 0;
int stepY = dy != 0 ? (dy > 0 ? 1 : -1) : 0;
int nextX = second.Pos.X + stepX;
int nextY = second.Pos.Y + stepY;
if (GetGridDataByPos(nextX, nextY, out var nextGrid)) return nextGrid;
return null;
}
}
public enum GridSpType { None,RemiliaGrid,KaguyaGrid,RemiliaGridDark,LeyLine,Max }
// 每个格子包含5个层次的信息
[MemoryPackable]
public partial class GridData : IdentifierBase
{
//-------- BaseData ---------//
// 位置信息
public MapPosition Pos;
//public bool CityBuildingRenderMark = false;
// 海陆层
public TerrainType Terrain;
// 地形层
public TerrainFeature Feature;
// UpdateGeoInfo 复用的HashSet缓冲区
private static HashSet<GeoSmallClass> _geoSmallSetBuffer;
// 植被层
public Vegetation Vegetation;
// 资源层+建筑层
public ResourceType Resource;
public WonderLibrary Wonder;
public ResourceType ResourceUnderBuilding;
// 特殊效果层
public List<GridSpType> SpTypeList;
// Geo信息层
public List<uint> GeoIdList;
public bool[] WaterRoadForceId;
// 文明层
public uint CivId;
public CivEnum CivEnum => Table.Instance.TransCivIdToCivEnum(CivId);
//奇观Id
//建筑level-只对部分建筑生效
public int buildingLevel;
//海军基底提供的每回合恢复次数 , 目前天狗酒馆也采用这个次数
//TODO 整合到gridSkill去
public int NavalBasePoint;
//建筑的建立时间目前只对temple有效
public uint BuildTime;
//通用冷却cd参数kaguyaFrenchAnimal吸引动物、EgyptianIrrigation生成农田都会操纵这个参数 //建筑的kaguyaFrenchAnimal吸引量每回合+1>=2则可以在周围找个树林吸引一个动物然后置0
public uint CommonColdTime;
//-------- RenderData ---------//
//cityborder相关的RenderMark
[MemoryPackIgnore]
public bool CityBorderRenderMark = false;
[MemoryPackConstructor]
public GridData()
{
SpTypeList = new List<GridSpType>();
}
public GridData(int x, int y,MapIdGenerator mapIdGenerator,MapConfig mapConfig)
{
SpTypeList = new List<GridSpType>();
Pos = new MapPosition(x,y);
Id = mapIdGenerator.GeneratorId();
WaterRoadForceId = new bool[Table.Instance.MaxForceCount];
}
//仅用于AI计算data不需要render的部分
public GridData(GridData copyData)
{
Pos = new MapPosition(copyData.Pos.X, copyData.Pos.Y);
Id = copyData.Id;
Terrain = copyData.Terrain;
Feature = copyData.Feature;
Vegetation = copyData.Vegetation;
Resource = copyData.Resource;
ResourceUnderBuilding = copyData.ResourceUnderBuilding;
CivId = copyData.CivId;
Wonder = copyData.Wonder;
buildingLevel = copyData.buildingLevel;
NavalBasePoint = copyData.NavalBasePoint;
GeoIdList = new List<uint>();
foreach (var id in copyData.GeoIdList) GeoIdList.Add(id);
WaterRoadForceId = new bool[copyData.WaterRoadForceId.Length];
Array.Copy(copyData.WaterRoadForceId, WaterRoadForceId, copyData.WaterRoadForceId.Length);
foreach (var skill in copyData.Skills) Skills.Add(skill.GetCopySkill());
//拷贝Grid的SpTypeList
SpTypeList = new List<GridSpType>();
SpTypeList.Clear();
foreach (var SpType in copyData.SpTypeList) SpTypeList.Add(SpType);
}
public void DeepCopy(GridData copyData)
{
Pos.X = copyData.Pos.X;
Pos.Y = copyData.Pos.Y;
Id = copyData.Id;
Terrain = copyData.Terrain;
Feature = copyData.Feature;
Vegetation = copyData.Vegetation;
Resource = copyData.Resource;
ResourceUnderBuilding = copyData.ResourceUnderBuilding;
CivId = copyData.CivId;
Wonder = copyData.Wonder;
buildingLevel = copyData.buildingLevel;
NavalBasePoint = copyData.NavalBasePoint;
WaterRoadForceId = new bool[copyData.WaterRoadForceId.Length];
Array.Copy(copyData.WaterRoadForceId, WaterRoadForceId, copyData.WaterRoadForceId.Length);
GeoIdList ??= new List<uint>();
GeoIdList.Clear();
foreach (var id in copyData.GeoIdList) GeoIdList.Add(id);
//拷贝Grid的SpTypeList
SpTypeList ??= new List<GridSpType>();
SpTypeList.Clear();
foreach (var SpType in copyData.SpTypeList) SpTypeList.Add(SpType);
Skills.Clear();
foreach (var skill in copyData.Skills) Skills.Add(skill.GetCopySkill());
}
public void SetGridData(TerrainType ter,TerrainFeature fea,Vegetation veg, ResourceType res,uint civ)
{
Terrain = ter;
Feature = fea;
Vegetation = veg;
Resource = res;
ResourceUnderBuilding = ResourceType.None;
CivId = civ;
}
public bool IsRoadBridgePort()
{
return Feature == TerrainFeature.Road || Resource == ResourceType.Port || Resource == ResourceType.Bridge;
}
public Vector3 V3() => Table.Instance.GridToWorld(this,"");
public bool HasBuilding()
{
return !(Resource == ResourceType.None ||
Resource == ResourceType.Fruit ||
Resource == ResourceType.Crop ||
Resource == ResourceType.Starfish ||
Resource == ResourceType.Animal ||
Resource == ResourceType.Fish ||
Resource == ResourceType.Metal ||
Resource == ResourceType.Treasure);
}
public bool IsMainMap()
{
if (!Main.MapData.GridMap.GetGridDataByGid(Id, out var gridData)
|| gridData != this)
return false;
return true;
}
public bool InMainSight()
{
if (!IsMainMap()) return false;
return Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(Id);
}
public GridSpType GetTopGridSpType()
{
GridSpType ret = GridSpType.None;
foreach (var SpType in SpTypeList)
{
if (SpType == GridSpType.KaguyaGrid) ret = GridSpType.KaguyaGrid;
if (SpType == GridSpType.RemiliaGrid) ret = GridSpType.RemiliaGrid;
}
return ret;
}
//返回该格子周围是否存在没有视野的格子
[MemoryPackIgnore]
private List<GridData> _aroundBuffer;
public bool UnsightNearby(MapData map, PlayerData player)
{
_aroundBuffer ??= new List<GridData>();
map.GridMap.GetAroundGridData(1, 1, this, _aroundBuffer);
foreach (var grid in _aroundBuffer)
{
if (player.Sight.CheckIsInSight(grid.Id)) return true;
}
return false;
}
// 全局通知调用
public void OnTurnStart(MapData map)
{
//Step #1 处理海军点 TODO 将来要并入skill去
NavalBasePoint = 1;
//Step #2 处理kaguyaFrenchAnimal(必须是该grid玩家的回合)
if (Resource == ResourceType.KaguyaFrenchYard && map.CheckIfGidBelongPid(Id,map.CurPlayer.Id))
{
CommonColdTime++;
if (CommonColdTime >= 2)
{
_aroundBuffer ??= new List<GridData>();
map.GridMap.GetAroundGridData(1, 1, this, _aroundBuffer);
if (map.GetPlayerDataByTerritoryGridId(Id, out var player))
{
GridData spawnedAnimalGrid = null;
foreach (var grid in _aroundBuffer)
{
if (!map.GetPlayerDataByTerritoryGridId(grid.Id, out var gridPlayer)) continue;
if (gridPlayer.Id != player.Id) continue;
if (grid.Vegetation != Vegetation.Trees) continue;
if (grid.Resource != ResourceType.None) continue;
grid.Resource = ResourceType.Animal;
grid.Renderer(map)?.InstantUpdateGrid(true);
grid.Renderer(Main.MapData)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Treasure));
CommonColdTime = 0;
Main.CityLogic.UpdateGridBuildingData_LogicView(map,this);
Renderer(map)?.InstantUpdateGrid(true);
Renderer(Main.MapData)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Fog));
spawnedAnimalGrid = grid;
break;
}
//新产出的Animal也可能在其他同玩家KaguyaFrenchYard的周围(跨城市共享一片树林的情况)
//此时那些KaguyaFrenchYard的buildingLevel也需要刷新,否则CityCoinPerTurn会少算
if (spawnedAnimalGrid != null)
{
_aroundBuffer.Clear();
map.GridMap.GetAroundGridData(1, 1, spawnedAnimalGrid, _aroundBuffer);
foreach (var neighbor in _aroundBuffer)
{
if (neighbor == this) continue; //自己已经更新过
if (neighbor.Resource != ResourceType.KaguyaFrenchYard) continue;
if (!map.GetPlayerDataByTerritoryGridId(neighbor.Id, out var neighborPlayer)) continue;
if (neighborPlayer.Id != player.Id) continue;
Main.CityLogic.UpdateGridBuildingData_LogicView(map, neighbor);
}
}
}
}
}
//Step #3 处理EgyptianIrrigation(必须是该grid玩家的回合)
if (Resource == ResourceType.EgyptianIrrigation && map.CheckIfGidBelongPid(Id,map.CurPlayer.Id))
{
CommonColdTime++;
if (CommonColdTime >= 2)
{
_aroundBuffer ??= new List<GridData>();
map.GridMap.GetAroundGridData(1, 1, this, _aroundBuffer);
if (map.GetPlayerDataByTerritoryGridId(Id, out var player))
foreach (var grid in _aroundBuffer)
{
if (!map.GetPlayerDataByTerritoryGridId(grid.Id, out var gridPlayer)) continue;
if (gridPlayer.Id != player.Id) continue;
if (grid.Terrain != TerrainType.Land) continue;
if (grid.Vegetation == Vegetation.Trees) continue;
if (grid.Feature == TerrainFeature.Mountain) continue;
if (grid.Resource != ResourceType.None) continue;
grid.Resource = ResourceType.Crop;
grid.Renderer(map)?.InstantUpdateGrid(true);
grid.Renderer(Main.MapData)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Treasure));
CommonColdTime = 0;
//Main.CityLogic.UpdateGridBuildingData(map,this);
//Renderer(map)?.SetUpdateGrid(true);
//Renderer(Main.MapData)?.PlayVFX(new GridVFXParams(GridVFXType.Fog));
break;
}
}
}
//Step #4 处理RemiliaMilitary
if (Resource == ResourceType.RemiliaMilitary && map.CheckIfGidBelongPid(Id,map.CurPlayer.Id))
{
if (!HasSpType(GridSpType.RemiliaGrid))
AddSpType(GridSpType.RemiliaGrid,map,null);
Renderer(map)?.InstantUpdateGrid();
}
//Step #5 处理MetalStation
if (Resource == ResourceType.MetalStation && map.CheckIfGidBelongPid(Id,map.CurPlayer.Id))
{
CommonColdTime++;
if (CommonColdTime > 1)
{
Resource = ResourceType.Metal;
//如果有moriyaRoad科技更新连通性
if(map.CurPlayer.TechTree.CheckIfHasTechAtom(TechAtom.MoriyaRoad))
Main.PlayerLogic.UpdateCityConnect(map,map.CurPlayer);
//Step #3 播放雾效,更新画面
if (InMainSight())
{
Renderer(map)?.InstantUpdateGrid(true);
Renderer(map)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Fog));
}
}
}
//Step #6 处理所有技能
OnSkillsTurnStart(map);
}
public void OnTurnEnd(MapData map)
{
//Step #2 处理所有技能
OnSkillsTurnEnd(map);
}
//皮肤层的一些基础属性调用
public bool HasSpType(GridSpType type)
{
foreach(var t in SpTypeList)
if (t == type)
return true;
return false;
}
public bool RemoveSpType(GridSpType type,MapData map)
{
foreach(var t in SpTypeList)
if (t == type)
{
SpTypeList.Remove(t);
if (type == GridSpType.RemiliaGrid && RealUnit(map, out var unit))
{
unit.RemoveSkill(SkillType.ScarletMistRealTimeVampire,map);
}
return true;
}
return false;
}
public bool AddSpType(GridSpType type,MapData map, UnitData origin)// = null)
{
if (HasSpType(type)) return false;
if (type == GridSpType.RemiliaGrid)
{
if(Resource == ResourceType.CityCenter) return false;
if (Terrain != TerrainType.Land) return false;
}
if (type == GridSpType.LeyLine)
{
if (Resource == ResourceType.CityCenter) return false;
if (Terrain != TerrainType.Land) return false;
if (Feature == TerrainFeature.Mountain) return false;
}
SpTypeList.Add(type);
origin?.HeroTask(map)?.OnAddSpType(map, type);
//如果是remiliaGrid且是斯卡雷特帝国的单位给当前的unit填加skill
// 注意:多人允许相同 Empire 后,多名 PlayerCivId==0 玩家会同时享有此特权,符合预期保留逻辑。
if (type == GridSpType.RemiliaGrid && RealUnit(map,out var unit) && unit.Player(map,out var player) && player.PlayerCivId == 0)
{
unit.AddSkill_Legacy(SkillType.ScarletMistRealTimeVampire, map,true,-1,false,-1,false,SpecialAddSkillType.Force,0);
}
return true;
}
public GridSpType GetOnlyOneSpType()
{
if (HasSpType(GridSpType.RemiliaGrid))
return GridSpType.RemiliaGrid;
if (HasSpType(GridSpType.KaguyaGrid))
return GridSpType.KaguyaGrid;
return SpTypeList.Count > 0 ? SpTypeList[0] : GridSpType.None;
}
/*public UnitData Unit(MapData map)
{
map.GetUnitDataByGid(Id, out var unit);
return unit;
}*/
/*public bool Unit(MapData map,out UnitData unit)
{
return map.GetUnitDataByGid(Id, out unit);
}*/
public bool RealUnit(MapData map,out UnitData unit)
{
return map.GetUnitDataByGid_Core(Id, out unit);
}
//返回Grid上是否存在一个VisibleUnit非敌方隐身单位)
public bool VisibleUnit(MapData map,PlayerData player,out UnitData unit)
{
return map.GetUnitDataByGid_Core(Id, out unit) && !unit.IsHideAndCantSee(map,player);
}
//返回Grid上是否存在一个VisibleUnit非隐身单位)但是从只需要考虑selfplayer,且一定是Main.MapData
public bool MainSelfPlayerVisibleUnit(out UnitData unit)
{
return Main.MapData.GetUnitDataByGid_Core(Id, out unit) && !unit.IsHideAndCantSee(Main.MapData,Main.MapData.PlayerMap.SelfPlayerData);
}
public CityData BelongButNotOnGridCity(MapData map)
{
map.GetCityDataByTerritoryGid(Id, out var city);
return city;
}
public bool City(MapData map ,out CityData city)
{
return map.GetCityDataByTerritoryGid(Id, out city);
}
public CityData CityOnGrid(MapData map)
{
map.GetCityDataByGid(Id, out var city);
return city;
}
public bool CityOnGrid(MapData map,out CityData city)
{
return map.GetCityDataByGid(Id, out city);
}
//返回当前grid提供了多少的cityExp
public int CityExp()
{
if (!Table.Instance.GridAndResourceDataAssets.GetResourceInfo(Resource, out var resourceInfo))
return 0;
//保护区特判
if (Resource == ResourceType.Preserve && Vegetation == Vegetation.Trees)
return buildingLevel;
var levelExp = resourceInfo.HasLevel ? resourceInfo.CityExpPerLevel * buildingLevel : 0;
return levelExp + resourceInfo.Exp;
}
public GridRenderer Renderer(MapData map)
{
if (map != Main.MapData) return null;
MapRenderer.Instance.ROGridMap.TryGetValue(Id, out var renderer);
return renderer;
}
public PlayerData Player(MapData map)
{
map.GetPlayerDataByTerritoryGridId(Id, out var player);
return player;
}
public bool Player(MapData map ,out PlayerData player)
{
return map.GetPlayerDataByTerritoryGridId(Id, out player);
}
public List<uint> GetRealTimeGeoIdList()
{
var ret = new List<uint>();
foreach (var t in GeoIdList)
{
}
foreach(var t in GeoIdList)
if (Table.Instance.GeoDataAssets.GetGeoInfo(t, out var info))
{
if (info.GeoBigClass == GeoBigClass.Forest && Vegetation == Vegetation.Trees) ret.Add(info.Id);
if (info.GeoBigClass == GeoBigClass.Mountain && Feature == TerrainFeature.Mountain) ret.Add(info.Id);
//平原要剔除有山的情况,如果已经有山就不加平原信息了
if (info.GeoBigClass == GeoBigClass.Plain && Feature != TerrainFeature.Mountain) ret.Add(info.Id);
//水域要剔除有山的情况,如果已经有山就不加平原信息了
if (info.GeoBigClass == GeoBigClass.Water && Feature != TerrainFeature.Mountain)ret.Add(info.Id);
if (info.GeoBigClass == GeoBigClass.Building)
{
if (info.GeoSmallClass == GeoSmallClass.Bridge && Resource == ResourceType.Bridge) ret.Add(info.Id);
if (info.GeoSmallClass == GeoSmallClass.Port && Resource == ResourceType.Port) ret.Add(info.Id);
if (info.GeoSmallClass == GeoSmallClass.Forge && Resource == ResourceType.Forge) ret.Add(info.Id);
if (info.GeoSmallClass == GeoSmallClass.Sawmill && Resource == ResourceType.Sawmill) ret.Add(info.Id);
if (info.GeoSmallClass == GeoSmallClass.Windmill&& Resource == ResourceType.Windmill) ret.Add(info.Id);
if (info.GeoSmallClass == GeoSmallClass.Market&& Resource == ResourceType.Market) ret.Add(info.Id);
if (info.GeoSmallClass == GeoSmallClass.Mine&& Resource == ResourceType.Mine) ret.Add(info.Id);
if (info.GeoSmallClass == GeoSmallClass.NavelBase&& Resource == ResourceType.NavalBase) ret.Add(info.Id);
if (info.GeoSmallClass == GeoSmallClass.Military&& Resource == ResourceType.Military) ret.Add(info.Id);
}
}
return ret;
}
public void UpdateGeoInfo(MapData map)
{
//TODO 后续要将这个改为Action
if (Main.MapData.Net.Mode == NetMode.Multi) return;
//Step #1 检查当前GeoList的信息和 grid的实机情况是否匹配
bool bridge = false;
bool port = false;
bool forest = false;
bool mountain = false;
bool forge = false;
bool sawmill = false;
bool military = false;
bool navelbase = false;
bool windmill = false;
bool market = false;
bool mine = false;
foreach(var t in GeoIdList)
if (Table.Instance.GeoDataAssets.GetGeoInfo(t, out var info))
{
if (info.GeoBigClass == GeoBigClass.Forest) forest = true;
if (info.GeoBigClass == GeoBigClass.Mountain) mountain = true;
if (info.GeoSmallClass == GeoSmallClass.Bridge) bridge = true;
if (info.GeoSmallClass == GeoSmallClass.Port) port = true;
if (info.GeoSmallClass == GeoSmallClass.Forge) forge = true;
if (info.GeoSmallClass == GeoSmallClass.Sawmill) sawmill = true;
if (info.GeoSmallClass == GeoSmallClass.Windmill) windmill = true;
if (info.GeoSmallClass == GeoSmallClass.Market) market = true;
if (info.GeoSmallClass == GeoSmallClass.Mine) mine = true;
if (info.GeoSmallClass == GeoSmallClass.NavelBase) navelbase = true;
if (info.GeoSmallClass == GeoSmallClass.Military) military = true;
}
var smallSet = _geoSmallSetBuffer ??= new HashSet<GeoSmallClass>();
smallSet.Clear();
uint id;
if (Vegetation == Vegetation.Trees && !forest)
{
smallSet.Add(GeoSmallClass.Mangrove);
smallSet.Add(GeoSmallClass.Deciduous);
smallSet.Add(GeoSmallClass.Jungle);
smallSet.Add(GeoSmallClass.Evergreen);
smallSet.Add(GeoSmallClass.Oasis);
smallSet.Add(GeoSmallClass.Taiga);
if (Table.Instance.GeoDataAssets.GetForestGeoId(map, this, out id))
GeoIdList.Add(id);
}
if (Feature == TerrainFeature.Mountain && !mountain)
{
smallSet.Add(GeoSmallClass.Volcano);
smallSet.Add(GeoSmallClass.Mountain);
smallSet.Add(GeoSmallClass.Hill);
if (Table.Instance.GeoDataAssets.GetGeoId(CivEnum, GeoBigClass.Mountain, smallSet, out id))
GeoIdList.Add(id);
}
if (Resource == ResourceType.Bridge && !bridge) smallSet.Add(GeoSmallClass.Bridge);
if (Resource == ResourceType.Port && !port) smallSet.Add(GeoSmallClass.Port);
if (Resource == ResourceType.Forge && !forge) smallSet.Add(GeoSmallClass.Forge);
if (Resource == ResourceType.Sawmill && !sawmill) smallSet.Add(GeoSmallClass.Sawmill);
if (Resource == ResourceType.Windmill && !windmill) smallSet.Add(GeoSmallClass.Windmill);
if (Resource == ResourceType.Market && !market) smallSet.Add(GeoSmallClass.Market);
if (Resource == ResourceType.Mine && !mine) smallSet.Add(GeoSmallClass.Mine);
if (Resource == ResourceType.NavalBase && !navelbase) smallSet.Add(GeoSmallClass.NavelBase);
if (Resource == ResourceType.Military && !military) smallSet.Add(GeoSmallClass.Military);
if(smallSet.Count > 0)
if (Table.Instance.GeoDataAssets.GetGeoId(CivEnum, GeoBigClass.Building, smallSet, out id))
GeoIdList.Add(id);
}
}
// 位置基类
[MemoryPackable]
public partial class MapPosition
{
public int X;
public int Y;
public uint PosId => CalculatePosId(X, Y);
public Vector2Int V2() => new Vector2Int(X, Y);
public static uint CalculatePosId(int x, int y)
{
return (uint)(x * 1000 + y);
}
[MemoryPackConstructor]
public MapPosition()
{
X = 0;
Y = 0;
}
public MapPosition(int x,int y)
{
X = x;
Y = y;
}
public MapPosition(Vector2 v2)
{
X = (int)v2.x;
Y = (int)v2.y;
}
public void SetPosition(MapPosition pos)
{
X = pos.X;
Y = pos.Y;
}
// 重载 GetHashCode
public override int GetHashCode()
{
return HashCode.Combine(X, Y);
// 或者更简单的方式:
// return X.GetHashCode() ^ Y.GetHashCode();
}
// 重载 Equals(object)
public override bool Equals(object obj)
{
return obj is MapPosition other && Equals(other);
}
// 实现 IEquatable<MapPosition>
public bool Equals(MapPosition other)
{
if (other == null) return false;
return X == other.X && Y == other.Y;
}
// 重载 == 操作符(推荐)
public static bool operator ==(MapPosition left, MapPosition right)
{
if (ReferenceEquals(left, right)) return true;
if (left is null || right is null) return false;
return left.Equals(right);
}
// 重载 != 操作符(推荐)
public static bool operator !=(MapPosition left, MapPosition right)
{
return !(left == right);
}
}
}