TH1/Unity/Assets/Scripts/TH1_Data/PlayerData.cs

1466 lines
53 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 ET;
using Logic.Action;
using Logic.AI;
using Logic.Skill;
using MemoryPack;
using TH1_Core.Managers;
using TH1_Logic.Core;
using TH1_Logic.HeroTask;
using TH1Renderer;
using UnityEngine;
namespace RuntimeData
{
// 奇观类型枚举
public enum WonderTypeEnum
{
None,
PEACE,
KNOWLEDGE,
TRADE,
WEALTH,
POWER,
PARK,
EYE
}
// 奇观状态枚举
public enum WonderState
{
NO_HINT,
HAVE_HINT,
FINISH_NOT_BUILD,
FINISH_BUILD,
Max
}
// 外交关系枚举
public enum DiplomacyState
{
NoDiplomacy,
Neutral,
League,
War,
LeagueRupture,
}
// 好感状态枚举
public enum FeelingState
{
Trust,
Appreciate,
Indifferent,
Suspicion,
Terrible,
}
// 好感策略枚举
public enum FeelingStrategy
{
Wise,
Charming,
Peaceful,
Diplomatic,
Powerful,
Brave,
Violent,
Threatening,
Weak,
Annoying,
Foolish,
Intrusive,
Dominative,
}
[MemoryPackable]
public partial class PlayerMapData
{
public List<PlayerData> PlayerDataList;
[MemoryPackIgnore]
public uint SelfPlayerId;
[MemoryPackIgnore]
public PlayerData SelfPlayerData => GetPlayerData(SelfPlayerId);
private Dictionary<uint, PlayerData> _playerDataDict;
// 无数据初始化
[MemoryPackConstructor]
public PlayerMapData()
{
PlayerDataList = new List<PlayerData>();
_playerDataDict = new Dictionary<uint, PlayerData>();
}
// 配置初始化
public PlayerMapData(MapData map, MapIdGenerator idGenerator, NetMode netMode)
{
PlayerDataList = new List<PlayerData>();
_playerDataDict = new Dictionary<uint, PlayerData>();
if (netMode == NetMode.Single)
{
for (int i = 0; i < map.MapConfig.PlayerCount; i++)
{
PlayerData player;
//处理player到底是谁的问题。目前临时使用的方案今后要改。目前civ一定=force,所以可以这么做
if (i == 0)
player = new PlayerData(map.MapConfig.selfCivId,map.MapConfig.selfForceId,idGenerator);
else if (map.MapConfig.selfCivId == i)
player = new PlayerData((uint)0,(uint)0,idGenerator);
else
player = new PlayerData((uint)i,(uint)i,idGenerator);
PlayerDataList.Add(player);
_playerDataDict[player.Id] = player;
}
}
if (netMode == NetMode.Multi)
{
// 这里 civList 要包含所有 civId
var civList = new List<uint>();
for (int i = 0; i < 8; i++) civList.Add((uint)i);
foreach (var multiCiv in map.MapConfig.MultiCivs)
{
var player = new PlayerData(multiCiv.CivId, multiCiv.CivId, idGenerator);
PlayerDataList.Add(player);
_playerDataDict[player.Id] = player;
civList.Remove(multiCiv.CivId);
multiCiv.PlayerId = player.Id;
}
for (int i = map.MapConfig.MultiCivs.Count; i < map.MapConfig.PlayerCount; i++)
{
int idx = UnityEngine.Random.Range(0, civList.Count);//map.Net.GetRandom().Next
var civId = civList[idx];
var player = new PlayerData(civId, civId, idGenerator);
PlayerDataList.Add(player);
_playerDataDict[player.Id] = player;
civList.RemoveAt(idx);
}
}
foreach (var player in PlayerDataList)
{
//从player的初始科技树获取信息为player设置初始skill
if (Table.Instance.PlayerDataAssets.GetPlayerInfo(player, out var info))
{
foreach (var t in info.TechStart)
{
if(!Table.Instance.TechDataAssets.GetTechInfo(t, out var techInfo))continue;
foreach(var a in techInfo.techActions)
if (a.ActionType == CommonActionType.UnitSkill)
{
if(a.SkillType is SkillType.KaguyaFrenchNapoleonicCode or SkillType.CommonPlayerSkillIndustry or SkillType.RemiliaForcesSkill1)
player.AddSkill(a.SkillType);
}
}
}
}
SelfPlayerId = PlayerDataList[0].Id;
foreach (var self in PlayerDataList)
{
foreach (var target in PlayerDataList)
{
if (self.Id == target.Id) continue;
self.DiplomacyData.AddCountryDiplomacyInfo(target.Id);
}
}
}
public PlayerMapData(PlayerMapData copyData)
{
PlayerDataList = new List<PlayerData>();
_playerDataDict = new Dictionary<uint, PlayerData>();
SelfPlayerId = copyData.SelfPlayerId;
foreach (var copyPlayer in copyData.PlayerDataList)
{
var player = new PlayerData(copyPlayer);
PlayerDataList.Add(player);
_playerDataDict[player.Id] = player;
}
}
public void DeepCopy(PlayerMapData copyData)
{
_playerDataDict.Clear();
SelfPlayerId = copyData.SelfPlayerId;
for (int i = 0; i < copyData.PlayerDataList.Count; i++)
{
var copyPlayer = copyData.PlayerDataList[i];
if (i >= PlayerDataList.Count)
{
var player = new PlayerData(copyPlayer);
PlayerDataList.Add(player);
_playerDataDict[player.Id] = player;
}
else
{
PlayerDataList[i].DeepCopy(copyPlayer);
_playerDataDict[PlayerDataList[i].Id] = PlayerDataList[i];
}
}
for (int i = PlayerDataList.Count - 1; i >= copyData.PlayerDataList.Count; i--)
{
_playerDataDict.Remove(PlayerDataList[i].Id);
PlayerDataList.RemoveAt(i);
}
}
// MemoryPack 反序列化之后的后处理
[MemoryPackOnDeserialized]
public void OnAfterMemoryPackDeserialize()
{
_playerDataDict ??= new Dictionary<uint, PlayerData>();
_playerDataDict.Clear();
foreach (var player in PlayerDataList) _playerDataDict[player.Id] = player;
}
// 根据 pid 获取玩家数据
public bool GetPlayerDataByPlayerID(uint pid, out PlayerData playerData)
{
return _playerDataDict.TryGetValue(pid, out playerData);
}
//用于经典模式判断是否已经抵达31回合从而结束游戏
public bool CheckTimeEnd()
{
return false;
if(SelfPlayerData.Turn == 61)
return true;
return false;
}
// 判断自己是否失败
public bool CheckSelfLose()
{
return !SelfPlayerData.Alive;
}
public PlayerData GetPlayerData(uint id)
{
if (_playerDataDict.TryGetValue(id, out var playerData))
{
return playerData;
}
return null;
}
public void OnTurnStart(MapData map, PlayerData player)
{
Main.PlayerLogic.StartNextTurn(map, player);
player.OnTurnStart(map);
}
public void OnTurnEnd(MapData map, PlayerData player)
{
Main.PlayerLogic.EndThisTurn(map, player);
player.OnTurnEnd(map);
}
}
[MemoryPackable]
public partial class PlayerData : IdentifierBase
{
// 文明 id, 阵营 id, 摇篮城市 id
public uint Turn;
public uint PlayerCivId;
public uint PlayerForceId;
public uint CradleCityId;
// 是否存活
public bool Alive;
// 财富总额
public int PlayerWealth;
public int PlayerTechPoint;
//分数
public int PlayerScore;
// 视野
public MapSightData Sight;
// 科技
public TechTreeData TechTree;
// 奇观
public WonderData Wonder;
// 外交
public DiplomacyData DiplomacyData;
//英雄
public PlayerHeroData PlayerHeroData;
//命名器
public PlayerNamerData PlayerNamerData;
// 用于记录已经连续几个 turn 没有进行攻击
public int TurnNoAttack;
// 用于记录累计击杀多少 unit
public int TotalKill;
// 英雄
private bool _heroDictInit;
//记录伟人的累计经验,下标直接从ChessType的Enum对应的uint转过来
public int[] giantExp = new int[6];
//记录伟人的复活冷却cd惩罚
public int[] giantPenalty = new int[6];
public List<uint> MeetPlayers;
public List<uint> CurAttackPlayers;
public List<uint> LastAttackPlayers;
//用于记录是否死亡是否要centMessage来宣告死亡信息
public bool DieMark = false;
//用于记录当前是否正在playing主要是视觉那边使用
public bool IsPlaying;
// 用以绑定开始游戏时的 Steam ID
public ulong SteamID;
// 无参数初始化
[MemoryPackConstructor]
public PlayerData()
{
Sight = new MapSightData();
TechTree = new TechTreeData();
Wonder = new WonderData();
DiplomacyData = new DiplomacyData();
MeetPlayers = new List<uint>();
CurAttackPlayers = new List<uint>();
LastAttackPlayers = new List<uint>();
PlayerNamerData = new PlayerNamerData();
SteamID = 0;
}
// 带 ID 初始化
public PlayerData(uint civId, uint forceId, MapIdGenerator idGenerator)
{
Turn = 0;
Id = idGenerator.GeneratorId();
if(Table.Instance.PlayerDataAssets.GetPlayerInfoByCivId(civId,forceId,out var info))
TechTree = new TechTreeData(info.TechStart);
else
TechTree = new TechTreeData();
Sight = new MapSightData();
Wonder = new WonderData();
DiplomacyData = new DiplomacyData();
PlayerHeroData = new PlayerHeroData();
CurAttackPlayers = new List<uint>();
LastAttackPlayers = new List<uint>();
PlayerNamerData = new PlayerNamerData();
MeetPlayers = new List<uint>();
MeetPlayers.Add(Id);
InitData(civId,forceId);
SteamID = 0;
}
public PlayerData(PlayerData copyData)
{
Turn = copyData.Turn;
Id = copyData.Id;
PlayerCivId = copyData.PlayerCivId;
PlayerForceId = copyData.PlayerForceId;
CradleCityId = copyData.CradleCityId;
Alive = copyData.Alive;
PlayerWealth = copyData.PlayerWealth;
PlayerTechPoint = copyData.PlayerTechPoint;
Sight = new MapSightData(copyData.Sight);
TechTree = new TechTreeData(copyData.TechTree);
Wonder = new WonderData(copyData.Wonder);
DiplomacyData = new DiplomacyData(copyData.DiplomacyData);
PlayerHeroData = new PlayerHeroData(copyData.PlayerHeroData);
PlayerNamerData = new PlayerNamerData(copyData.PlayerNamerData);
CurAttackPlayers = new List<uint>();
foreach (var id in copyData.CurAttackPlayers) CurAttackPlayers.Add(id);
LastAttackPlayers = new List<uint>();
foreach (var id in copyData.LastAttackPlayers) LastAttackPlayers.Add(id);
MeetPlayers = new List<uint>();
foreach (var id in copyData.MeetPlayers) MeetPlayers.Add(id);
TurnNoAttack = copyData.TurnNoAttack;
TotalKill = copyData.TotalKill;
foreach (var skill in copyData.Skills) Skills.Add(skill.GetCopySkill());
//拷贝giantExp和giantPenalty
for (int i = 0; i < 6; i++)
{
giantExp[i] = copyData.giantExp[i];
giantPenalty[i] = copyData.giantPenalty[i];
}
SteamID = copyData.SteamID;
}
public void DeepCopy(PlayerData copyData)
{
Turn = copyData.Turn;
Id = copyData.Id;
PlayerCivId = copyData.PlayerCivId;
PlayerForceId = copyData.PlayerForceId;
CradleCityId = copyData.CradleCityId;
Alive = copyData.Alive;
PlayerWealth = copyData.PlayerWealth;
PlayerTechPoint = copyData.PlayerTechPoint;
Sight.DeepCopy(copyData.Sight);
TechTree.DeepCopy(copyData.TechTree);
Wonder.DeepCopy(copyData.Wonder);
DiplomacyData.DeepCopy(copyData.DiplomacyData);
PlayerHeroData.DeepCopy(copyData.PlayerHeroData);
PlayerNamerData.DeepCopy(copyData.PlayerNamerData);
CurAttackPlayers.Clear();
foreach (var id in copyData.CurAttackPlayers) CurAttackPlayers.Add(id);
LastAttackPlayers.Clear();
foreach (var id in copyData.LastAttackPlayers) LastAttackPlayers.Add(id);
MeetPlayers.Clear();
foreach (var id in copyData.MeetPlayers) MeetPlayers.Add(id);
TurnNoAttack = copyData.TurnNoAttack;
TotalKill = copyData.TotalKill;
foreach (var skill in copyData.Skills)
{
AddSkill(skill.GetSkillType());
if (!GetSkill(skill.GetSkillType(), out var selfSkill)) continue;
selfSkill.DeepCopy(skill);
}
for (int i = Skills.Count - 1; i >= 0; i--)
{
if (copyData.GetSkill(Skills[i].GetSkillType(), out _)) continue;
Skills.RemoveAt(i);
}
for (int i = 0; i < 6; i++)
{
giantExp[i] = copyData.giantExp[i];
giantPenalty[i] = copyData.giantPenalty[i];
}
SteamID = copyData.SteamID;
}
private void InitData(uint civId,uint forceId)
{
Alive = true;
PlayerWealth = 5;
PlayerCivId = civId;
PlayerForceId = forceId;
PlayerTechPoint = 0;
TurnNoAttack = 0;
TotalKill = 0;
PlayerHeroData.Init(Table.Instance.TransCivIdToCivEnum(civId) ,Table.Instance.TransForceIdToForceEnum(forceId));
PlayerNamerData.Init(Table.Instance.TransCivIdToCivEnum(civId));
}
// 全局通知调用
public void OnTurnStart(MapData map)
{
Turn++;
//减少1点伟人复活冷却的时间点
for (int i = 0; i < 6; i++)
if (giantPenalty[i] > 0) giantPenalty[i]--;
LastAttackPlayers.Clear();
foreach (var id in CurAttackPlayers) LastAttackPlayers.Add(id);
CurAttackPlayers.Clear();
for (int i = Skills.Count - 1; i >= 0; i--)
{
var skill = Skills[i];
if (skill.IsFinished())
{
Skills.RemoveAt(i);
continue;
}
skill.OnTurnStart(this, map);
}
// 刷新好感
RefreshFeelingValue(map);
// 刷新外交
RefreshDiplomacyState(map);
IsPlaying = true;
//更新所有单位的视觉状态 TODO 之后依赖大回合的逻辑处理
foreach (var unit in map.UnitMap.UnitList)
unit.Renderer(map)?.InstantUpdateUnit(true);
}
public void OnTurnEnd(MapData map)
{
foreach (var skill in Skills)skill.OnTurnEnd(this, map);
foreach (var player in map.PlayerMap.PlayerDataList)
{
if (player.Id == Id) continue;
this.GetCountryDiplomacyInfo(player.Id, out var selfToPlayer);
// 回合结束处理联盟破裂标记
if (selfToPlayer.DiplomacyState == DiplomacyState.LeagueRupture) selfToPlayer.IsLeagueRupture = true;
// 回合结束处理AI 冷静期计数
if (selfToPlayer.IsCalm > 0) selfToPlayer.IsCalm--;
}
IsPlaying = false;
}
public bool IsSelfPlayer()
{
return Main.MapData.PlayerMap.SelfPlayerData == this;
}
// 添加当前回合攻击者
public void AddAttacker(uint playerId)
{
this.AddTurnAttacker(playerId, Turn);
}
public CivEnum Civ()
{
return Table.Instance.TransCivIdToCivEnum(PlayerCivId);
}
//增加金币(目前处理了逻辑和动画 TODO 现在还是逻辑和动画没有分开,后续还是要分开
public void AddCoin(int coin,GridData grid = null)
{
PlayerWealth += coin;
//如果加钱的是真人自己玩家并且有金币来源位置那么播动画。暂时用legacy方案
if (Main.MapData.PlayerMap.SelfPlayerData == this && grid != null)
{
var startPos = Table.Instance.GridToWorld(grid);
var moneyPanel = GameObject.Find("UICanvas/TopBarPanel/MoneyPanel/Icon").transform;
var endPos = moneyPanel.position;
MapRenderer.Instance.ProjectileManager.CreateProjectileMulti(startPos,endPos,ProjectileType.Coin,ProjectileMoveType.CoinParabola,coin,0.05f);
}
}
//增加faith的动画目前处理了逻辑和动画 TODO 现在还是逻辑和动画没有分开,后续还是要分开
public void AddFaith(int faith,GridData grid = null)
{
//如果加钱的是真人自己玩家并且有金币来源位置那么播动画。暂时用legacy方案
if (Main.MapData.PlayerMap.SelfPlayerData == this && grid != null)
{
var startPos = Table.Instance.GridToWorld(grid);
var faithPanel = GameObject.Find("UICanvas/TopBarPanel/FaithPanel/Icon").transform;
MapRenderer.Instance.ProjectileManager.CreateProjectile(startPos,faithPanel.position,ProjectileType.Faith,ProjectileMoveType.CoinParabola,faith);
}
}
// 检查前几回合内是否有攻击者
public bool CheckTurnsAttacker(uint turns, uint playerId)
{
if (turns >= Turn) turns = Turn;
return this.CheckTurnAttacker(playerId, Turn - turns);
}
// 刷新对他国好感值
public void RefreshFeelingValue(MapData map)
{
int maxScore = -1;
uint maxScorePlayer = 0;
foreach (var player in map.PlayerMap.PlayerDataList)
{
if (!player.Alive) continue;
if (player.PlayerScore <= maxScore) continue;
maxScore = player.PlayerScore;
maxScorePlayer = player.Id;
}
var originCity = new HashSet<uint>();
foreach (var player in map.PlayerMap.PlayerDataList)
{
originCity.Add(player.CradleCityId);
}
foreach (var player in map.PlayerMap.PlayerDataList)
{
if (!player.Alive) continue;
if (player.Id == Id) continue;
this.GetCountryDiplomacyInfo(player.Id, out var selfToPlayer);
player.GetCountryDiplomacyInfo(Id, out var playerToSelf);
selfToPlayer.FeelingStrategyList.Clear();
if (playerToSelf == null || selfToPlayer == null) continue;
var score = 50f;
// 明智的 愚蠢的
var score1 = 0f;
foreach (var otherPlayer in map.PlayerMap.PlayerDataList)
{
if (!player.Alive) continue;
if (otherPlayer.Id == Id || otherPlayer.Id == player.Id) continue;
this.GetCountryDiplomacyInfo(otherPlayer.Id, out var selfToOtherPlayer);
if (selfToOtherPlayer.DiplomacyState == DiplomacyState.NoDiplomacy) continue;
player.GetCountryDiplomacyInfo(otherPlayer.Id, out var playerToOtherPlayer);
if (playerToOtherPlayer.DiplomacyState == DiplomacyState.NoDiplomacy) continue;
if (selfToOtherPlayer.DiplomacyState == playerToOtherPlayer.DiplomacyState) score1 += 5;
else score1 -= 5;
}
if (score1> 0)
{
score1 += 5;
score += Mathf.Min(20, score1);
selfToPlayer.FeelingStrategyList.Add(FeelingStrategy.Wise);
}
if (score1 < 0)
{
score1 -= 5;
score += Mathf.Max(-20, score1);
selfToPlayer.FeelingStrategyList.Add(FeelingStrategy.Foolish);
}
// 迷人的 恼人的
if (map.MapConfig.AIDiff == AIDifficult.EASY && map.CheckIsPlayer(player.Id) && map.CheckIsAI(Id))
{
score += 15;
selfToPlayer.FeelingStrategyList.Add(FeelingStrategy.Charming);
}
if (map.MapConfig.AIDiff == AIDifficult.LUNATIC && map.CheckIsPlayer(player.Id) && map.CheckIsAI(Id))
{
score -= 15;
selfToPlayer.FeelingStrategyList.Add(FeelingStrategy.Annoying);
}
// 和平的 暴力的
if (!CheckTurnsAttacker(3, player.Id))
{
score += 15;
selfToPlayer.FeelingStrategyList.Add(FeelingStrategy.Peaceful);
}
else
{
score -= 15;
selfToPlayer.FeelingStrategyList.Add(FeelingStrategy.Violent);
}
// 外交的
if (selfToPlayer.IsEmbassy || playerToSelf.IsEmbassy)
{
score += 15;
selfToPlayer.FeelingStrategyList.Add(FeelingStrategy.Diplomatic);
}
// 强大的 弱小的
var selfScore = 0f;
var playerScore = 0f;
var selfUnit = new HashSet<UnitData>();
map.GetUnitDataListByPlayerId(Id, selfUnit);
var targetUnit = new HashSet<UnitData>();
map.GetUnitDataListByPlayerId(player.Id, targetUnit);
foreach (var unit in selfUnit) selfScore += unit.GetMilitary();
foreach (var unit in targetUnit) playerScore += unit.GetMilitary();
if (selfScore < playerScore)
{
score += 15;
selfToPlayer.FeelingStrategyList.Add(FeelingStrategy.Powerful);
}
if (selfScore > playerScore)
{
score -= 15;
selfToPlayer.FeelingStrategyList.Add(FeelingStrategy.Weak);
}
// 勇敢的
if (maxScorePlayer != Id)
{
player.GetCountryDiplomacyInfo(maxScorePlayer, out var playerToMaxScorePlayer);
if (playerToMaxScorePlayer != null && playerToMaxScorePlayer.DiplomacyState == DiplomacyState.War)
{
score += 15;
selfToPlayer.FeelingStrategyList.Add(FeelingStrategy.Brave);
}
}
// 威胁的
var playerUnit = new HashSet<UnitData>();
map.GetUnitDataListByPlayerId(player.Id, playerUnit);
var selfTerritory = map.GetPlayerTerritoryGridIdSet(Id);
foreach (var gridId in selfTerritory)
{
if (!map.GridMap.GetGridDataByGid(gridId, out var gridData)) continue;
foreach (var unit in playerUnit)
{
if (!map.GetGridDataByUnitId(unit.Id, out var unitGrid)) continue;
var dis = map.GridMap.CalcDistance(unitGrid, gridData);
if (dis > 1) continue;
score -= 15;
selfToPlayer.FeelingStrategyList.Add(FeelingStrategy.Threatening);
break;
}
if (selfToPlayer.FeelingStrategyList.Contains(FeelingStrategy.Threatening)) break;
}
// 侵略的
var playerTerritory = map.GetPlayerTerritoryGridIdSet(player.Id);
foreach (var playerGridId in playerTerritory)
{
if (!map.GridMap.GetGridDataByGid(playerGridId, out var playerGrid)) continue;
foreach (var selfGridId in selfTerritory)
{
if (!map.GridMap.GetGridDataByGid(selfGridId, out var selfGrid)) continue;
var dis = map.GridMap.CalcDistance(playerGrid, selfGrid);
if (dis > 1) continue;
score -= 15;
selfToPlayer.FeelingStrategyList.Add(FeelingStrategy.Intrusive);
break;
}
if (selfToPlayer.FeelingStrategyList.Contains(FeelingStrategy.Intrusive)) break;
}
// 主宰的
var count = 0f;
if (maxScorePlayer == player.Id)
{
var otherCity = new List<CityData>();
map.GetCityDataListByPlayerId(player.Id, otherCity);
foreach (var city in otherCity)
{
if (originCity.Contains(city.Id)) count++;
}
if (count >= originCity.Count * 0.5f)
{
score -= 15;
selfToPlayer.FeelingStrategyList.Add(FeelingStrategy.Dominative);
}
}
score = Mathf.Max(0, score);
selfToPlayer.FeelingValue = score;
if (score <= 10) selfToPlayer.FeelingState = FeelingState.Terrible;
else if (score <= 30) selfToPlayer.FeelingState = FeelingState.Suspicion;
else if (score <= 60) selfToPlayer.FeelingState = FeelingState.Indifferent;
else if (score <= 85) selfToPlayer.FeelingState = FeelingState.Appreciate;
else if (score <= 100) selfToPlayer.FeelingState = FeelingState.Trust;
}
}
// 刷新对他国的外交关系,回合开始时调用
public void RefreshDiplomacyState(MapData map)
{
foreach (var player in map.PlayerMap.PlayerDataList)
{
if (!player.Alive) continue;
if (player.Id == Id) continue;
this.GetCountryDiplomacyInfo(player.Id, out var selfToPlayer);
player.GetCountryDiplomacyInfo(Id, out var playerToSelf);
// 如果没有外交关系,且没有见过面,则设置为无外交关系
if (!MeetPlayers.Contains(player.Id)) selfToPlayer.DiplomacyState = DiplomacyState.NoDiplomacy;
// 如果没有外交关系,且见过面,则设置为中立
else if (selfToPlayer.DiplomacyState == DiplomacyState.NoDiplomacy)
selfToPlayer.DiplomacyState = DiplomacyState.Neutral;
// 如果上一回合回合内双方未发生战斗,则该回合开始时变为中立关系
//判断有没有对方单位站在我方city上
bool otherPlayerOnSelfCity = false;
var cityList = new HashSet<CityData>();
map.GetCityDataListByPlayerId(Id,cityList);
foreach (var city in cityList)
{
if(!map.GetGridDataByCityId(city.Id,out var grid))continue;
if(!map.GetUnitDataByGid(grid.Id,out var unit))continue;
if(!map.GetPlayerDataByUnitId(unit.Id,out var tPlayer))continue;
if (tPlayer.Id == player.Id)
{
otherPlayerOnSelfCity = true;
break;
}
}
if (selfToPlayer.DiplomacyState == DiplomacyState.War && !LastAttackPlayers.Contains(player.Id) && !otherPlayerOnSelfCity)
selfToPlayer.DiplomacyState = DiplomacyState.Neutral;
// 联盟破裂转中立
if (selfToPlayer.DiplomacyState == DiplomacyState.LeagueRupture &&
playerToSelf.DiplomacyState == DiplomacyState.LeagueRupture &&
selfToPlayer.IsLeagueRupture && playerToSelf.IsLeagueRupture)
{
selfToPlayer.DiplomacyState = DiplomacyState.Neutral;
playerToSelf.DiplomacyState = DiplomacyState.Neutral;
selfToPlayer.IsLeagueRupture = false;
playerToSelf.IsLeagueRupture = false;
}
}
}
}
// 奇观信息
[MemoryPackable]
public partial class WonderData
{
// 所有奇观信息
public Dictionary<WonderTypeEnum, WonderState> WonderInfoDict;
public HashSet<WonderTypeEnum> WonderRenderMark;
[MemoryPackConstructor]
public WonderData()
{
WonderInfoDict = new Dictionary<WonderTypeEnum, WonderState>();
WonderRenderMark = new HashSet<WonderTypeEnum>();
foreach (WonderTypeEnum wonderType in System.Enum.GetValues(typeof(WonderTypeEnum)))
WonderInfoDict[wonderType] = WonderState.NO_HINT;
}
public WonderData(WonderData copyData)
{
WonderInfoDict = new Dictionary<WonderTypeEnum, WonderState>(copyData.WonderInfoDict);
WonderRenderMark = new HashSet<WonderTypeEnum>(copyData.WonderRenderMark);
foreach (var kv in copyData.WonderInfoDict)
{
WonderInfoDict[kv.Key] = kv.Value;
}
foreach (var typeEnum in copyData.WonderRenderMark) WonderRenderMark.Add(typeEnum);
}
public void DeepCopy(WonderData copyData)
{
WonderInfoDict.Clear();
WonderRenderMark.Clear();
foreach (var kv in copyData.WonderInfoDict) WonderInfoDict[kv.Key] = kv.Value;
foreach (var typeEnum in copyData.WonderRenderMark) WonderRenderMark.Add(typeEnum);
}
// 获取某个奇观的状态
public WonderState GetWonderState(WonderTypeEnum wonderType)
{
if (WonderInfoDict.TryGetValue(wonderType, out var state))
{
return state;
}
return WonderState.NO_HINT;
}
public void SetWonderState(WonderTypeEnum wonderType, WonderState state)
{
WonderInfoDict[wonderType] = state;
WonderRenderMark.Add(wonderType);
}
// 判断某个奇观是否变动
public bool IsWonderRenderMark(WonderTypeEnum wonderType)
{
return WonderRenderMark.Contains(wonderType);
}
}
// 视野信息
[MemoryPackable]
public partial class MapSightData
{
public HashSet<uint> SightGidSet;
[MemoryPackConstructor]
public MapSightData()
{
SightGidSet = new HashSet<uint>();
}
public MapSightData(MapSightData copyData)
{
SightGidSet = new HashSet<uint>(copyData.SightGidSet);
}
public void DeepCopy(MapSightData copyData)
{
SightGidSet.Clear();
foreach (var gid in copyData.SightGidSet) SightGidSet.Add(gid);
}
// 判断是否在视野内
public bool CheckIsInSight(uint gid)
{
return SightGidSet.Contains(gid);
}
//更新unit移动路径上的视野 便捷版 unit在gridpos上 更新视野
public bool UpdateSightByPath(UnitData unit,PlayerData player,Vector2Int pos,MapData map)
{
if (!map.GridMap.GetGridDataByPos(pos.x, pos.y, out var grid))
{
Debug.Log("错误!UpdateSightByPath 时无法通过x,y获得grid");
return false;
}
var range = unit?.GetSightRange(map,grid) ?? 1;
var list = map.GridMap.GetAroundGridIdList(range,grid);
var count = Main.PlayerLogic.UpdateSight_LogicView(map, player, list);
unit.HeroTask(map)?.OnExploredGrids(map, count);
return true;
}
}
// 科技信息
[MemoryPackable]
public partial class TechTreeData
{
public HashSet<TechType> TechSet;
[MemoryPackIgnore] public HashSet<uint> TechActionCacheSet;
[MemoryPackIgnore] public HashSet<TechAtom> TechAtomCacheSet;
[MemoryPackConstructor]
public TechTreeData()
{
TechSet = new HashSet<TechType>();
TechActionCacheSet = new HashSet<uint>();
TechAtomCacheSet = new HashSet<TechAtom>();
}
public TechTreeData(List<TechType> startTechList = null)
{
TechSet = new HashSet<TechType>();
TechActionCacheSet = new HashSet<uint>();
TechAtomCacheSet = new HashSet<TechAtom>();
if (startTechList != null)
{
foreach(var t in startTechList) LearnTech(t);
}
}
public TechTreeData(TechTreeData copyData)
{
TechSet = new HashSet<TechType>(copyData.TechSet);
TechActionCacheSet = new HashSet<uint>(copyData.TechActionCacheSet);
TechAtomCacheSet = new HashSet<TechAtom>(copyData.TechAtomCacheSet);
}
// MemoryPack 反序列化之后的后处理
[MemoryPackOnDeserialized]
public void OnAfterMemoryPackDeserialize()
{
TechActionCacheSet ??= new HashSet<uint>();
foreach (var tech in TechSet)
{
var techInfo = Table.Instance.TechDataAssets.GetTechInfo(tech);
foreach (var techItem in techInfo.techActions)
TechActionCacheSet.Add(techItem.Id);
foreach (var techAtom in techInfo.TechAtomList)
{
TechAtomCacheSet.Add(techAtom);
if (!Table.Instance.TechDataAssets.GetTechAtomInfo(techAtom, out var info)) continue;
if(info.EnableAction)
foreach(var t in info.TechActions)
TechActionCacheSet.Add(t.Id);
}
}
}
public void DeepCopy(TechTreeData copyData)
{
TechSet.Clear();
TechActionCacheSet.Clear();
foreach (var tech in copyData.TechSet) TechSet.Add(tech);
foreach (var act in copyData.TechActionCacheSet) TechActionCacheSet.Add(act);
foreach (var atom in copyData.TechAtomCacheSet) TechAtomCacheSet.Add(atom);
}
public void LearnTech(TechType techType)
{
TechSet.Add(techType);
var techInfo = Table.Instance.TechDataAssets.GetTechInfo(techType);
foreach (var act in techInfo.techActions) TechActionCacheSet.Add(act.Id);
foreach (var techAtom in techInfo.TechAtomList)
{
TechAtomCacheSet.Add(techAtom);
if (!Table.Instance.TechDataAssets.GetTechAtomInfo(techAtom, out var info)) continue;
if(info.EnableAction)
foreach(var t in info.TechActions)
TechActionCacheSet.Add(t.Id);
}
}
// 删除科技
public void RemoveTech(TechType techType)
{
TechSet.Remove(techType);
}
// 是否拥有某个科技
public bool CheckIfHasTech(TechType techType) { return TechSet.Contains(techType); }
public bool CheckIfHasTech(List<TechType> techType)
{
foreach (var tech in techType)
if (CheckIfHasTech(tech))
return true;
return false;
}
//是否拥有某个原子科技
public bool CheckIfHasTechAtom(TechAtom atom) { return TechAtomCacheSet.Contains(atom); }
public bool HasAllTech(PlayerData player)
{
bool ret = true;
Table.Instance.PlayerDataAssets.GetPlayerInfo(player, out var info);
foreach (TechType tech in info.TechPool)
{
var techInfo = Table.Instance.TechDataAssets.GetTechInfo(tech);
if (CheckIfHasTech(tech))
continue;
ret = false;
break;
}
return ret;
}
public int GetScore()
{
int ret = 0;
foreach (var tech in TechSet)
{
var techInfo = Table.Instance.TechDataAssets.GetTechInfo(tech);
ret += techInfo.CostLevel * 100;
}
return ret;
}
public bool CheckActionCan(CommonActionId actionId)
{
if (!Table.Instance.ActionDataAssets.GetActionInfo(actionId, out var info)) return false;
if (info.NoNeedTech) return true;
return TechActionCacheSet.Contains(actionId.Id);
}
public bool CheckIfTechUnsee(TechType techType)
{
return !HasFatherTech(Table.Instance.TechDataAssets.GetTechInfo(techType).FatherTechList);
}
private bool HasFatherTech(List<TechType> techList)
{
foreach(var tech in techList)
if (TechSet.Contains(tech))
return true;
return false;
}
public bool CheckIfTechCanLearn(TechType techType)
{
//Debug.Log(techType);
return !TechSet.Contains(techType) && !CheckIfTechUnsee(techType);
}
}
// 主动攻击我的敌人信息
[MemoryPackable]
public partial class DiplomacyData
{
public List<CountryDiplomacyInfo> Info;
private Dictionary<uint, CountryDiplomacyInfo> _infoDict;
[MemoryPackConstructor]
public DiplomacyData()
{
Info = new List<CountryDiplomacyInfo>();
}
public DiplomacyData(DiplomacyData copyData)
{
Info = new List<CountryDiplomacyInfo>();
}
// MemoryPack 反序列化之后的后处理
[MemoryPackOnDeserialized]
public void OnAfterMemoryPackDeserialize()
{
Refresh();
}
public void DeepCopy(DiplomacyData copyData)
{
for (int i = 0; i < copyData.Info.Count; i++)
{
if (Info.Count <= i) Info.Add(new CountryDiplomacyInfo());
Info[i].DeepCopy(copyData.Info[i]);
}
}
public bool CheckTurnAttacker(uint selfId, uint targetId, uint turn)
{
GetCountryDiplomacyInfo(selfId, targetId, out var info);
if (info == null) return false;
return info.AttackTurn != 0 && info.AttackTurn >= turn;
}
public void AddTurnAttacker(uint selfId, uint targetId, uint turn)
{
GetCountryDiplomacyInfo(selfId, targetId, out var info);
if (info == null) return;
info.AttackTurn = turn;
}
public void AddCountryDiplomacyInfo(uint targetId)
{
Refresh();
if (_infoDict.ContainsKey(targetId)) return;
var info = new CountryDiplomacyInfo { PlayerId = targetId };
Info.Add(info);
}
public bool GetCountryDiplomacyInfo(uint selfId, uint targetId, out CountryDiplomacyInfo info)
{
info = null;
if (selfId == targetId) return false;
Refresh();
return _infoDict.TryGetValue(targetId, out info);
}
private void Refresh()
{
if (_infoDict == null) _infoDict = new Dictionary<uint, CountryDiplomacyInfo>();
if (_infoDict.Count == Info.Count) return;
_infoDict.Clear();
foreach (var countryDiplomacy in Info) _infoDict[countryDiplomacy.PlayerId] = countryDiplomacy;
}
}
public static class DiplomacyDataExtensions
{
public static bool GetCountryDiplomacyInfo(this PlayerData player, uint targetId, out CountryDiplomacyInfo info)
{
return player.DiplomacyData.GetCountryDiplomacyInfo(player.Id, targetId, out info);
}
public static void GetCountryDiplomacyInfo(this PlayerData player, PlayerData targetPlayer, out CountryDiplomacyInfo info)
{
player.DiplomacyData.GetCountryDiplomacyInfo(player.Id, targetPlayer.Id, out info);
}
public static void AddTurnAttacker(this PlayerData player, uint targetId, uint turn)
{
player.DiplomacyData.AddTurnAttacker(player.Id, targetId, turn);
}
public static void AddTurnAttacker(this PlayerData player, PlayerData targetPlayer, uint turn)
{
player.DiplomacyData.AddTurnAttacker(player.Id, targetPlayer.Id, turn);
}
public static bool CheckTurnAttacker(this PlayerData player, uint targetId, uint turn)
{
return player.DiplomacyData.CheckTurnAttacker(player.Id, targetId, turn);
}
public static bool CheckTurnAttacker(this PlayerData player, PlayerData targetPlayer, uint turn)
{
return player.DiplomacyData.CheckTurnAttacker(player.Id, targetPlayer.Id, turn);
}
}
// 对他国的数据
[MemoryPackable]
public partial class CountryDiplomacyInfo
{
public uint PlayerId;
// 我对国家 PlayerId 的外交关系
public DiplomacyState DiplomacyState;
// 我对国家 PlayerId 的好感值
public float FeelingValue;
// 我对国家 PlayerId 的好感态度
public FeelingState FeelingState;
// 我对国家 PlayerId 的好感策略
public List<FeelingStrategy> FeelingStrategyList;
// 国家 PlayerId 攻击我的回合记录
public uint AttackTurn;
// 国家 PlayerId 是否在我国建立了大使馆
public bool IsEmbassy;
// 联盟破裂回合结束标记
public bool IsLeagueRupture;
// 国家对我发起的结盟请求
public bool IsLeagueRequest;
// 冷静期标记
[MemoryPackIgnore]
public int IsCalm;
[MemoryPackConstructor]
public CountryDiplomacyInfo()
{
AttackTurn = 0;
IsCalm = 0;
IsEmbassy = false;
IsLeagueRupture = false;
IsLeagueRequest = false;
FeelingStrategyList = new List<FeelingStrategy>();
}
public CountryDiplomacyInfo(CountryDiplomacyInfo copyData)
{
PlayerId = copyData.PlayerId;
AttackTurn = copyData.AttackTurn;
DiplomacyState = copyData.DiplomacyState;
FeelingValue = copyData.FeelingValue;
FeelingState = copyData.FeelingState;
FeelingStrategyList= new List<FeelingStrategy>();
foreach (var strategy in copyData.FeelingStrategyList)FeelingStrategyList.Add(strategy);
IsEmbassy = copyData.IsEmbassy;
IsLeagueRupture = copyData.IsLeagueRupture;
IsLeagueRequest = copyData.IsLeagueRequest;
IsCalm = copyData.IsCalm;
}
public void DeepCopy(CountryDiplomacyInfo copyData)
{
PlayerId = copyData.PlayerId;
AttackTurn = copyData.AttackTurn;
DiplomacyState = copyData.DiplomacyState;
FeelingValue = copyData.FeelingValue;
FeelingState = copyData.FeelingState;
FeelingStrategyList.Clear();
foreach (var strategy in copyData.FeelingStrategyList)FeelingStrategyList.Add(strategy);
IsEmbassy = copyData.IsEmbassy;
IsLeagueRupture = copyData.IsLeagueRupture;
IsLeagueRequest = copyData.IsLeagueRequest;
IsCalm = copyData.IsCalm;
}
}
// 英雄的数据
[MemoryPackable]
public partial class PlayerHeroData
{
//当前最多获取英雄数量
public int MaxHeroCount;
//当前已经拥有的英雄数量
public int HeroCount => HeroList.Count;
//当前已经有的英雄
public List<UnitFullType> HeroList;
public GiantType LeaderGiantType;
public Dictionary<UnitFullType, HeroTaskContentBase> HeroTaskDict;
[MemoryPackConstructor]
public PlayerHeroData()
{
MaxHeroCount = 1;
HeroList = new List<UnitFullType>();
LeaderGiantType = GiantType.None;
HeroTaskDict = new Dictionary<UnitFullType, HeroTaskContentBase>();
}
public PlayerHeroData(PlayerHeroData copyData)
{
MaxHeroCount = copyData.MaxHeroCount;
HeroList = new List<UnitFullType>(copyData.HeroList);
LeaderGiantType = copyData.LeaderGiantType;
HeroTaskDict = new Dictionary<UnitFullType, HeroTaskContentBase>();
foreach (var kv in copyData.HeroTaskDict) HeroTaskDict.TryAdd(kv.Key,kv.Value?.GetCopyHeroTaskContent());
}
public void DeepCopy(PlayerHeroData copyData)
{
MaxHeroCount = copyData.MaxHeroCount;
HeroList = new List<UnitFullType>(copyData.HeroList);
LeaderGiantType = copyData.LeaderGiantType;
HeroTaskDict.Clear();
foreach (var kv in copyData.HeroTaskDict) HeroTaskDict.TryAdd(kv.Key,kv.Value?.GetCopyHeroTaskContent());
}
public void Init(CivEnum civEnum, ForceEnum forceEnum)
{
LeaderGiantType = civEnum switch
{
CivEnum.Egyptian => GiantType.EgyptianRemilia,
CivEnum.French => GiantType.FrenchKaguya,
_ => GiantType.None
};
}
public GiantType GetLeaderGiantType()
{
return LeaderGiantType;
}
public bool HasHero(GiantType giantType)
{
foreach (var heroType in HeroList)
if (heroType.GiantType == giantType)
return true;
return false;
}
public bool AddHero(GiantType giantType)
{
var type = new UnitFullType(UnitType.Giant, giantType, 0);
//如果不是首个英雄起步是Lv1
if (HeroCount > 0) type.UnitLevel = 1;
if (HasHero(giantType)) return false;
HeroList.Add(type);
//如果Lv3或者其他意外就不需要填加对应task了
if(HeroTaskManager.Instance.GetHeroTaskContent(type, out var task))
HeroTaskDict.Add(type,task);
return true;
}
//发生在英雄升级的时候更新heroList让新的英雄type替换旧的type
public bool UpdateHero(UnitFullType newType)
{
if (!HasHero(newType.GiantType)) return false;
//TODO 临时写法
if (this == Main.MapData.PlayerMap.SelfPlayerData.PlayerHeroData)
{
UIManager.Instance.BottomBarUI.UpdateHeroButtonSprite();
}
for(int i =0;i < HeroCount;i++)
if (HeroList[i].GiantType == newType.GiantType)
{
HeroTaskDict.Remove(HeroList[i]);
HeroList[i] = newType;
//如果不是满级,要更新新的任务
if(newType.UnitLevel < 3){
if (!HeroTaskManager.Instance.GetHeroTaskContent(newType, out var task)) return false;
HeroTaskDict.Add(newType,task);
}
return true;
}
return false;
}
public bool ForceFinishHeroTask(GiantType giant)
{
if (!HasHero(giant)) return false;
if(!GetHeroTask(giant,out var task))return false;
//task.Level = task.TargetLevel;
if (task.IsForceFinished) return false;
task.ForceFinish();
return true;
}
public bool GetHeroTask(GiantType giant, out HeroTaskContentBase task)
{
foreach(var t in HeroTaskDict)
if (t.Key.GiantType == giant)
{
task = t.Value;
return true;
}
task = null;
return false;
}
public void UpdateHeroMaxCount(uint unitLevel)
{
if (unitLevel + 1 > MaxHeroCount)
MaxHeroCount = Mathf.Min(3, (int)unitLevel + 1);
}
//获取英雄的升级费用值
public int GetHeroFinishTaskCost(GiantType giant)
{
foreach (var heroType in HeroList)
if (heroType.GiantType == giant)
{
if(GetHeroTask(giant,out var task))
return task.GetFinishCost() * ((int)heroType.UnitLevel + 1) ;
}
return 0;
}
public uint GetHeroLevel(GiantType giant)
{
foreach (var heroType in HeroList)
if (heroType.GiantType == giant)
return heroType.UnitLevel;
return 0;
}
//返回现在外部的herobutton应该显示谁的头像
public Sprite GetHeroButtonSprite()
{
var giant = GetLeaderGiantType();
if (HeroCount > 0)
giant = HeroList[HeroCount - 1].GiantType;
if (!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(new UnitFullType(UnitType.Giant, giant, 0),
out var info))
return null;
if (!Table.Instance.UnitTypeDataAssets.GetUnitSpriteByInfo(info,Main.MapData.PlayerMap.SelfPlayerData,out var sprite))
return null;
return sprite;
}
//返回现在外部的herobutton是否应该显示提示符号
public bool GetHeroButtonHint()
{
return HeroCount < MaxHeroCount;
}
}
// 命名器的数据
[MemoryPackable]
public partial class PlayerNamerData
{
//City命名
[MemoryPackInclude]
private List<CityLibrary> _cityNamer;
[MemoryPackInclude]
private int _cityNamerPointer;
[MemoryPackConstructor]
public PlayerNamerData()
{
_cityNamer = new List<CityLibrary>();
_cityNamerPointer = 0;
}
public void Init(CivEnum civEnum)
{
if (!Table.Instance.CivDataAssets.GetCivInfo(Table.Instance.TransCivEnumToCivId(civEnum), out var info))
return;
foreach (var t in info.CityInfoList)
_cityNamer.Add(t.CityNameEnum);
Table.Instance.ShuffleRange(_cityNamer, 1);
}
public PlayerNamerData(PlayerNamerData copyData)
{
_cityNamer = new List<CityLibrary>(copyData._cityNamer);
_cityNamerPointer = copyData._cityNamerPointer;
}
public void DeepCopy(PlayerNamerData copyData)
{
_cityNamer = new List<CityLibrary>(copyData._cityNamer);
_cityNamerPointer = copyData._cityNamerPointer;
}
public CityLibrary GetSetNextCity()
{
if (_cityNamerPointer >= _cityNamer.Count)
_cityNamerPointer = 1;//重复命名的时候,跳过首都
return _cityNamer[_cityNamerPointer++];
}
}
}