AI4.0更新

This commit is contained in:
wuwenbo 2025-07-14 19:41:58 +08:00
parent b4a4ab0a0b
commit 7824e42af8
13 changed files with 305 additions and 278 deletions

View File

@ -27,7 +27,7 @@ MonoBehaviour:
_version: 3.33
_category:
_comments:
_translation: {x: 71, y: 178}
_translation: {x: -189, y: -71}
_zoomFactor: 1
_haltSerialization: 0
_externalSerializationFile: {fileID: 0}

View File

@ -18,7 +18,7 @@ MonoBehaviour:
_version: 3.33
_category:
_comments:
_translation: {x: 109, y: -993}
_zoomFactor: 0.8057433
_translation: {x: 1016, y: 32}
_zoomFactor: 0.25006658
_haltSerialization: 0
_externalSerializationFile: {fileID: 0}

File diff suppressed because one or more lines are too long

View File

@ -90,8 +90,8 @@ namespace NodeCanvas.Tasks.Actions
if (unitGrid.Id == grid.Id) continue;
if (!param.MapData.GetUnitDataByGid(grid.Id, out var unit)) continue;
var dis = param.MapData.GridMap.CalcDistance(grid, target);
if (selfUnits.Contains(unit)) selfScore += unit.GetCost() / (dis + 1f);
else enemyScore += unit.GetCost() / (dis + 1f);
if (selfUnits.Contains(unit)) selfScore += unit.GetMilitary() / (dis + 1f);
else enemyScore += unit.GetMilitary() / (dis + 1f);
}
var targetScore = (selfScore - enemyScore) / path.length;

View File

@ -0,0 +1,67 @@
/*
* @Author:
* @Description:
* @Date: 20250606 19:06:16
* @Modify:
*/
using System;
using Logic;
using Logic.AI;
using NodeCanvas.Framework;
using ParadoxNotion.Design;
using UnityEngine;
namespace NodeCanvas.Tasks.Actions
{
[Category("AIAction")]
[Serializable]
public class AIParamStandingTrainUnit : ActionTask
{
protected override string info => string.Format($"常备军训练单位");
protected override void OnExecute()
{
// 直接从Blackboard获取AICalculatorData
var data = blackboard.GetVariable<AICalculatorData>("Data");
if (data?.value?.TargetParam.CityData == null || data.value.AIActions.Count == 0)
{
EndAction(false);
return;
}
var city = data.value.TargetParam.CityData;
var count = data.value.TargetParam.MapData.GetUnitCount(city.Id);
if (count >= Mathf.Min(5, city.Level * 0.6f))
{
EndAction(false);
return;
}
var targetUnitType = UnitType.None;
// 如果不能造剑士
bool canSwordsman = false;
foreach (var aiAction in data.value.AIActions)
{
if (aiAction.ActionLogic.ActionId.UnitType == UnitType.Swordsman) canSwordsman = true;
}
if (!canSwordsman) targetUnitType = UnitType.Warrior;
// 如果回合金 < 15
if (targetUnitType == UnitType.None && Main.PlayerLogic.GetPlayerStarsPerTurn(data.value.Map, data.value.Player.Id) < 15)
{
targetUnitType = UnitType.Warrior;
}
// 否则造剑士
if (targetUnitType == UnitType.None) targetUnitType = UnitType.Swordsman;
for (int i = data.value.AIActions.Count - 1; i >= 0; i--)
{
if (data.value.AIActions[i].ActionLogic.ActionId.UnitType == targetUnitType) continue;
data.value.AIActions.RemoveAt(i);
}
EndAction(data.value.AIActions.Count > 0);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 61a78b1e94b24f748619cf5b94d8fe93
timeCreated: 1752491476

View File

@ -479,8 +479,8 @@ namespace RuntimeData
{
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 (ownerId == Id) selfScore += unit.GetMilitary();
if (ownerId == player.Id) playerScore += unit.GetMilitary();
}
if (selfScore < playerScore) score += 15;
if (selfScore > playerScore) score -= 15;

View File

@ -206,12 +206,20 @@ namespace RuntimeData
return (float)Health / GetMaxHealth();
}
// 获取军事分
public float GetMilitary()
{
if (!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType, out var info))
return 0;
if (GetHealthRatio() <= 0.5f) return info.Cost * 0.5f;
return info.Cost;
}
// 获取造价
public float GetCost()
{
if (!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType, GiantType, out var info))
return 0;
if (GetHealthRatio() <= 0.5f) return info.Cost * 0.5f;
return info.Cost;
}

View File

@ -108,6 +108,7 @@ namespace Logic.AI
TechResource,
CityTrainDefendAttack,
AroundGapScoreMax,
CityTrainMilitary,
}
@ -118,9 +119,7 @@ namespace Logic.AI
public MapData Map;
public PlayerData Player;
public Strategy CountryStrategy;
public PlayerData AttackPlayer;
public CountryAttackType AttackType;
public PlayerData DefendTarget;
public HashSet<PlayerData> AttackPlayerSet;
// 策略集合
public Dictionary<CityData, Strategy> CityStrategy;
@ -203,6 +202,7 @@ namespace Logic.AI
public AICalculatorData()
{
AttackPlayerSet = new HashSet<PlayerData>();
CityStrategy = new Dictionary<CityData, Strategy>();
FreeUnitStrategy = new Dictionary<UnitData, Strategy>();
LegionStrategy = new Dictionary<uint, Strategy>();
@ -255,9 +255,7 @@ namespace Logic.AI
Map = map;
Player = player;
CountryStrategy = Strategy.None;
AttackPlayer = null;
AttackType = CountryAttackType.None;
DefendTarget = null;
AttackPlayerSet.Clear();
IsFinish = false;
AIActions.Clear();
@ -625,7 +623,7 @@ namespace Logic.AI
var score = 0f;
foreach (var unit in kv.Value)
{
score += unit.GetCost();
score += unit.GetMilitary();
}
LegionScore[kv.Key] = score;
}
@ -637,7 +635,7 @@ namespace Logic.AI
foreach (var unit in kv.Value)
{
if (!Map.GetGridDataByUnitId(unit.Id, out var grid)) continue;
var ratio = unit.GetCost() / score;
var ratio = unit.GetMilitary() / score;
vec += new Vector2(grid.Pos.X, grid.Pos.Y) * ratio;
}
var center = new Vector2Int((int)Math.Round(vec.X), (int)Math.Round(vec.Y));
@ -772,6 +770,9 @@ namespace Logic.AI
{
foreach (var cityId in CityBorder)
{
if (!Map.GetPlayerIdByCityId(cityId, out var ownerId)) continue;
if(!Map.PlayerMap.GetPlayerDataByPlayerID(ownerId, out var owner)) continue;
if (!AttackPlayerSet.Contains(owner)) continue;
if (!LegionCanMoveCities[legionId].Contains(cityId)) continue;
if (!Map.GetGridDataByCityId(cityId, out var cityGrid)) continue;
var dis = Map.GridMap.CalcDistance(cityGrid, LegionGrid[legionId]) + 1;
@ -918,8 +919,8 @@ namespace Logic.AI
foreach (var aroundGrid in aroundGrids)
{
if (!Map.GetUnitDataByGid(aroundGrid.Id, out var attacker)) continue;
if (!selfUnit.Contains(attacker)) score += attacker.GetCost();
else score -= attacker.GetCost();
if (!selfUnit.Contains(attacker)) score += attacker.GetMilitary();
else score -= attacker.GetMilitary();
}
if (score > 6f)
{
@ -1074,7 +1075,7 @@ namespace Logic.AI
var score = 0f;
var unitList = new List<UnitData>();
Map.GetUnitDataListByPlayerId(player.Id, unitList);
foreach (var unit in unitList) score += unit.GetCost();
foreach (var unit in unitList) score += unit.GetMilitary();
return score;
}
@ -1143,140 +1144,92 @@ namespace Logic.AI
// 计算两个小兵的克制分 克制分表 克制表
public float CalUnitCounterScore(UnitType self, UnitType target)
{
if (self == UnitType.Warrior && target == UnitType.Warrior) return 0;
if (self == UnitType.Archer && target == UnitType.Warrior) return 1;
if (self == UnitType.Defender && target == UnitType.Warrior) return -0.5f;
if (self == UnitType.Rider && target == UnitType.Warrior) return 0;
if (self == UnitType.Knights && target == UnitType.Warrior) return 3;
if (self == UnitType.Catapult && target == UnitType.Warrior) return 3;
if (self == UnitType.Swordsman && target == UnitType.Warrior) return 0.5f;
if (self == UnitType.Boat && target == UnitType.Warrior) return 0;
if (self == UnitType.RammerShip && target == UnitType.Warrior) return 0.5f;
if (self == UnitType.Ship && target == UnitType.Warrior) return 1f;
if (self == UnitType.BomberShip && target == UnitType.Warrior) return 1.5f;
if (self == UnitType.Swordsman && target == UnitType.Warrior) return 1f;
if (self == UnitType.Warrior && target == UnitType.Archer) return 0.5f;
if (self == UnitType.Archer && target == UnitType.Archer) return 0;
if (self == UnitType.Defender && target == UnitType.Archer) return -0.5f;
if (self == UnitType.Rider && target == UnitType.Archer) return 1;
if (self == UnitType.Knights && target == UnitType.Archer) return 3;
if (self == UnitType.Catapult && target == UnitType.Archer) return 3;
if (self == UnitType.Swordsman && target == UnitType.Archer) return 3;
if (self == UnitType.Boat && target == UnitType.Archer) return 0;
if (self == UnitType.RammerShip && target == UnitType.Archer) return 3f;
if (self == UnitType.Ship && target == UnitType.Archer) return 0f;
if (self == UnitType.BomberShip && target == UnitType.Archer) return 3f;
if (self == UnitType.Warrior && target == UnitType.Defender) return -1f;
if (self == UnitType.Archer && target == UnitType.Defender) return 0.5f;
if (self == UnitType.Defender && target == UnitType.Defender) return -2f;
if (self == UnitType.Rider && target == UnitType.Defender) return -1.5f;
if (self == UnitType.Knights && target == UnitType.Defender) return 0;
if (self == UnitType.Archer && target == UnitType.Defender) return 1f;
if (self == UnitType.Catapult && target == UnitType.Defender) return 2;
if (self == UnitType.Swordsman && target == UnitType.Defender) return 0;
if (self == UnitType.Boat && target == UnitType.Defender) return 0;
if (self == UnitType.RammerShip && target == UnitType.Defender) return 0;
if (self == UnitType.Ship && target == UnitType.Defender) return 0.5f;
if (self == UnitType.BomberShip && target == UnitType.Defender) return 1.5f;
if (self == UnitType.Swordsman && target == UnitType.Defender) return 1;
if (self == UnitType.RammerShip && target == UnitType.Defender) return 1;
if (self == UnitType.Ship && target == UnitType.Defender) return 1f;
if (self == UnitType.BomberShip && target == UnitType.Defender) return 2f;
if (self == UnitType.Warrior && target == UnitType.Rider) return 0.5f;
if (self == UnitType.Archer && target == UnitType.Rider) return 1.5f;
if (self == UnitType.Defender && target == UnitType.Rider) return 0;
if (self == UnitType.Rider && target == UnitType.Rider) return 0.5f;
if (self == UnitType.Knights && target == UnitType.Rider) return 3;
if (self == UnitType.Catapult && target == UnitType.Rider) return 3;
if (self == UnitType.Swordsman && target == UnitType.Rider) return 3;
if (self == UnitType.Boat && target == UnitType.Rider) return 0;
if (self == UnitType.RammerShip && target == UnitType.Rider) return 3f;
if (self == UnitType.Ship && target == UnitType.Rider) return 1.5f;
if (self == UnitType.BomberShip && target == UnitType.Rider) return 3f;
if (self == UnitType.Archer && target == UnitType.Rider) return 1f;
if (self == UnitType.Warrior && target == UnitType.Knights) return 0.5f;
if (self == UnitType.Archer && target == UnitType.Knights) return 1.5f;
if (self == UnitType.Defender && target == UnitType.Knights) return 0f;
if (self == UnitType.Rider && target == UnitType.Knights) return 0.5f;
if (self == UnitType.Knights && target == UnitType.Knights) return 3f;
if (self == UnitType.Catapult && target == UnitType.Knights) return 3f;
if (self == UnitType.Swordsman && target == UnitType.Knights) return 3f;
if (self == UnitType.Boat && target == UnitType.Knights) return 0f;
if (self == UnitType.RammerShip && target == UnitType.Knights) return 3f;
if (self == UnitType.Ship && target == UnitType.Knights) return 1.5f;
if (self == UnitType.BomberShip && target == UnitType.Knights) return 3f;
if (self == UnitType.Warrior && target == UnitType.Catapult) return 2;
if (self == UnitType.Archer && target == UnitType.Catapult) return 2;
if (self == UnitType.Defender && target == UnitType.Catapult) return 1;
if (self == UnitType.Rider && target == UnitType.Catapult) return 2;
if (self == UnitType.Rider && target == UnitType.Catapult) return 1;
if (self == UnitType.Knights && target == UnitType.Catapult) return 3;
if (self == UnitType.Catapult && target == UnitType.Catapult) return 3;
if (self == UnitType.Swordsman && target == UnitType.Catapult) return 3;
if (self == UnitType.Boat && target == UnitType.Catapult) return 0;
if (self == UnitType.RammerShip && target == UnitType.Catapult) return 3;
if (self == UnitType.Ship && target == UnitType.Catapult) return 2f;
if (self == UnitType.BomberShip && target == UnitType.Catapult) return 3f;
if (self == UnitType.Warrior && target == UnitType.Swordsman) return -1;
if (self == UnitType.Archer && target == UnitType.Swordsman) return 0.5f;
if (self == UnitType.Defender && target == UnitType.Swordsman) return -2;
if (self == UnitType.Rider && target == UnitType.Swordsman) return -2;
if (self == UnitType.Knights && target == UnitType.Swordsman) return 1;
if (self == UnitType.Catapult && target == UnitType.Swordsman) return 2;
if (self == UnitType.Swordsman && target == UnitType.Swordsman) return 0;
if (self == UnitType.Boat && target == UnitType.Swordsman) return 0;
if (self == UnitType.RammerShip && target == UnitType.Swordsman) return 0;
if (self == UnitType.Ship && target == UnitType.Swordsman) return 0.5f;
if (self == UnitType.BomberShip && target == UnitType.Swordsman) return 1.5f;
if (self == UnitType.Catapult && target == UnitType.RammerShip) return 1;
if (self == UnitType.Ship && target == UnitType.RammerShip) return 1f;
if (self == UnitType.Warrior && target == UnitType.Boat) return 1.5f;
if (self == UnitType.Archer && target == UnitType.Boat) return 1.5f;
if (self == UnitType.Defender && target == UnitType.Boat) return 0.5f;
if (self == UnitType.Rider && target == UnitType.Boat) return 1.5f;
if (self == UnitType.Knights && target == UnitType.Boat) return 3;
if (self == UnitType.Catapult && target == UnitType.Boat) return 3;
if (self == UnitType.Swordsman && target == UnitType.Boat) return 3;
if (self == UnitType.Boat && target == UnitType.Boat) return 0;
if (self == UnitType.RammerShip && target == UnitType.Boat) return 3;
if (self == UnitType.Ship && target == UnitType.Boat) return 1.5f;
if (self == UnitType.BomberShip && target == UnitType.Boat) return 3f;
if (self == UnitType.Catapult && target == UnitType.Ship) return 1;
if (self == UnitType.RammerShip && target == UnitType.Ship) return 1;
if (self == UnitType.Warrior && target == UnitType.RammerShip) return -1;
if (self == UnitType.Archer && target == UnitType.RammerShip) return 0.5f;
if (self == UnitType.Defender && target == UnitType.RammerShip) return -2f;
if (self == UnitType.Rider && target == UnitType.RammerShip) return -2f;
if (self == UnitType.Knights && target == UnitType.RammerShip) return 1;
if (self == UnitType.Catapult && target == UnitType.RammerShip) return 3;
if (self == UnitType.Swordsman && target == UnitType.RammerShip) return 0;
if (self == UnitType.Boat && target == UnitType.RammerShip) return 0;
if (self == UnitType.RammerShip && target == UnitType.RammerShip) return 0;
if (self == UnitType.Ship && target == UnitType.RammerShip) return 0.5f;
if (self == UnitType.BomberShip && target == UnitType.RammerShip) return 1.5f;
if (self == UnitType.Catapult && target == UnitType.BomberShip) return 1;
if (self == UnitType.Warrior && target == UnitType.Ship) return 0.5f;
if (self == UnitType.Archer && target == UnitType.Ship) return 0;
if (self == UnitType.Defender && target == UnitType.Ship) return -0.5f;
if (self == UnitType.Rider && target == UnitType.Ship) return 0;
if (self == UnitType.Knights && target == UnitType.Ship) return 3;
if (self == UnitType.Catapult && target == UnitType.Ship) return 2;
if (self == UnitType.Swordsman && target == UnitType.Ship) return 3;
if (self == UnitType.Boat && target == UnitType.Ship) return 0;
if (self == UnitType.RammerShip && target == UnitType.Ship) return 3;
if (self == UnitType.Ship && target == UnitType.Ship) return 0;
if (self == UnitType.BomberShip && target == UnitType.Ship) return 3;
if (self == UnitType.Warrior && target == UnitType.BomberShip) return 1;
if (self == UnitType.Archer && target == UnitType.BomberShip) return 1;
if (self == UnitType.Defender && target == UnitType.BomberShip) return 0.5f;
if (self == UnitType.Rider && target == UnitType.BomberShip) return 1;
if (self == UnitType.Knights && target == UnitType.BomberShip) return 3;
if (self == UnitType.Catapult && target == UnitType.BomberShip) return 3;
if (self == UnitType.Swordsman && target == UnitType.BomberShip) return 3;
if (self == UnitType.Boat && target == UnitType.BomberShip) return 0;
if (self == UnitType.RammerShip && target == UnitType.BomberShip) return 3;
if (self == UnitType.Ship && target == UnitType.BomberShip) return 1f;
if (self == UnitType.BomberShip && target == UnitType.BomberShip) return 1.5f;
if (self == UnitType.Catapult && (target == UnitType.Giant || target == UnitType.BigGuy)) return 2;
if (self == UnitType.Swordsman && (target == UnitType.Giant || target == UnitType.BigGuy)) return 1;
if (self == UnitType.BomberShip && (target == UnitType.Giant || target == UnitType.BigGuy)) return 2;
return 0;
}
// 计算两个小兵的军事差距分
public float CalUnitMilitaryGapScore(MapData map, UnitData self, UnitData target)
{
var score = self.GetMilitary() - target.GetMilitary();
score += CalUnitCounterScore(self, target);
if (map.GetGridDataByUnitId(self.Id, out var selfGrid) &&
map.GetGridDataByUnitId(target.Id, out var targetGrid))
{
var selfMag = self.GetSkill(SkillType.DASH, out _)
? self.GetAttackRange() + self.MP
: self.GetAttackRange();
var dis = map.GridMap.CalcDistance(selfGrid, targetGrid);
if (dis <= selfMag)
{
var dmg = Table.Instance.CalcDamage(map, self, target);
var attackScore = (float)dmg / target.GetMaxHealth() * target.GetCost();
score += Mathf.Min(5, attackScore);
}
var targetMag = target.GetSkill(SkillType.DASH, out _)
? target.GetAttackRange() + self.MP
: target.GetAttackRange();
if (dis <= targetMag)
{
var dmg = Table.Instance.CalcDamage(map, target, self);
var attackScore = (float)dmg / self.GetMaxHealth() * self.GetCost();
score -= Mathf.Min(self.GetMilitary(), attackScore);
}
}
if (self.GetAttackRange() == 1 && map.GetPlayerIdByUnitId(self.Id, out var selfPlayerId))
{
var selfUnits = new HashSet<UnitData>();
Map.GetUnitDataListByPlayerId(selfPlayerId, selfUnits);
var count = 0;
foreach (var unit in selfUnits) if (unit.GetAttackRange() == 1) count++;
if (count / (float)selfUnits.Count < 0.6f)
score += 6 - count / (float)selfUnits.Count * 10;
}
if (self.UnitType == UnitType.Catapult && map.GetGridDataByUnitId(self.Id, out var grid))
{
var gridList = Map.GridMap.GetAroundGridData(1, 1, grid);
bool isSea = true;
foreach (var aroundGrid in gridList)
{
if (aroundGrid.Terrain == TerrainType.Land) isSea = false;
}
if (isSea) score++;
}
return score;
}
// 计算科技对应的兵种
public void GetUnitTypeByTech(TechType techType, out UnitType unitType, out GiantType giantType)
{
@ -1355,7 +1308,6 @@ namespace Logic.AI
if (ThreatScore[target.Id] < 10) continue;
if (MilitaryGapScore[target.Id] > -5) continue;
CountryStrategy = Strategy.Defend;
DefendTarget = target;
return;
}
@ -1393,63 +1345,87 @@ namespace Logic.AI
}
}
int maxScore = 0;
PlayerData maxScorePlayer = null;
foreach (var player in Map.PlayerMap.PlayerDataList)
{
if (player.PlayerScore <= maxScore) continue;
maxScore = player.PlayerScore;
maxScorePlayer = player;
}
//然后判断是否做进攻的国家战略
foreach (var target in Map.PlayerMap.PlayerDataList)
if (maxScorePlayer != null && maxScorePlayer != Player && AttackDistance[maxScorePlayer.Id] <= 5)
{
if (target == Player) continue;
if (ThreatScore[target.Id] < 10) continue;
if (MilitaryGapScore[target.Id] < 3) continue;
if (AttackDistance[target.Id] > 7) continue;
CountryStrategy = Strategy.Attack;
AttackPlayer = target;
AttackType = CountryAttackType.CounterattackInvasions;
return;
AttackPlayerSet.Add(maxScorePlayer);
}
foreach (var target in Map.PlayerMap.PlayerDataList)
{
if (target == Player) continue;
if (MilitaryGapScore[target.Id] < 0) continue;
if (AttackDistance[target.Id] > 7) continue;
CountryStrategy = Strategy.Attack;
AttackPlayer = target;
AttackType = CountryAttackType.BullyWeak;
return;
}
foreach (var target in Map.PlayerMap.PlayerDataList)
{
if (target == Player) continue;
if (MilitaryGapScore[target.Id] < 3) continue;
bool hasCityCenter = false;
foreach (var city in selfCity)
if (maxScorePlayer != null && maxScorePlayer != Map.PlayerMap.SelfPlayerData)
{
foreach (var target in Map.PlayerMap.PlayerDataList)
{
if (hasCityCenter) break;
if(!Map.GetGridDataByCityId(city.Id,out var cityGrid)) continue;
var gridList = Map.GridMap.GetAroundGridData(8, 8, cityGrid);
foreach (var grid in gridList)
{
if (grid.Resource != ResourceType.CityCenter) continue;
if (Map.GetCityDataByGid(grid.Id, out var _)) continue;
var path = PathFinder.FindPath((int)Map.MapConfig.Width, (int)Map.MapConfig.Height,
new (grid.Pos.X, grid.Pos.Y), new (cityGrid.Pos.X, cityGrid.Pos.Y), Map, Player);
if (!path.found) continue;
if (path.length > 8) continue;
hasCityCenter = true;
break;
}
if (target == Player) continue;
if (ThreatScore[target.Id] < 10) continue;
if (MilitaryGapScore[target.Id] < 3) continue;
if (AttackDistance[target.Id] > 7) continue;
CountryStrategy = Strategy.Attack;
AttackPlayerSet.Add(target);
}
if (!hasCityCenter) continue;
CountryStrategy = Strategy.Attack;
AttackPlayer = target;
AttackType = CountryAttackType.ForcedExpansion;
return;
foreach (var target in Map.PlayerMap.PlayerDataList)
{
if (target == Player) continue;
if (MilitaryGapScore[target.Id] < 0) continue;
if (AttackDistance[target.Id] > 7) continue;
CountryStrategy = Strategy.Attack;
AttackPlayerSet.Add(target);
}
foreach (var target in Map.PlayerMap.PlayerDataList)
{
if (target == Player) continue;
if (MilitaryGapScore[target.Id] < 3) continue;
bool hasCityCenter = false;
foreach (var city in selfCity)
{
if (hasCityCenter) break;
if (!Map.GetGridDataByCityId(city.Id, out var cityGrid)) continue;
var gridList = Map.GridMap.GetAroundGridData(8, 8, cityGrid);
foreach (var grid in gridList)
{
if (grid.Resource != ResourceType.CityCenter) continue;
if (Map.GetCityDataByGid(grid.Id, out var _)) continue;
var path = PathFinder.FindPath((int)Map.MapConfig.Width, (int)Map.MapConfig.Height,
new(grid.Pos.X, grid.Pos.Y), new(cityGrid.Pos.X, cityGrid.Pos.Y), Map, Player);
if (!path.found) continue;
if (path.length > 8) continue;
hasCityCenter = true;
break;
}
}
if (!hasCityCenter) continue;
CountryStrategy = Strategy.Attack;
AttackPlayerSet.Add(target);
}
}
CountryStrategy = Strategy.Development;
if (maxScorePlayer != null && maxScorePlayer == Map.PlayerMap.SelfPlayerData)
{
foreach (var target in Map.PlayerMap.PlayerDataList)
{
if (target == Player) continue;
if (MilitaryGapScore[target.Id] < 0) continue;
if (AttackDistance[target.Id] > 5) continue;
CountryStrategy = Strategy.Attack;
AttackPlayerSet.Add(target);
}
}
if (CountryStrategy == Strategy.None) CountryStrategy = Strategy.Development;
}
// 计算城市周围单位
@ -1476,7 +1452,7 @@ namespace Logic.AI
private float CalCityDefendScore(CityData city)
{
var score = 0f;
foreach (var unit in CityDefendUnits[city.Id]) score += unit.GetCost();
foreach (var unit in CityDefendUnits[city.Id]) score += unit.GetMilitary();
if (city.CityWall) score += 2;
return score;
}
@ -1493,7 +1469,7 @@ namespace Logic.AI
{
if (!Map.GetGridDataByUnitId(unit.Id, out var unitGrid)) continue;
var distance = Map.GridMap.CalcDistance(cityGrid, unitGrid);
score += unit.GetCost() / (distance + 1);
score += unit.GetMilitary() / (distance + 1);
}
return score;
@ -1503,7 +1479,7 @@ namespace Logic.AI
private float CalCityEnemyScore(CityData city)
{
var score = 0f;
foreach (var unit in CityEnemyUnits[city.Id]) score += unit.GetCost();
foreach (var unit in CityEnemyUnits[city.Id]) score += unit.GetMilitary();
return score;
}
@ -1542,7 +1518,7 @@ namespace Logic.AI
3 => 0,
_ => ratio
};
score += unit.GetCost() * ratio;
score += unit.GetMilitary() * ratio;
}
foreach (var unit in CityDefendUnits[city.Id])
{
@ -1559,7 +1535,7 @@ namespace Logic.AI
3 => 0,
_ => ratio
};
score -= unit.GetCost() * ratio;
score -= unit.GetMilitary() * ratio;
}
return score;
}
@ -1701,7 +1677,7 @@ namespace Logic.AI
for (int i = selfCity.Count - 1; i >= 0; i--)
{
var city = selfCity[i];
if (PlayerBorderDistance[city.Id] < 5) continue;
if (PlayerBorderDistance[city.Id] > 5) continue;
if (CityDangerScore[city.Id] <= 0) continue;
CityStrategy[city] = Strategy.Military;
selfCity.RemoveAt(i);

View File

@ -6,11 +6,13 @@
*/
using System;
using RuntimeData;
using System.Collections.Generic;
using System.Linq;
using Logic.Action;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Logic.AI
@ -707,6 +709,7 @@ namespace Logic.AI
if (type == CalculateType.CityTrainDefend) CalculateCityTrainDefend(data, param, result);
if (type == CalculateType.CityTrainAttack) CalculateCityTrainAttack(data, param, result);
if (type == CalculateType.CityTrainMilitary) CalculateCityTrainMilitary(data, param, result);
if (type == CalculateType.CityDevelopment) CalculateCityDevelopment(data, param, result);
if (type == CalculateType.CityTrainDefendAttack) CalculateCityTrainDefendAttack(data, param, result);
@ -806,7 +809,7 @@ namespace Logic.AI
foreach (var unit in param.MapData.UnitMap.UnitList)
{
if (selfUnits.Contains(unit)) continue;
score += unit.GetCost();
score += unit.GetMilitary();
}
result.Score[CalculateType.LegionDevelopmentKill] = 1f / (score + 1);
}
@ -889,7 +892,7 @@ namespace Logic.AI
{
if (!param.MapData.GetUnitDataByGid(aroundGrid.Id, out var aroundUnit)) continue;
if (!selfUnits.Contains(aroundUnit)) continue;
score += aroundUnit.GetCost();
score += aroundUnit.GetMilitary();
}
result.Score[CalculateType.LegionDefendMove] = 1 / ((float)path.length + 1) * 1000 + score / 1000f;
}
@ -925,98 +928,70 @@ namespace Logic.AI
private static void CalculateCityTrainAttack(AICalculatorData data, CommonActionParams param, CalculateResult result)
{
if (data.AttackPlayer == null) return;
if (!param.MapData.GetGridDataByCityId(param.CityData.Id, out var cityGrid)) return;
if (!param.MapData.GetUnitDataByGid(cityGrid.Id, out var newUnit)) return;
var selfUnits = new HashSet<UnitData>();
param.MapData.GetUnitDataListByPlayerId(param.PlayerData.Id, selfUnits);
if (!param.MapData.GetGridDataByCityId(param.CityData.Id, out var cityGrid)) return;
var units = new HashSet<UnitData>();
var targets = new HashSet<UnitData>();
var selfScore = 0f;
var targetScore = 0f;
var score = 0f;
foreach (var unit in param.MapData.UnitMap.UnitList)
{
if (!selfUnits.Contains(unit)) continue;
if (selfUnits.Contains(unit))
{
units.Add(unit);
selfScore += unit.GetCost();
}
else
{
targets.Add(unit);
targetScore += unit.GetCost();
}
if (selfUnits.Contains(unit)) continue;
if (!param.MapData.GetPlayerIdByUnitId(unit.Id, out var ownerId)) continue;
if (!param.PlayerData.LastAttackPlayers.Contains(ownerId) &&
!param.PlayerData.CurAttackPlayers.Contains(ownerId)) continue;
score += data.CalUnitMilitaryGapScore(param.MapData, newUnit, unit);
}
float score = selfScore - targetScore;
foreach (var selfUnit in units)
{
foreach (var target in targets)
{
score += data.CalUnitCounterScore(selfUnit, target) * 2;
score -= data.CalUnitCounterScore(target, selfUnit);
}
}
result.Score[CalculateType.CityTrainAttack] = score;
}
private static void CalculateCityTrainMilitary(AICalculatorData data, CommonActionParams param, CalculateResult result)
{
if (!param.MapData.GetGridDataByCityId(param.CityData.Id, out var cityGrid)) return;
if (!param.MapData.GetUnitDataByGid(cityGrid.Id, out var newUnit)) return;
var selfUnits = new HashSet<UnitData>();
param.MapData.GetUnitDataListByPlayerId(param.PlayerData.Id, selfUnits);
var score = 0f;
foreach (var unit in param.MapData.UnitMap.UnitList)
{
if (selfUnits.Contains(unit)) continue;
if (!param.MapData.GetGridDataByUnitId(unit.Id, out var unitGrid)) continue;
var dis = param.MapData.GridMap.CalcDistance(cityGrid, unitGrid);
if (dis > 3) continue;
score += data.CalUnitMilitaryGapScore(param.MapData, newUnit, unit);
}
result.Score[CalculateType.CityTrainMilitary] = score;
}
private static void CalculateCityTrainDefendAttack(AICalculatorData data, CommonActionParams param, CalculateResult result)
{
if (data.AttackPlayer == null) return;
if (!param.MapData.GetGridDataByCityId(param.CityData.Id, out var cityGrid)) return;
if (!param.MapData.GetUnitDataByGid(cityGrid.Id, out var newUnit)) return;
var selfUnits = new HashSet<UnitData>();
param.MapData.GetUnitDataListByPlayerId(param.PlayerData.Id, selfUnits);
if (!param.MapData.GetGridDataByCityId(param.CityData.Id, out var cityGrid)) return;
var units = new HashSet<UnitData>();
var targets = new HashSet<UnitData>();
var selfScore = 0f;
var targetScore = 0f;
var score = 0f;
foreach (var unit in param.MapData.UnitMap.UnitList)
{
if (!param.MapData.GetGridDataByUnitId(unit.Id, out var unitGrid)) continue;
var dis = param.MapData.GridMap.CalcDistance(cityGrid, unitGrid);
if (dis > 6) continue;
if (selfUnits.Contains(unit))
{
units.Add(unit);
selfScore += unit.GetCost();
}
else
{
targets.Add(unit);
targetScore += unit.GetCost();
}
if (selfUnits.Contains(unit)) continue;
if (!param.MapData.GetPlayerIdByUnitId(unit.Id, out var ownerId)) continue;
if (!param.PlayerData.LastAttackPlayers.Contains(ownerId) &&
!param.PlayerData.CurAttackPlayers.Contains(ownerId)) continue;
score += data.CalUnitMilitaryGapScore(param.MapData, newUnit, unit);
}
float score = selfScore - targetScore;
foreach (var selfUnit in units)
{
foreach (var target in targets)
{
score += data.CalUnitCounterScore(selfUnit, target) * 2;
score -= data.CalUnitCounterScore(target, selfUnit);
}
}
result.Score[CalculateType.CityTrainDefendAttack] = score;
}
private static void CalculateCityTrainDefend(AICalculatorData data, CommonActionParams param, CalculateResult result)
{
float score = 0;
var selfUnits = new HashSet<UnitData>();
param.MapData.GetUnitDataListByPlayerId(param.PlayerData.Id, selfUnits);
if (!param.MapData.GetGridDataByCityId(param.CityData.Id, out var cityGrid)) return;
if (!param.MapData.GetUnitDataByGid(cityGrid.Id, out var newUnit)) return;
foreach (var unit in selfUnits)
{
if (!param.MapData.GetGridDataByUnitId(unit.Id, out var unitGrid)) continue;
if (param.MapData.GridMap.CalcDistance(cityGrid, unitGrid) > 3) continue;
score += unit.GetDefenseValue(param.MapData) + unit.Health;
}
result.Score[CalculateType.CityTrainDefend] = score;
result.Score[CalculateType.CityTrainDefend] = newUnit.GetDefenseValue(param.MapData) + newUnit.Health;
}
private static void CalculatePlayerTechDefend(AICalculatorData data, CommonActionParams param, CalculateResult result)

View File

@ -113,14 +113,16 @@ namespace Logic.Editor
{
if (_main?.MapData == null || _player == null) return;
MainEditor.Instance.GetPlayerStrategy(_player.Id, out var playerStrategy, out var targetId, out var attackType);
MainEditor.Instance.GetPlayerStrategy(_player.Id, out var playerStrategy, out var targetIdSet);
EditorGUILayout.BeginHorizontal();
if (playerStrategy != Strategy.Attack)
InspectorUtils.InspectorTextWidthRich($"<b>玩家ID: {_player.Id}, 国家战略为: {playerStrategy}</b>");
else
{
var idStr = "";
foreach (var id in targetIdSet) idStr += $"{id}";
InspectorUtils.InspectorTextWidthRich(
$"<b>玩家ID: {_player.Id}, 国家战略为: {playerStrategy}, 目标:{targetId}, 类型:{attackType}</b>");
$"<b>玩家ID: {_player.Id}, 国家战略为: {playerStrategy}, 目标:{idStr}</b>");
}
EditorGUILayout.EndHorizontal();

View File

@ -17,8 +17,7 @@ namespace Logic
public bool IsGo = false;
public AICalculatorData Data;
private Dictionary<uint, Strategy> _playerStrategy;
private Dictionary<uint, CountryAttackType> _playerAttackType;
private Dictionary<uint, uint> _playerAttackTarget;
private Dictionary<uint, HashSet<uint>> _playerAttackTarget;
private Dictionary<uint, Strategy> _cityStrategy;
private Dictionary<uint, Strategy> _unitStrategy;
private Dictionary<uint, Strategy> _legionStrategy;
@ -33,8 +32,7 @@ namespace Logic
public MainEditor()
{
_playerStrategy = new Dictionary<uint, Strategy>();
_playerAttackType = new Dictionary<uint, CountryAttackType>();
_playerAttackTarget = new Dictionary<uint, uint>();
_playerAttackTarget = new Dictionary<uint, HashSet<uint>>();
_cityStrategy = new Dictionary<uint, Strategy>();
_unitStrategy = new Dictionary<uint, Strategy>();
_legionStrategy = new Dictionary<uint, Strategy>();
@ -62,14 +60,11 @@ namespace Logic
return _actionRecord.GetValueOrDefault(cid);
}
public void GetPlayerStrategy(uint pid, out Strategy strategy, out uint target, out CountryAttackType attackType)
public void GetPlayerStrategy(uint pid, out Strategy strategy, out HashSet<uint> target)
{
strategy = Strategy.None;
target = 0;
attackType = CountryAttackType.None;
_playerStrategy.TryGetValue(pid, out strategy);
_playerAttackTarget.TryGetValue(pid, out target);
_playerAttackType.TryGetValue(pid, out attackType);
}
public void GetUnitStrategy(uint uid, uint legion, uint playerId, out Strategy strategy, out uint cityId, out LegionStrategyType type)
@ -113,8 +108,10 @@ namespace Logic
if (Data == null) return;
if (Data.Player == null) return;
_playerStrategy[Data.Player.Id] = Data.CountryStrategy;
_playerAttackType[Data.Player.Id] = Data.AttackType;
if (Data.AttackPlayer != null) _playerAttackTarget[Data.Player.Id] = Data.AttackPlayer.Id;
if (!_playerAttackTarget.ContainsKey(Data.Player.Id))
_playerAttackTarget[Data.Player.Id] = new HashSet<uint>();
_playerAttackTarget[Data.Player.Id].Clear();
foreach (var player in Data.AttackPlayerSet) _playerAttackTarget[Data.Player.Id].Add(player.Id);
foreach (var kv in Data.CityStrategy) _cityStrategy[kv.Key.Id] = kv.Value;
foreach (var kv in Data.FreeUnitStrategy) _unitStrategy[kv.Key.Id] = kv.Value;
foreach (var kv in Data.LegionStrategy) _legionStrategy[kv.Key * 10000 + Data.Player.Id] = kv.Value;

View File

@ -85,9 +85,8 @@ namespace TH1Renderer
if (MainEditor.Instance.Data != null)
{
MainEditor.Instance.GetCityStrategy(_cityId, out var cst);
MainEditor.Instance.GetPlayerStrategy(_playerData.Id, out var pst, out var target, out var type);
MainEditor.Instance.GetPlayerStrategy(_playerData.Id, out var pst, out var target);
_debugText.text += $"CST={cst} PST={pst}";
if (pst == Strategy.Attack) _debugText.text += $"TAR={target} Type={type}";
_debugText.text += "\n";
}