外交系统实现
This commit is contained in:
parent
4956b27a23
commit
19c56ecf8f
@ -8,7 +8,10 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Logic.Action;
|
||||
using Logic.AI;
|
||||
using NUnit.Framework;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
|
||||
@ -28,6 +31,7 @@ namespace RuntimeData
|
||||
EYE
|
||||
}
|
||||
|
||||
|
||||
// 奇观状态枚举
|
||||
public enum WonderState
|
||||
{
|
||||
@ -39,6 +43,28 @@ namespace RuntimeData
|
||||
}
|
||||
|
||||
|
||||
// 外交关系枚举
|
||||
public enum DiplomacyState
|
||||
{
|
||||
NoDiplomacy,
|
||||
Neutral,
|
||||
League,
|
||||
War,
|
||||
LeagueRupture,
|
||||
}
|
||||
|
||||
|
||||
// 好感状态枚举
|
||||
public enum FeelingState
|
||||
{
|
||||
Trust,
|
||||
Appreciate,
|
||||
Indifferent,
|
||||
Suspicion,
|
||||
Terrible,
|
||||
}
|
||||
|
||||
|
||||
[Serializable]
|
||||
public class PlayerMapData : ISerializationCallbackReceiver
|
||||
{
|
||||
@ -229,6 +255,7 @@ namespace RuntimeData
|
||||
public List<uint> MeetPlayers;
|
||||
public List<uint> CurAttackPlayers;
|
||||
public List<uint> LastAttackPlayers;
|
||||
public DiplomacyData DiplomacyData;
|
||||
|
||||
//用于记录是否死亡,是否要centMessage来宣告死亡信息
|
||||
public bool DieMark = false;
|
||||
@ -239,6 +266,7 @@ namespace RuntimeData
|
||||
Sight = new MapSightData();
|
||||
TechTree = new TechTreeData();
|
||||
Wonder = new WonderData();
|
||||
DiplomacyData = new DiplomacyData();
|
||||
MeetPlayers = new List<uint>();
|
||||
CurAttackPlayers = new List<uint>();
|
||||
LastAttackPlayers = new List<uint>();
|
||||
@ -257,6 +285,7 @@ namespace RuntimeData
|
||||
Sight = new MapSightData();
|
||||
|
||||
Wonder = new WonderData();
|
||||
DiplomacyData = new DiplomacyData();
|
||||
CurAttackPlayers = new List<uint>();
|
||||
LastAttackPlayers = new List<uint>();
|
||||
MeetPlayers = new List<uint>();
|
||||
@ -277,6 +306,7 @@ namespace RuntimeData
|
||||
Sight = new MapSightData(copyData.Sight);
|
||||
TechTree = new TechTreeData(copyData.TechTree);
|
||||
Wonder = new WonderData(copyData.Wonder);
|
||||
DiplomacyData = new DiplomacyData(copyData.DiplomacyData);
|
||||
|
||||
CurAttackPlayers = new List<uint>();
|
||||
foreach (var id in copyData.CurAttackPlayers) CurAttackPlayers.Add(id);
|
||||
@ -305,6 +335,7 @@ namespace RuntimeData
|
||||
Sight.DeepCopy(copyData.Sight);
|
||||
TechTree.DeepCopy(copyData.TechTree);
|
||||
Wonder.DeepCopy(copyData.Wonder);
|
||||
DiplomacyData.DeepCopy(copyData.DiplomacyData);
|
||||
|
||||
CurAttackPlayers.Clear();
|
||||
foreach (var id in copyData.CurAttackPlayers) CurAttackPlayers.Add(id);
|
||||
@ -358,11 +389,186 @@ namespace RuntimeData
|
||||
|
||||
skill.OnTurnStart(this, map);
|
||||
}
|
||||
|
||||
RefreshFeelingValue(map);
|
||||
}
|
||||
|
||||
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;
|
||||
DiplomacyData.GetCountryDiplomacyInfo(player.Id, out var selfToPlayer);
|
||||
if (selfToPlayer.DiplomacyState == DiplomacyState.LeagueRupture) selfToPlayer.IsLeagueRupture = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 添加当前回合攻击者
|
||||
public void AddAttacker(uint playerId)
|
||||
{
|
||||
DiplomacyData.AddTurnAttacker(Turn, playerId);
|
||||
}
|
||||
|
||||
// 检查前几回合内是否有攻击者
|
||||
public bool CheckTurnsAttacker(uint turns, uint playerId)
|
||||
{
|
||||
for (int i = 0; i < turns; i++)
|
||||
{
|
||||
if (Turn < i) return false;
|
||||
if (!DiplomacyData.CheckTurnAttacker(Turn - (uint)i, playerId)) continue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 刷新对他国好感值
|
||||
public void RefreshFeelingValue(MapData map)
|
||||
{
|
||||
int maxScore = 0;
|
||||
uint maxScorePlayer = 0;
|
||||
foreach (var player in map.PlayerMap.PlayerDataList)
|
||||
{
|
||||
if (player.PlayerScore <= maxScore) continue;
|
||||
maxScore = player.PlayerScore;
|
||||
maxScorePlayer = player.Id;
|
||||
}
|
||||
|
||||
foreach (var player in map.PlayerMap.PlayerDataList)
|
||||
{
|
||||
if (player.Id == Id) continue;
|
||||
DiplomacyData.GetCountryDiplomacyInfo(player.Id, out var selfToPlayer);
|
||||
player.DiplomacyData.GetCountryDiplomacyInfo(Id, out var playerToSelf);
|
||||
if (playerToSelf == null || selfToPlayer == null) continue;
|
||||
var score = 0f;
|
||||
|
||||
// 明智的 愚蠢的
|
||||
var score1 = 0f;
|
||||
foreach (var otherPlayer in map.PlayerMap.PlayerDataList)
|
||||
{
|
||||
if (otherPlayer.Id == Id || otherPlayer.Id == player.Id) continue;
|
||||
DiplomacyData.GetCountryDiplomacyInfo(player.Id, out var selfToOtherPlayer);
|
||||
if (selfToOtherPlayer.DiplomacyState == DiplomacyState.NoDiplomacy) continue;
|
||||
player.DiplomacyData.GetCountryDiplomacyInfo(player.Id, out var playerToOtherPlayer);
|
||||
if (playerToOtherPlayer.DiplomacyState == DiplomacyState.NoDiplomacy) continue;
|
||||
|
||||
if (selfToOtherPlayer.DiplomacyState == playerToOtherPlayer.DiplomacyState) score1 += 5;
|
||||
else score1 -= 5;
|
||||
}
|
||||
if (score1 + 5 > 0) score += Mathf.Min(20, score1);
|
||||
if (score1 - 5 < 0) score += Mathf.Max(-20, score1);
|
||||
|
||||
// 迷人的 恼人的
|
||||
if (map.MapConfig.AIDiff == AIDifficult.EASY && player.Id == map.PlayerMap.SelfPlayerId &&
|
||||
Id != map.PlayerMap.SelfPlayerId) score += 15;
|
||||
if (map.MapConfig.AIDiff == AIDifficult.LUNATIC && player.Id == map.PlayerMap.SelfPlayerId &&
|
||||
Id != map.PlayerMap.SelfPlayerId) score -= 15;
|
||||
|
||||
// 和平的 暴力的
|
||||
if (!CheckTurnsAttacker(3, player.Id)) score += 15;
|
||||
else score -= 15;
|
||||
|
||||
// 外交的
|
||||
if (selfToPlayer.IsEmbassy || playerToSelf.IsEmbassy) score += 15;
|
||||
|
||||
// 强大的 弱小的
|
||||
var selfScore = 0f;
|
||||
var playerScore = 0f;
|
||||
foreach (var gridId in Sight.SightGidSet)
|
||||
{
|
||||
if (!map.GetUnitDataByGid(gridId, out var unit)) continue;
|
||||
if (!map.GetPlayerIdByUnitId(unit.Id, out var ownerId)) continue;
|
||||
if (ownerId == Id) selfScore += unit.GetCost();
|
||||
if (ownerId == player.Id) playerScore += unit.GetCost();
|
||||
}
|
||||
if (selfScore < playerScore) score += 15;
|
||||
if (selfScore > playerScore) score -= 15;
|
||||
|
||||
// 勇敢的
|
||||
if (maxScorePlayer != Id)
|
||||
{
|
||||
player.DiplomacyData.GetCountryDiplomacyInfo(maxScorePlayer, out var playerToMaxScorePlayer);
|
||||
if (playerToMaxScorePlayer.DiplomacyState == DiplomacyState.War) score += 15;
|
||||
}
|
||||
|
||||
// 威胁的
|
||||
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;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 侵略的
|
||||
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;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 主宰的
|
||||
if (maxScorePlayer == player.Id)
|
||||
{
|
||||
var count = 0;
|
||||
var playerCity = new HashSet<CityData>();
|
||||
map.GetCityDataListByPlayerId(player.Id, playerCity);
|
||||
foreach (var city in playerCity) if (city.IsCradle) count++;
|
||||
if (count > 0) count--;
|
||||
score -= 15 + count * 5;
|
||||
}
|
||||
|
||||
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.Id == Id) continue;
|
||||
DiplomacyData.GetCountryDiplomacyInfo(player.Id, out var selfToPlayer);
|
||||
player.DiplomacyData.GetCountryDiplomacyInfo(Id, out var playerToSelf);
|
||||
// 如果没有外交关系,且没有见过面,则设置为无外交关系
|
||||
if (!MeetPlayers.Contains(player.Id)) selfToPlayer.DiplomacyState = DiplomacyState.NoDiplomacy;
|
||||
// 如果没有外交关系,且见过面,则设置为中立
|
||||
else if (selfToPlayer.DiplomacyState == DiplomacyState.NoDiplomacy)
|
||||
selfToPlayer.DiplomacyState = DiplomacyState.Neutral;
|
||||
// 如果上一回合回合内双方未发生战斗,则该回合开始时变为中立关系
|
||||
if (selfToPlayer.DiplomacyState == DiplomacyState.War && !LastAttackPlayers.Contains(player.Id))
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -640,4 +846,125 @@ namespace RuntimeData
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 主动攻击我的敌人信息
|
||||
[Serializable]
|
||||
public class DiplomacyData : ISerializationCallbackReceiver
|
||||
{
|
||||
public List<CountryDiplomacyInfo> Info;
|
||||
private Dictionary<uint, CountryDiplomacyInfo> _infoDict;
|
||||
|
||||
public DiplomacyData()
|
||||
{
|
||||
Info = new List<CountryDiplomacyInfo>();
|
||||
}
|
||||
|
||||
public DiplomacyData(DiplomacyData copyData)
|
||||
{
|
||||
Info = new List<CountryDiplomacyInfo>();
|
||||
}
|
||||
|
||||
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 turn, uint playerId)
|
||||
{
|
||||
GetCountryDiplomacyInfo(playerId, out var info);
|
||||
if (info == null) return false;
|
||||
return info.AttackTurn == 0 || info.AttackTurn < turn;
|
||||
}
|
||||
|
||||
public void AddTurnAttacker(uint playerId, uint turn)
|
||||
{
|
||||
GetCountryDiplomacyInfo(playerId, out var info);
|
||||
if (info == null) return;
|
||||
info.AttackTurn = turn;
|
||||
}
|
||||
|
||||
public void GetCountryDiplomacyInfo(uint playerId, out CountryDiplomacyInfo info)
|
||||
{
|
||||
Refresh();
|
||||
if (!_infoDict.TryGetValue(playerId, out info))
|
||||
{
|
||||
info = new CountryDiplomacyInfo { PlayerId = playerId };
|
||||
Info.Add(info);
|
||||
_infoDict[playerId] = 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 void OnBeforeSerialize()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnAfterDeserialize()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 对他国的数据
|
||||
[Serializable]
|
||||
public class CountryDiplomacyInfo
|
||||
{
|
||||
public uint PlayerId;
|
||||
// 我对国家 PlayerId 的外交关系
|
||||
public DiplomacyState DiplomacyState;
|
||||
// 我对国家 PlayerId 的好感值
|
||||
public float FeelingValue;
|
||||
// 我对国家 PlayerId 的好感态度
|
||||
public FeelingState FeelingState;
|
||||
// 国家 PlayerId 攻击我的回合记录
|
||||
public uint AttackTurn;
|
||||
// 国家 PlayerId 是否在我国建立了大使馆
|
||||
public bool IsEmbassy;
|
||||
// 联盟破裂回合结束标记
|
||||
public bool IsLeagueRupture;
|
||||
|
||||
public CountryDiplomacyInfo()
|
||||
{
|
||||
AttackTurn = 0;
|
||||
IsEmbassy = false;
|
||||
IsLeagueRupture = false;
|
||||
}
|
||||
|
||||
public CountryDiplomacyInfo(CountryDiplomacyInfo copyData)
|
||||
{
|
||||
PlayerId = copyData.PlayerId;
|
||||
AttackTurn = copyData.AttackTurn;
|
||||
DiplomacyState = copyData.DiplomacyState;
|
||||
FeelingValue = copyData.FeelingValue;
|
||||
FeelingState = copyData.FeelingState;
|
||||
IsEmbassy = copyData.IsEmbassy;
|
||||
IsLeagueRupture = copyData.IsLeagueRupture;
|
||||
}
|
||||
|
||||
public void DeepCopy(CountryDiplomacyInfo copyData)
|
||||
{
|
||||
PlayerId = copyData.PlayerId;
|
||||
AttackTurn = copyData.AttackTurn;
|
||||
DiplomacyState = copyData.DiplomacyState;
|
||||
FeelingValue = copyData.FeelingValue;
|
||||
FeelingState = copyData.FeelingState;
|
||||
IsEmbassy = copyData.IsEmbassy;
|
||||
IsLeagueRupture = copyData.IsLeagueRupture;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2490,7 +2490,7 @@ namespace Logic.Action
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 小兵攻击,目前只用于 AI 的行为
|
||||
public class UnitAttackAction : ActionLogicBase
|
||||
{
|
||||
|
||||
@ -870,7 +870,14 @@ namespace Logic
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 主动建立同盟
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,8 +209,10 @@ namespace Logic
|
||||
if (!mapData.GetCityDataByUnitId(unit2.Id, out var city2)) return false;
|
||||
if (!mapData.GetGridDataByUnitId(unit1.Id, out var grid1)) return false;
|
||||
if (!mapData.GetGridDataByUnitId(unit2.Id, out var grid2)) return false;
|
||||
Main.PlayerLogic.SetDiplomacyLeague(player1, player2, DiplomacyState.War);
|
||||
player1.CurAttackPlayers.Add(player2.Id);
|
||||
player2.CurAttackPlayers.Add(player1.Id);
|
||||
player2.AddAttacker(player1.Id);
|
||||
player1.TurnNoAttack = 0;
|
||||
|
||||
// 计算攻击伤害
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user