docs: 新增西班牙语和日语README并优化多语言文档

新增README-ES.md(西班牙语)和README-JA.md(日语)文档,完善多语言README互链。优化各语言README徽章、技术栈、外链格式及语言切换区,提升文档一致性与可读性。
This commit is contained in:
谦君
2025-12-25 18:25:08 +08:00
parent b24a262ca7
commit 724a70bebb
72 changed files with 13300 additions and 2133 deletions

View File

@@ -1,9 +1,102 @@
import type { NPC, Planet, Player, FleetMission, SpyReport, SpiedNotification, IncomingFleetAlert, Fleet, DebrisField } from '@/types/game'
import type {
NPC,
Planet,
Player,
FleetMission,
SpyReport,
SpiedNotification,
IncomingFleetAlert,
Fleet,
DebrisField,
Resources,
TradeOffer,
IntelReport,
JointAttackInvite,
IntelType,
AidNotification,
AllyDefenseNotification,
AttitudeChangeNotification
} from '@/types/game'
import { MissionType, ShipType, TechnologyType, RelationStatus, NPCAIType } from '@/types/game'
// 重新导出类型供外部使用
export type { TradeOffer, IntelReport, JointAttackInvite, IntelType, AidNotification, AllyDefenseNotification, AttitudeChangeNotification }
import * as fleetLogic from './fleetLogic'
import * as diplomaticLogic from './diplomaticLogic'
import * as resourceLogic from './resourceLogic'
import { DIPLOMATIC_CONFIG, SHIPS } from '@/config/gameConfig'
// ========== 敌对NPC增强行为类型定义 ==========
/**
* 骚扰任务类型
*/
export type HarassmentType = 'spy' | 'raid' | 'intimidate'
/**
* 报复等级
*/
export interface RevengeLevel {
attackCount: number
fleetMultiplier: number
attackInterval: number
name: string
}
/**
* 围攻协调信息
*/
export interface SiegeCoordination {
targetPlanetId: string
targetPosition: { galaxy: number; system: number; position: number }
coordinatorNpcId: string
participantNpcIds: string[]
arrivalTime: number
startedAt: number
}
// TradeOffer, IntelReport, JointAttackInvite, IntelType 类型已移至 @/types/game.ts
/**
* NPC之间的关系
*/
export interface NPCRelation {
npcId: string
targetNpcId: string
status: 'ally' | 'neutral' | 'enemy'
strength: number // 关系强度 0-100
lastUpdated: number
}
/**
* NPC联盟
*/
export interface NPCAlliance {
id: string
name: string
leaderNpcId: string
memberNpcIds: string[]
enemyNpcIds: string[]
createdAt: number
}
/**
* 辅助函数:获取舰队中最慢船只的速度
* 用于计算飞行时间
*/
const getFleetMinSpeed = (fleet: Partial<Fleet>): number => {
let minSpeed = Infinity
for (const [shipType, count] of Object.entries(fleet)) {
if ((count || 0) > 0) {
const shipConfig = SHIPS[shipType as ShipType]
if (shipConfig) {
minSpeed = Math.min(minSpeed, shipConfig.speed)
}
}
}
return minSpeed === Infinity ? 10000 : minSpeed // 默认使用基础速度
}
/**
* AI 类型行为修改器
* 根据 NPC 的 AI 类型调整其行为参数
@@ -342,27 +435,133 @@ export const shouldNPCGiftPlayer = (npc: NPC, player: Player, currentTime: numbe
return Math.random() < giftProbability
}
/**
* 计算玩家的总资源产量(每小时)
*/
const calculatePlayerTotalProduction = (player: Player): { metal: number; crystal: number; deuterium: number } => {
let totalMetal = 0
let totalCrystal = 0
let totalDeuterium = 0
// 计算当前激活的军官加成
const bonuses = player.officers
? {
resourceProductionBonus: Object.values(player.officers).reduce((sum, officer) => {
if (officer.active && officer.expiresAt && officer.expiresAt > Date.now()) {
return sum + (officer.bonuses?.resourceProductionBonus || 0)
}
return sum
}, 0),
darkMatterProductionBonus: Object.values(player.officers).reduce((sum, officer) => {
if (officer.active && officer.expiresAt && officer.expiresAt > Date.now()) {
return sum + (officer.bonuses?.darkMatterProductionBonus || 0)
}
return sum
}, 0),
energyProductionBonus: Object.values(player.officers).reduce((sum, officer) => {
if (officer.active && officer.expiresAt && officer.expiresAt > Date.now()) {
return sum + (officer.bonuses?.energyProductionBonus || 0)
}
return sum
}, 0)
}
: { resourceProductionBonus: 0, darkMatterProductionBonus: 0, energyProductionBonus: 0 }
// 遍历所有星球计算总产量
for (const planet of player.planets) {
if (planet.isMoon) continue // 月球没有矿场
const production = resourceLogic.calculateResourceProduction(planet, bonuses)
totalMetal += production.metal || 0
totalCrystal += production.crystal || 0
totalDeuterium += production.deuterium || 0
}
return { metal: totalMetal, crystal: totalCrystal, deuterium: totalDeuterium }
}
/**
* NPC向玩家赠送资源
* 动态计算赠送量基于玩家每小时产量的4-8倍
* 赠送的资源会从NPC主星球扣除
*/
export const giftResourcesToPlayer = (npc: NPC, player: Player): void => {
const { NPC_GIFT_CONFIG } = DIPLOMATIC_CONFIG
const dynamicConfig = NPC_GIFT_CONFIG.DYNAMIC_GIFT
const baseConfig = NPC_GIFT_CONFIG.BASE_GIFT_AMOUNT
// 随机生成赠送资源量
const giftResources = {
metal:
Math.floor(Math.random() * (NPC_GIFT_CONFIG.GIFT_AMOUNT.METAL.max - NPC_GIFT_CONFIG.GIFT_AMOUNT.METAL.min + 1)) +
NPC_GIFT_CONFIG.GIFT_AMOUNT.METAL.min,
crystal:
Math.floor(Math.random() * (NPC_GIFT_CONFIG.GIFT_AMOUNT.CRYSTAL.max - NPC_GIFT_CONFIG.GIFT_AMOUNT.CRYSTAL.min + 1)) +
NPC_GIFT_CONFIG.GIFT_AMOUNT.CRYSTAL.min,
deuterium:
Math.floor(Math.random() * (NPC_GIFT_CONFIG.GIFT_AMOUNT.DEUTERIUM.max - NPC_GIFT_CONFIG.GIFT_AMOUNT.DEUTERIUM.min + 1)) +
NPC_GIFT_CONFIG.GIFT_AMOUNT.DEUTERIUM.min,
// 获取NPC主星球
const npcPlanet = npc.planets[0]
if (!npcPlanet) return
let giftResources = {
metal: 0,
crystal: 0,
deuterium: 0,
darkMatter: 0,
energy: 0
}
if (dynamicConfig?.ENABLED) {
// 动态计算:根据玩家产量
const playerProduction = calculatePlayerTotalProduction(player)
// 随机生成产量倍数4-8倍
const multiplierRange = dynamicConfig.PRODUCTION_MULTIPLIER
const multiplier = multiplierRange.min + Math.random() * (multiplierRange.max - multiplierRange.min)
// 计算赠送量(产量 × 倍数)
let metalGift = Math.floor(playerProduction.metal * multiplier)
let crystalGift = Math.floor(playerProduction.crystal * multiplier)
let deuteriumGift = Math.floor(playerProduction.deuterium * multiplier)
// 应用最小值保底
metalGift = Math.max(metalGift, dynamicConfig.MIN_AMOUNT.METAL)
crystalGift = Math.max(crystalGift, dynamicConfig.MIN_AMOUNT.CRYSTAL)
deuteriumGift = Math.max(deuteriumGift, dynamicConfig.MIN_AMOUNT.DEUTERIUM)
// 应用最大值封顶
metalGift = Math.min(metalGift, dynamicConfig.MAX_AMOUNT.METAL)
crystalGift = Math.min(crystalGift, dynamicConfig.MAX_AMOUNT.CRYSTAL)
deuteriumGift = Math.min(deuteriumGift, dynamicConfig.MAX_AMOUNT.DEUTERIUM)
giftResources.metal = metalGift
giftResources.crystal = crystalGift
giftResources.deuterium = deuteriumGift
} else {
// 使用基础配置(后备方案)
giftResources.metal = Math.floor(Math.random() * (baseConfig.METAL.max - baseConfig.METAL.min + 1)) + baseConfig.METAL.min
giftResources.crystal = Math.floor(Math.random() * (baseConfig.CRYSTAL.max - baseConfig.CRYSTAL.min + 1)) + baseConfig.CRYSTAL.min
giftResources.deuterium =
Math.floor(Math.random() * (baseConfig.DEUTERIUM.max - baseConfig.DEUTERIUM.min + 1)) + baseConfig.DEUTERIUM.min
}
// 根据好感度额外加成:好感度越高,赠送越多
const relation = npc.relations?.[player.id]
if (relation && relation.reputation > 60) {
// 好感度60-100区间额外增加0-40%
const reputationBonus = 1 + (relation.reputation - 60) / 100
giftResources.metal = Math.floor(giftResources.metal * reputationBonus)
giftResources.crystal = Math.floor(giftResources.crystal * reputationBonus)
giftResources.deuterium = Math.floor(giftResources.deuterium * reputationBonus)
}
// 限制赠送量不超过NPC拥有的资源只赠送NPC实际拥有的部分
giftResources.metal = Math.min(giftResources.metal, Math.floor(npcPlanet.resources.metal))
giftResources.crystal = Math.min(giftResources.crystal, Math.floor(npcPlanet.resources.crystal))
giftResources.deuterium = Math.min(giftResources.deuterium, Math.floor(npcPlanet.resources.deuterium))
// 如果NPC资源不足所有资源都为0则不赠送
if (giftResources.metal <= 0 && giftResources.crystal <= 0 && giftResources.deuterium <= 0) {
return
}
// 从NPC星球扣除资源
npcPlanet.resources.metal -= giftResources.metal
npcPlanet.resources.crystal -= giftResources.crystal
npcPlanet.resources.deuterium -= giftResources.deuterium
// 处理赠送
diplomaticLogic.handleNPCGiftToPlayer(npc, player, giftResources)
@@ -370,6 +569,161 @@ export const giftResourcesToPlayer = (npc: NPC, player: Player): void => {
;(npc as any).lastGiftTime = Date.now()
}
/**
* 检查NPC是否应该协防玩家
* 当玩家受到攻击且NPC是友好状态时触发
*/
export const shouldNPCDefendPlayer = (npc: NPC, player: Player, currentTime: number): boolean => {
const { ALLY_DEFENSE_CONFIG } = DIPLOMATIC_CONFIG
// 检查功能是否启用
if (!ALLY_DEFENSE_CONFIG?.ENABLED) {
return false
}
// 检查好感度
const relation = npc.relations?.[player.id]
if (!relation || relation.reputation < ALLY_DEFENSE_CONFIG.MIN_REPUTATION) {
return false
}
// 检查上次协防时间
const lastDefendTime = (npc as any).lastDefendTime || 0
if (currentTime - lastDefendTime < ALLY_DEFENSE_CONFIG.CHECK_INTERVAL * 1000) {
return false
}
// 检查当前协防任务数量
const activeDefenseMissions = npc.fleetMissions?.filter(m => m.missionType === MissionType.Station && m.status === 'outbound').length || 0
if (activeDefenseMissions >= ALLY_DEFENSE_CONFIG.MAX_CONCURRENT_DEFENSES) {
return false
}
// 检查玩家是否有来袭攻击舰队
const incomingAttacks =
player.incomingFleetAlerts?.filter(
alert => alert.missionType === MissionType.Attack && alert.fleetSize >= ALLY_DEFENSE_CONFIG.MIN_INCOMING_FLEET_SIZE
) || []
if (incomingAttacks.length === 0) {
return false
}
// 根据好感度计算协防概率
const reputationBonus = (relation.reputation - ALLY_DEFENSE_CONFIG.MIN_REPUTATION) / 30 // 70-100区间
const defenseProbability = ALLY_DEFENSE_CONFIG.BASE_DEFENSE_PROBABILITY + reputationBonus * 0.3
return Math.random() < defenseProbability
}
/**
* NPC派舰队协防玩家
*/
export const sendDefenseFleet = (npc: NPC, _player: Player, targetPlanet: Planet): FleetMission | null => {
const { ALLY_DEFENSE_CONFIG } = DIPLOMATIC_CONFIG
// 选择最近且有舰队的NPC星球
const sourcePlanet = selectBestNPCPlanet(npc, targetPlanet.position)
if (!sourcePlanet) return null
// 计算派遣舰队战斗舰船的30%-60%
const fleetRatio =
ALLY_DEFENSE_CONFIG.FLEET_RATIO.min + Math.random() * (ALLY_DEFENSE_CONFIG.FLEET_RATIO.max - ALLY_DEFENSE_CONFIG.FLEET_RATIO.min)
const combatShipTypes = [
ShipType.LightFighter,
ShipType.HeavyFighter,
ShipType.Cruiser,
ShipType.Battleship,
ShipType.Battlecruiser,
ShipType.Bomber,
ShipType.Destroyer
]
const defenseFleet: Partial<Fleet> = {}
let hasShips = false
for (const shipType of combatShipTypes) {
const available = sourcePlanet.fleet[shipType] || 0
if (available > 0) {
const toSend = Math.floor(available * fleetRatio)
if (toSend > 0) {
defenseFleet[shipType] = toSend
sourcePlanet.fleet[shipType] = available - toSend
hasShips = true
}
}
}
if (!hasShips) return null
// 计算飞行时间
const distance = fleetLogic.calculateDistance(sourcePlanet.position, targetPlanet.position)
const minSpeed = getFleetMinSpeed(defenseFleet)
const flightTime = fleetLogic.calculateFlightTime(distance, minSpeed)
const currentTime = Date.now()
const arrivalTime = currentTime + flightTime
// 创建协防任务
const mission: FleetMission = {
id: `ally_defend_${currentTime}_${npc.id}`,
playerId: npc.id,
npcId: npc.id,
originPlanetId: sourcePlanet.id,
targetPosition: targetPlanet.position,
targetPlanetId: targetPlanet.id,
fleet: defenseFleet as Fleet,
missionType: MissionType.Station,
departureTime: currentTime,
arrivalTime: arrivalTime,
returnTime: arrivalTime + ALLY_DEFENSE_CONFIG.STATION_DURATION,
status: 'outbound',
cargo: { metal: 0, crystal: 0, deuterium: 0, darkMatter: 0, energy: 0 },
isGift: false,
isHostile: false // 盟友协防不是敌对任务
}
// 添加到NPC任务列表
if (!npc.fleetMissions) {
npc.fleetMissions = []
}
npc.fleetMissions.push(mission)
// 更新上次协防时间
;(npc as any).lastDefendTime = currentTime
return mission
}
/**
* 检查并执行NPC协防行为
*/
export const checkAndExecuteAllyDefense = (npc: NPC, player: Player, currentTime: number): void => {
if (!shouldNPCDefendPlayer(npc, player, currentTime)) {
return
}
// 找到受攻击的玩家星球
const incomingAttacks = player.incomingFleetAlerts?.filter(alert => alert.missionType === MissionType.Attack) || []
if (incomingAttacks.length === 0) return
// 选择一个受攻击的星球进行协防
const targetAlert = incomingAttacks[Math.floor(Math.random() * incomingAttacks.length)]
if (!targetAlert) return
const targetPlanet = player.planets.find(p => p.id === targetAlert.targetPlanetId)
if (!targetPlanet) return
// 派遣协防舰队
const mission = sendDefenseFleet(npc, player, targetPlanet)
if (mission) {
// 可以在这里添加通知玩家的逻辑
diplomaticLogic.notifyPlayerOfAllyDefense(npc, player, targetPlanet, mission)
}
}
/**
* 选择NPC的最佳攻击来源星球
*/
@@ -795,7 +1149,10 @@ export const updateNPCBehavior = (
giftResourcesToPlayer(npc, player)
}
// 6. 更新即将到来的舰队警告(删除过期的
// 6. 检查是否应该协防玩家仅友好NPC玩家被攻击时
checkAndExecuteAllyDefense(npc, player, currentTime)
// 7. 更新即将到来的舰队警告(删除过期的)
updateIncomingFleetAlerts(player, currentTime)
}
@@ -898,7 +1255,10 @@ export const updateNPCBehaviorWithLimit = (
giftResourcesToPlayer(npc, player)
}
// 6. 更新即将到来的舰队警告(删除过期的
// 6. 检查是否应该协防玩家仅友好NPC玩家被攻击时不受并发限制
checkAndExecuteAllyDefense(npc, player, currentTime)
// 7. 更新即将到来的舰队警告(删除过期的)
updateIncomingFleetAlerts(player, currentTime)
return { spyCreated, attackCreated }
@@ -1552,3 +1912,1875 @@ export const diagnoseNPCBehavior = (npcs: NPC[], player: Player, currentTime: nu
}
})
}
// ========== 敌对NPC增强行为系统 ==========
/**
* 获取NPC的报复等级
* 基于被攻击次数确定报复强度
*/
export const getRevengeLevel = (npc: NPC, playerId: string): RevengeLevel => {
const { HOSTILE_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const levels = HOSTILE_BEHAVIOR_CONFIG.REVENGE_ESCALATION.LEVELS
const memoryDuration = HOSTILE_BEHAVIOR_CONFIG.REVENGE_ESCALATION.MEMORY_DURATION
// 默认等级(用于数组为空或未找到时)
const defaultLevel: RevengeLevel = levels[0] || { attackCount: 1, fleetMultiplier: 1.0, attackInterval: 600, name: 'mild' }
const attackRecord = npc.attackedBy?.[playerId]
if (!attackRecord) {
return defaultLevel // 默认最低等级
}
// 检查记忆是否过期
const now = Date.now()
if (now - attackRecord.lastAttackTime > memoryDuration) {
return defaultLevel // 记忆过期,重置为最低等级
}
// 根据被攻击次数确定报复等级
const attackCount = attackRecord.count
let currentLevel = defaultLevel
for (const level of levels) {
if (attackCount >= level.attackCount) {
currentLevel = level
}
}
return currentLevel
}
/**
* 检查NPC是否应该执行骚扰战术
*/
export const shouldNPCHarass = (npc: NPC, player: Player, currentTime: number): boolean => {
const { HOSTILE_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const harassConfig = HOSTILE_BEHAVIOR_CONFIG.HARASSMENT
if (!harassConfig.ENABLED) {
return false
}
// 检查外交关系
const relation = npc.relations?.[player.id]
if (!relation || relation.status !== RelationStatus.Hostile) {
return false
}
// 检查好感度是否足够低
if (relation.reputation > harassConfig.TRIGGER_REPUTATION) {
return false
}
// 检查骚扰冷却时间
const lastHarassTime = (npc as any).lastHarassTime || 0
if (currentTime - lastHarassTime < harassConfig.INTERVAL * 1000) {
return false
}
// 概率判断
return Math.random() < harassConfig.PROBABILITY
}
/**
* 选择骚扰类型
*/
export const selectHarassmentType = (): HarassmentType => {
const { HOSTILE_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const types = HOSTILE_BEHAVIOR_CONFIG.HARASSMENT.TYPES
const rand = Math.random()
if (rand < types.spy) {
return 'spy'
} else if (rand < types.spy + types.raid) {
return 'raid'
} else {
return 'intimidate'
}
}
/**
* 创建骚扰任务
*/
export const createHarassmentMission = (
npc: NPC,
player: Player,
allPlanets: Planet[],
harassmentType: HarassmentType
): FleetMission | null => {
const { HOSTILE_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const harassConfig = HOSTILE_BEHAVIOR_CONFIG.HARASSMENT
// 选择随机玩家星球作为目标
const playerPlanets = allPlanets.filter(p => p.ownerId === player.id)
if (playerPlanets.length === 0) return null
const targetPlanet = playerPlanets[Math.floor(Math.random() * playerPlanets.length)]
if (!targetPlanet) return null
// 选择NPC最佳星球
const npcPlanet = selectBestNPCPlanet(npc, targetPlanet.position)
if (!npcPlanet) return null
let fleet: Partial<Fleet> = {}
let missionType: MissionType = MissionType.Attack
if (harassmentType === 'spy') {
// 侦查骚扰:派出间谍探测器
const probes = npcPlanet.fleet[ShipType.EspionageProbe] || 0
if (probes < 1) return null
fleet = { [ShipType.EspionageProbe]: Math.min(probes, 3) }
missionType = MissionType.Spy
} else {
// 袭击或威慑:派出小规模战斗舰队
const fleetRatio =
harassConfig.FLEET_SIZE_RATIO.min + Math.random() * (harassConfig.FLEET_SIZE_RATIO.max - harassConfig.FLEET_SIZE_RATIO.min)
const combatShips = [ShipType.LightFighter, ShipType.HeavyFighter, ShipType.Cruiser]
let hasShips = false
for (const shipType of combatShips) {
const available = npcPlanet.fleet[shipType] || 0
if (available > 0) {
const sendCount = Math.max(1, Math.floor(available * fleetRatio))
fleet[shipType] = sendCount
hasShips = true
}
}
if (!hasShips) return null
// 威慑任务使用部署类型(不攻击,只是展示武力)
if (harassmentType === 'intimidate') {
missionType = MissionType.Deploy
}
}
// 从NPC星球扣除舰队
for (const [shipType, count] of Object.entries(fleet)) {
npcPlanet.fleet[shipType as ShipType] = (npcPlanet.fleet[shipType as ShipType] || 0) - (count as number)
}
// 计算飞行时间
const distance = fleetLogic.calculateDistance(npcPlanet.position, targetPlanet.position)
const fleetMinSpeed = getFleetMinSpeed(fleet)
const flightTime = fleetLogic.calculateFlightTime(distance, fleetMinSpeed)
const now = Date.now()
const mission: FleetMission = {
id: `npc-harass-${harassmentType}-${npc.id}-${now}`,
playerId: npc.id,
npcId: npc.id,
isHostile: harassmentType !== 'intimidate', // 威慑不是敌对行动
originPlanetId: npcPlanet.id,
targetPosition: targetPlanet.position,
targetPlanetId: targetPlanet.id,
missionType,
fleet,
cargo: { metal: 0, crystal: 0, deuterium: 0, darkMatter: 0, energy: 0 },
departureTime: now,
arrivalTime: now + flightTime * 1000,
status: 'outbound'
}
// 更新骚扰时间
;(npc as any).lastHarassTime = now
// 添加到NPC任务列表
if (!npc.fleetMissions) {
npc.fleetMissions = []
}
npc.fleetMissions.push(mission)
return mission
}
/**
* 检查是否可以发起围攻
* 需要多个敌对NPC协调
*/
export const canInitiateSiege = (npcs: NPC[], player: Player, currentTime: number): { canSiege: boolean; eligibleNpcs: NPC[] } => {
const { HOSTILE_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const siegeConfig = HOSTILE_BEHAVIOR_CONFIG.SIEGE
if (!siegeConfig.ENABLED) {
return { canSiege: false, eligibleNpcs: [] }
}
// 找出所有符合围攻条件的敌对NPC
const eligibleNpcs = npcs.filter(npc => {
const relation = npc.relations?.[player.id]
if (!relation || relation.status !== RelationStatus.Hostile) {
return false
}
// 检查好感度是否足够低
if (relation.reputation > siegeConfig.TRIGGER_REPUTATION) {
return false
}
// 检查围攻冷却
const lastSiegeTime = (npc as any).lastSiegeTime || 0
if (currentTime - lastSiegeTime < siegeConfig.COOLDOWN) {
return false
}
// 检查是否有足够的舰队
const npcPlanet = npc.planets[0]
if (!npcPlanet) return false
const combatPower = calculateNPCCombatPower(npcPlanet)
return combatPower >= MIN_COMBAT_POWER_FOR_SPY * 10 // 围攻需要较大战力
})
// 检查是否有足够的NPC参与围攻
const canSiege = eligibleNpcs.length >= siegeConfig.MIN_HOSTILE_NPCS
return { canSiege, eligibleNpcs }
}
/**
* 发起围攻
* 协调多个NPC同时攻击玩家
*/
export const initiateSiege = (
eligibleNpcs: NPC[],
player: Player,
allPlanets: Planet[]
): { missions: FleetMission[]; coordination: SiegeCoordination } | null => {
const { HOSTILE_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const siegeConfig = HOSTILE_BEHAVIOR_CONFIG.SIEGE
if (eligibleNpcs.length < siegeConfig.MIN_HOSTILE_NPCS) {
return null
}
// 选择目标星球(选择资源最多的)
const playerPlanets = allPlanets.filter(p => p.ownerId === player.id)
if (playerPlanets.length === 0) return null
let targetPlanet = playerPlanets[0]
let maxResources = 0
for (const planet of playerPlanets) {
const totalResources = planet.resources.metal + planet.resources.crystal + planet.resources.deuterium
if (totalResources > maxResources) {
maxResources = totalResources
targetPlanet = planet
}
}
if (!targetPlanet) return null
// 计算统一到达时间以最远NPC的飞行时间为基准
let maxFlightTime = 0
for (const npc of eligibleNpcs) {
const npcPlanet = selectBestNPCPlanet(npc, targetPlanet.position)
if (npcPlanet) {
const distance = fleetLogic.calculateDistance(npcPlanet.position, targetPlanet.position)
const flightTime = fleetLogic.calculateFlightTime(distance, 10000) // 使用基准速度
maxFlightTime = Math.max(maxFlightTime, flightTime)
}
}
const now = Date.now()
const coordWindow = siegeConfig.COORDINATION_WINDOW
const baseArrivalTime = now + maxFlightTime * 1000 + coordWindow
const missions: FleetMission[] = []
const participantNpcIds: string[] = []
// 为每个NPC创建攻击任务
for (const npc of eligibleNpcs) {
const npcPlanet = selectBestNPCPlanet(npc, targetPlanet.position)
if (!npcPlanet) continue
// 计算围攻舰队
const fleetRatio = siegeConfig.FLEET_RATIO.min + Math.random() * (siegeConfig.FLEET_RATIO.max - siegeConfig.FLEET_RATIO.min)
const combatShips = [
ShipType.LightFighter,
ShipType.HeavyFighter,
ShipType.Cruiser,
ShipType.Battleship,
ShipType.Bomber,
ShipType.Destroyer,
ShipType.Battlecruiser
]
const siegeFleet: Partial<Fleet> = {}
let hasShips = false
for (const shipType of combatShips) {
const available = npcPlanet.fleet[shipType] || 0
if (available > 0) {
const sendCount = Math.max(1, Math.floor(available * fleetRatio))
siegeFleet[shipType] = sendCount
hasShips = true
}
}
if (!hasShips) continue
// 从NPC星球扣除舰队
for (const [shipType, count] of Object.entries(siegeFleet)) {
npcPlanet.fleet[shipType as ShipType] = (npcPlanet.fleet[shipType as ShipType] || 0) - (count as number)
}
// 计算随机偏移的到达时间(在协调窗口内)
const arrivalOffset = Math.random() * coordWindow
const arrivalTime = baseArrivalTime + arrivalOffset
// 反推出发时间
const distance = fleetLogic.calculateDistance(npcPlanet.position, targetPlanet.position)
const siegeMinSpeed = getFleetMinSpeed(siegeFleet)
const actualFlightTime = fleetLogic.calculateFlightTime(distance, siegeMinSpeed)
const departureTime = arrivalTime - actualFlightTime * 1000
const mission: FleetMission = {
id: `npc-siege-${npc.id}-${now}`,
playerId: npc.id,
npcId: npc.id,
isHostile: true,
originPlanetId: npcPlanet.id,
targetPosition: targetPlanet.position,
targetPlanetId: targetPlanet.id,
missionType: MissionType.Attack,
fleet: siegeFleet,
cargo: { metal: 0, crystal: 0, deuterium: 0, darkMatter: 0, energy: 0 },
departureTime: Math.max(now, departureTime),
arrivalTime,
status: 'outbound'
}
// 更新NPC的围攻时间
;(npc as any).lastSiegeTime = now
// 添加到NPC任务列表
if (!npc.fleetMissions) {
npc.fleetMissions = []
}
npc.fleetMissions.push(mission)
missions.push(mission)
participantNpcIds.push(npc.id)
}
if (missions.length < siegeConfig.MIN_HOSTILE_NPCS) {
return null // 没有足够的NPC成功发起围攻
}
const coordination: SiegeCoordination = {
targetPlanetId: targetPlanet.id,
targetPosition: targetPlanet.position,
coordinatorNpcId: eligibleNpcs[0]?.id || '',
participantNpcIds,
arrivalTime: baseArrivalTime,
startedAt: now
}
return { missions, coordination }
}
/**
* 执行报复升级攻击
* 根据报复等级派出不同强度的攻击
*/
export const executeEscalatedRevenge = (
npc: NPC,
player: Player,
allPlanets: Planet[],
config: DynamicBehaviorConfig
): FleetMission | null => {
const { HOSTILE_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const escalationConfig = HOSTILE_BEHAVIOR_CONFIG.REVENGE_ESCALATION
if (!escalationConfig.ENABLED) {
return null
}
// 获取报复等级
const revengeLevel = getRevengeLevel(npc, player.id)
// 检查攻击间隔
const lastRevengeTime = npc.lastAttackTime || 0
const now = Date.now()
if (now - lastRevengeTime < revengeLevel.attackInterval * 1000) {
return null
}
// 找到攻击者的星球
const attackRecord = npc.attackedBy?.[player.id]
if (!attackRecord?.planetId) {
return null
}
const targetPlanet = allPlanets.find(p => p.id === attackRecord.planetId)
if (!targetPlanet) {
return null
}
// 选择NPC最佳星球
const npcPlanet = selectBestNPCPlanet(npc, targetPlanet.position)
if (!npcPlanet) {
return null
}
// 根据报复等级计算舰队规模
const baseFleetRatio = config.attackFleetSizeRatio
const escalatedRatio = Math.min(1.0, baseFleetRatio * revengeLevel.fleetMultiplier)
const combatShips = [
ShipType.LightFighter,
ShipType.HeavyFighter,
ShipType.Cruiser,
ShipType.Battleship,
ShipType.Bomber,
ShipType.Destroyer,
ShipType.Battlecruiser,
ShipType.Deathstar
]
const revengeFleet: Partial<Fleet> = {}
let hasShips = false
for (const shipType of combatShips) {
const available = npcPlanet.fleet[shipType] || 0
if (available > 0) {
const sendCount = Math.max(1, Math.floor(available * escalatedRatio))
revengeFleet[shipType] = sendCount
hasShips = true
}
}
if (!hasShips) {
return null
}
// 从NPC星球扣除舰队
for (const [shipType, count] of Object.entries(revengeFleet)) {
npcPlanet.fleet[shipType as ShipType] = (npcPlanet.fleet[shipType as ShipType] || 0) - (count as number)
}
// 计算飞行时间
const distance = fleetLogic.calculateDistance(npcPlanet.position, targetPlanet.position)
const revengeMinSpeed = getFleetMinSpeed(revengeFleet)
const flightTime = fleetLogic.calculateFlightTime(distance, revengeMinSpeed)
const mission: FleetMission = {
id: `npc-revenge-escalated-${revengeLevel.name}-${npc.id}-${now}`,
playerId: npc.id,
npcId: npc.id,
isHostile: true,
originPlanetId: npcPlanet.id,
targetPosition: targetPlanet.position,
targetPlanetId: targetPlanet.id,
missionType: MissionType.Attack,
fleet: revengeFleet,
cargo: { metal: 0, crystal: 0, deuterium: 0, darkMatter: 0, energy: 0 },
departureTime: now,
arrivalTime: now + flightTime * 1000,
status: 'outbound'
}
// 更新攻击时间
npc.lastAttackTime = now
// 添加到NPC任务列表
if (!npc.fleetMissions) {
npc.fleetMissions = []
}
npc.fleetMissions.push(mission)
return mission
}
/**
* 呼叫盟友NPC助战
* 在报复等级较高时,可能呼叫盟友一起攻击
*/
export const callAlliesForRevenge = (
npc: NPC,
allNpcs: NPC[],
player: Player,
allPlanets: Planet[],
_config: DynamicBehaviorConfig
): FleetMission[] => {
const { HOSTILE_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const escalationConfig = HOSTILE_BEHAVIOR_CONFIG.REVENGE_ESCALATION
if (!escalationConfig.CALL_ALLIES) {
return []
}
// 获取报复等级
const revengeLevel = getRevengeLevel(npc, player.id)
// 计算呼叫盟友概率(报复等级越高概率越大)
const levelIndex = HOSTILE_BEHAVIOR_CONFIG.REVENGE_ESCALATION.LEVELS.findIndex(l => l.name === revengeLevel.name)
const allyCallProbability = escalationConfig.ALLY_CALL_BASE_PROBABILITY * (levelIndex + 1)
if (Math.random() > allyCallProbability) {
return []
}
// 找到NPC的盟友同样敌对玩家的NPC
const allyMissions: FleetMission[] = []
const attackRecord = npc.attackedBy?.[player.id]
if (!attackRecord?.planetId) {
return []
}
const targetPlanet = allPlanets.find(p => p.id === attackRecord.planetId)
if (!targetPlanet) {
return []
}
for (const allyNpc of allNpcs) {
if (allyNpc.id === npc.id) continue // 跳过自己
// 检查是否是盟友(也敌对玩家)
const allyRelation = allyNpc.relations?.[player.id]
if (!allyRelation || allyRelation.status !== RelationStatus.Hostile) {
continue
}
// 检查NPC之间是否有盟友关系
const interNpcRelation = allyNpc.allies?.includes(npc.id) || npc.allies?.includes(allyNpc.id)
if (!interNpcRelation) {
// 即使不是正式盟友敌对同一玩家的NPC也有概率响应
if (Math.random() > 0.3) continue
}
// 选择盟友NPC的最佳星球
const allyPlanet = selectBestNPCPlanet(allyNpc, targetPlanet.position)
if (!allyPlanet) continue
// 派出援军舰队(较小规模)
const combatShips = [ShipType.LightFighter, ShipType.HeavyFighter, ShipType.Cruiser, ShipType.Battleship]
const allyFleet: Partial<Fleet> = {}
let hasShips = false
for (const shipType of combatShips) {
const available = allyPlanet.fleet[shipType] || 0
if (available > 0) {
const sendCount = Math.max(1, Math.floor(available * 0.3)) // 援军派30%
allyFleet[shipType] = sendCount
hasShips = true
}
}
if (!hasShips) continue
// 从盟友星球扣除舰队
for (const [shipType, count] of Object.entries(allyFleet)) {
allyPlanet.fleet[shipType as ShipType] = (allyPlanet.fleet[shipType as ShipType] || 0) - (count as number)
}
// 计算飞行时间
const distance = fleetLogic.calculateDistance(allyPlanet.position, targetPlanet.position)
const allyMinSpeed = getFleetMinSpeed(allyFleet)
const flightTime = fleetLogic.calculateFlightTime(distance, allyMinSpeed)
const now = Date.now()
const mission: FleetMission = {
id: `npc-ally-revenge-${allyNpc.id}-${now}`,
playerId: allyNpc.id,
npcId: allyNpc.id,
isHostile: true,
originPlanetId: allyPlanet.id,
targetPosition: targetPlanet.position,
targetPlanetId: targetPlanet.id,
missionType: MissionType.Attack,
fleet: allyFleet,
cargo: { metal: 0, crystal: 0, deuterium: 0, darkMatter: 0, energy: 0 },
departureTime: now,
arrivalTime: now + flightTime * 1000,
status: 'outbound'
}
// 添加到盟友NPC任务列表
if (!allyNpc.fleetMissions) {
allyNpc.fleetMissions = []
}
allyNpc.fleetMissions.push(mission)
allyMissions.push(mission)
}
return allyMissions
}
/**
* 增强版NPC行为更新函数
* 包含围攻、骚扰、报复升级等增强行为
*/
export const updateHostileNPCBehavior = (
npc: NPC,
allNpcs: NPC[],
player: Player,
allPlanets: Planet[],
_debrisFields: Record<string, DebrisField>,
currentTime: number,
activeSiege?: SiegeCoordination
): {
harassMission?: FleetMission
siegeMissions?: FleetMission[]
revengeMission?: FleetMission
allyRevengeMissions?: FleetMission[]
newSiegeCoordination?: SiegeCoordination
} => {
const result: {
harassMission?: FleetMission
siegeMissions?: FleetMission[]
revengeMission?: FleetMission
allyRevengeMissions?: FleetMission[]
newSiegeCoordination?: SiegeCoordination
} = {}
const config = calculateDynamicBehavior(player.points)
// 检查是否是敌对NPC
const relation = npc.relations?.[player.id]
if (!relation || relation.status !== RelationStatus.Hostile) {
return result
}
// 1. 检查报复升级(优先级最高)
if (npc.revengeTarget === player.id) {
const revengeMission = executeEscalatedRevenge(npc, player, allPlanets, config)
if (revengeMission) {
result.revengeMission = revengeMission
// 创建警告
const targetPlanet = allPlanets.find(p => p.id === revengeMission.targetPlanetId)
if (targetPlanet) {
const alert = createIncomingFleetAlert(revengeMission, npc, targetPlanet)
if (!player.incomingFleetAlerts) {
player.incomingFleetAlerts = []
}
player.incomingFleetAlerts.push(alert)
}
// 呼叫盟友助战
const allyMissions = callAlliesForRevenge(npc, allNpcs, player, allPlanets, config)
if (allyMissions.length > 0) {
result.allyRevengeMissions = allyMissions
// 为盟友任务创建警告
for (const allyMission of allyMissions) {
const targetPlanet = allPlanets.find(p => p.id === allyMission.targetPlanetId)
const allyNpc = allNpcs.find(n => n.id === allyMission.npcId)
if (targetPlanet && allyNpc) {
const alert = createIncomingFleetAlert(allyMission, allyNpc, targetPlanet)
player.incomingFleetAlerts.push(alert)
}
}
}
return result // 报复后不执行其他行为
}
}
// 2. 检查围攻(如果没有正在进行的围攻)
if (!activeSiege) {
const { canSiege, eligibleNpcs } = canInitiateSiege(allNpcs, player, currentTime)
if (canSiege && eligibleNpcs.includes(npc)) {
// 概率触发围攻
const { HOSTILE_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
if (Math.random() < HOSTILE_BEHAVIOR_CONFIG.SIEGE.BASE_PROBABILITY) {
const siegeResult = initiateSiege(eligibleNpcs, player, allPlanets)
if (siegeResult) {
result.siegeMissions = siegeResult.missions
result.newSiegeCoordination = siegeResult.coordination
// 为所有围攻任务创建警告
for (const mission of siegeResult.missions) {
const targetPlanet = allPlanets.find(p => p.id === mission.targetPlanetId)
const attackerNpc = allNpcs.find(n => n.id === mission.npcId)
if (targetPlanet && attackerNpc) {
const alert = createIncomingFleetAlert(mission, attackerNpc, targetPlanet)
if (!player.incomingFleetAlerts) {
player.incomingFleetAlerts = []
}
player.incomingFleetAlerts.push(alert)
}
}
return result // 围攻后不执行其他行为
}
}
}
}
// 3. 检查骚扰战术
if (shouldNPCHarass(npc, player, currentTime)) {
const harassmentType = selectHarassmentType()
const harassMission = createHarassmentMission(npc, player, allPlanets, harassmentType)
if (harassMission) {
result.harassMission = harassMission
// 创建警告
const targetPlanet = allPlanets.find(p => p.id === harassMission.targetPlanetId)
if (targetPlanet) {
const alert = createIncomingFleetAlert(harassMission, npc, targetPlanet)
if (!player.incomingFleetAlerts) {
player.incomingFleetAlerts = []
}
player.incomingFleetAlerts.push(alert)
}
}
}
return result
}
// ========== 中立NPC行为系统 ==========
/**
* 检查中立NPC是否应该提议贸易
*/
export const shouldNPCOfferTrade = (npc: NPC, player: Player, currentTime: number): boolean => {
const { NEUTRAL_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const tradeConfig = NEUTRAL_BEHAVIOR_CONFIG.TRADE
if (!tradeConfig.ENABLED) {
return false
}
// 检查玩家当前贸易提议数量是否已达上限
const maxOffers = (tradeConfig as any).MAX_PENDING_OFFERS || 30
if ((player.tradeOffers?.length || 0) >= maxOffers) {
return false
}
// 检查外交关系
const relation = npc.relations?.[player.id]
if (!relation || relation.status !== RelationStatus.Neutral) {
return false
}
// 检查好感度范围
if (relation.reputation < tradeConfig.MIN_REPUTATION || relation.reputation > tradeConfig.MAX_REPUTATION) {
return false
}
// 检查贸易冷却
const lastTradeTime = (npc as any).lastTradeOfferTime || 0
if (currentTime - lastTradeTime < tradeConfig.CHECK_INTERVAL * 1000) {
return false
}
// 概率判断
return Math.random() < tradeConfig.PROBABILITY
}
/**
* 创建贸易提议
*/
export const createTradeOffer = (npc: NPC, player: Player): TradeOffer | null => {
const { NEUTRAL_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const tradeConfig = NEUTRAL_BEHAVIOR_CONFIG.TRADE
// 获取NPC主星球
const npcPlanet = npc.planets[0]
if (!npcPlanet) return null
// 计算玩家总产量
const playerProduction = calculatePlayerTotalProduction(player)
// 随机决定贸易量
const tradeMultiplier = tradeConfig.TRADE_AMOUNT.min + Math.random() * (tradeConfig.TRADE_AMOUNT.max - tradeConfig.TRADE_AMOUNT.min)
// 随机选择交易类型
const tradeTypes: Array<{ offer: 'metal' | 'crystal' | 'deuterium'; request: 'metal' | 'crystal' | 'deuterium'; rate: number }> = [
{ offer: 'crystal', request: 'metal', rate: tradeConfig.EXCHANGE_RATES.metalToCrystal },
{ offer: 'deuterium', request: 'metal', rate: tradeConfig.EXCHANGE_RATES.metalToDeuterium },
{ offer: 'deuterium', request: 'crystal', rate: tradeConfig.EXCHANGE_RATES.crystalToDeuterium }
]
const selectedTrade = tradeTypes[Math.floor(Math.random() * tradeTypes.length)]
if (!selectedTrade) return null
// 计算交易量基于玩家产量和NPC资源
const baseAmount = playerProduction[selectedTrade.request] * tradeMultiplier
const npcHas = Math.floor(npcPlanet.resources[selectedTrade.offer] || 0)
// 验证基础数值有效性
if (!isFinite(baseAmount) || baseAmount <= 0 || !isFinite(npcHas) || npcHas <= 0) {
return null
}
// NPC提供的资源量
const offerAmount = Math.min(Math.floor(baseAmount / selectedTrade.rate), npcHas)
if (!isFinite(offerAmount) || offerAmount <= 0) return null
// 玩家需要支付的资源量(含手续费)
const requestAmount = Math.floor(offerAmount * selectedTrade.rate * (1 + tradeConfig.FEE_PERCENTAGE / 100))
if (!isFinite(requestAmount) || requestAmount <= 0) return null
const now = Date.now()
const offer: TradeOffer = {
id: `trade-${npc.id}-${now}`,
npcId: npc.id,
npcName: npc.name,
timestamp: now,
offeredResources: {
type: selectedTrade.offer,
amount: offerAmount
},
requestedResources: {
type: selectedTrade.request,
amount: requestAmount
},
expiresAt: now + 30 * 60 * 1000, // 30分钟后过期
status: 'pending'
}
// 更新NPC的贸易时间
;(npc as any).lastTradeOfferTime = now
return offer
}
/**
* 处理贸易接受
*/
export const acceptTradeOffer = (
offer: TradeOffer,
npc: NPC,
player: Player,
playerPlanet: Planet
): { success: boolean; reason?: string } => {
const { NEUTRAL_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const tradeConfig = NEUTRAL_BEHAVIOR_CONFIG.TRADE
// 检查贸易是否过期
if (Date.now() > offer.expiresAt) {
offer.status = 'expired'
return { success: false, reason: 'errors.tradeExpired' }
}
// 检查玩家是否有足够资源
const playerHas = playerPlanet.resources[offer.requestedResources.type]
if (playerHas < offer.requestedResources.amount) {
return { success: false, reason: 'errors.insufficientResources' }
}
// 获取NPC主星球
const npcPlanet = npc.planets[0]
if (!npcPlanet) {
return { success: false, reason: 'errors.npcPlanetNotFound' }
}
// 检查NPC是否还有足够资源
const npcHas = npcPlanet.resources[offer.offeredResources.type]
if (npcHas < offer.offeredResources.amount) {
return { success: false, reason: 'errors.npcInsufficientResources' }
}
// 执行交易
// 从玩家扣除
playerPlanet.resources[offer.requestedResources.type] -= offer.requestedResources.amount
// 给玩家资源
playerPlanet.resources[offer.offeredResources.type] += offer.offeredResources.amount
// 从NPC扣除
npcPlanet.resources[offer.offeredResources.type] -= offer.offeredResources.amount
// 给NPC资源
npcPlanet.resources[offer.requestedResources.type] += offer.requestedResources.amount
// 增加好感度
const relation = npc.relations?.[player.id]
if (relation) {
relation.reputation = Math.min(DIPLOMATIC_CONFIG.MAX_REPUTATION, relation.reputation + tradeConfig.REPUTATION_GAIN)
relation.lastUpdated = Date.now()
}
offer.status = 'accepted'
return { success: true }
}
/**
* 检查中立NPC是否应该摇摆态度
*/
export const shouldNPCSwingAttitude = (
npc: NPC,
player: Player,
currentTime: number
): { shouldSwing: boolean; direction?: 'friendly' | 'hostile' } => {
const { NEUTRAL_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const swingConfig = NEUTRAL_BEHAVIOR_CONFIG.SWING
if (!swingConfig.ENABLED) {
return { shouldSwing: false }
}
// 检查外交关系
const relation = npc.relations?.[player.id]
if (!relation || relation.status !== RelationStatus.Neutral) {
return { shouldSwing: false }
}
// 检查摇摆冷却
const lastSwingCheck = (npc as any).lastSwingCheck || 0
if (currentTime - lastSwingCheck < swingConfig.CHECK_INTERVAL * 1000) {
return { shouldSwing: false }
}
// 更新检查时间
;(npc as any).lastSwingCheck = currentTime
// 检查是否达到摇摆阈值
if (relation.reputation >= swingConfig.SWING_THRESHOLD.toFriendly) {
// 好感度足够高,可能变友好
const probability = swingConfig.BASE_PROBABILITY * (relation.reputation / 20)
if (Math.random() < probability) {
return { shouldSwing: true, direction: 'friendly' }
}
} else if (relation.reputation <= swingConfig.SWING_THRESHOLD.toHostile) {
// 好感度足够低,可能变敌对
const probability = swingConfig.BASE_PROBABILITY * (Math.abs(relation.reputation) / 20)
if (Math.random() < probability) {
return { shouldSwing: true, direction: 'hostile' }
}
}
return { shouldSwing: false }
}
/**
* 执行NPC态度摇摆
*/
export const executeNPCSwing = (npc: NPC, player: Player, direction: 'friendly' | 'hostile'): void => {
const relation = npc.relations?.[player.id]
if (!relation) return
if (direction === 'friendly') {
relation.status = RelationStatus.Friendly
relation.reputation = Math.max(relation.reputation, DIPLOMATIC_CONFIG.FRIENDLY_THRESHOLD + 5)
} else {
relation.status = RelationStatus.Hostile
relation.reputation = Math.min(relation.reputation, DIPLOMATIC_CONFIG.HOSTILE_THRESHOLD - 5)
}
relation.lastUpdated = Date.now()
}
/**
* 中立NPC观察附近事件并调整好感度
*/
export const observeNearbyEvents = (neutralNpc: NPC, eventNpc: NPC, player: Player, eventType: 'attack' | 'help'): void => {
const { NEUTRAL_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const observeConfig = NEUTRAL_BEHAVIOR_CONFIG.OBSERVE
if (!observeConfig.ENABLED) return
// 检查是否是中立NPC
const relation = neutralNpc.relations?.[player.id]
if (!relation || relation.status !== RelationStatus.Neutral) return
// 检查是否在同一星系(如果配置要求)
if (observeConfig.SAME_GALAXY_ONLY) {
const neutralPlanet = neutralNpc.planets[0]
const eventPlanet = eventNpc.planets[0]
if (!neutralPlanet || !eventPlanet) return
if (neutralPlanet.position.galaxy !== eventPlanet.position.galaxy) return
}
// 根据事件类型调整好感度
if (eventType === 'attack') {
relation.reputation = Math.max(DIPLOMATIC_CONFIG.MIN_REPUTATION, relation.reputation + observeConfig.ATTACK_NEARBY_PENALTY)
} else if (eventType === 'help') {
relation.reputation = Math.min(DIPLOMATIC_CONFIG.MAX_REPUTATION, relation.reputation + observeConfig.HELP_NEARBY_BONUS)
}
relation.lastUpdated = Date.now()
}
// ========== 友好NPC增强行为系统 ==========
/**
* 检查友好NPC是否应该分享情报
*/
export const shouldNPCShareIntel = (npc: NPC, player: Player, currentTime: number): boolean => {
const { FRIENDLY_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const intelConfig = FRIENDLY_BEHAVIOR_CONFIG.INTEL_SHARING
if (!intelConfig.ENABLED) {
return false
}
// 检查外交关系
const relation = npc.relations?.[player.id]
if (!relation || relation.status !== RelationStatus.Friendly) {
return false
}
// 检查好感度
if (relation.reputation < intelConfig.MIN_REPUTATION) {
return false
}
// 检查分享冷却
const lastIntelTime = (npc as any).lastIntelShareTime || 0
if (currentTime - lastIntelTime < intelConfig.INTERVAL * 1000) {
return false
}
// 概率判断
return Math.random() < intelConfig.PROBABILITY
}
/**
* 选择情报类型
*/
export const selectIntelType = (): IntelType => {
const { FRIENDLY_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const types = FRIENDLY_BEHAVIOR_CONFIG.INTEL_SHARING.INTEL_TYPES
const rand = Math.random()
if (rand < types.enemyFleet) {
return 'enemyFleet'
} else if (rand < types.enemyFleet + types.enemyResources) {
return 'enemyResources'
} else {
return 'enemyMovement'
}
}
/**
* 创建情报报告
*/
export const createIntelReport = (friendlyNpc: NPC, allNpcs: NPC[], player: Player): IntelReport | null => {
// 找到一个敌对NPC作为情报目标
const hostileNpcs = allNpcs.filter(n => {
const relation = n.relations?.[player.id]
return relation && relation.status === RelationStatus.Hostile
})
if (hostileNpcs.length === 0) return null
const targetNpc = hostileNpcs[Math.floor(Math.random() * hostileNpcs.length)]
if (!targetNpc) return null
const targetPlanet = targetNpc.planets[0]
if (!targetPlanet) return null
const intelType = selectIntelType()
const now = Date.now()
const report: IntelReport = {
id: `intel-${friendlyNpc.id}-${now}`,
fromNpcId: friendlyNpc.id,
fromNpcName: friendlyNpc.name,
timestamp: now,
targetNpcId: targetNpc.id,
targetNpcName: targetNpc.name,
intelType,
data: {},
read: false
}
// 根据情报类型填充数据
switch (intelType) {
case 'enemyFleet':
report.data.fleet = { ...targetPlanet.fleet }
break
case 'enemyResources':
report.data.resources = { ...targetPlanet.resources }
break
case 'enemyMovement':
// 检查NPC是否有正在进行的任务
const activeMission = targetNpc.fleetMissions?.find(m => m.status === 'outbound')
if (activeMission) {
report.data.movement = {
targetPosition: activeMission.targetPosition,
arrivalTime: activeMission.arrivalTime,
missionType: activeMission.missionType
}
} else {
// 没有活动任务,改为分享舰队信息
report.intelType = 'enemyFleet'
report.data.fleet = { ...targetPlanet.fleet }
}
break
}
// 更新NPC的情报分享时间
;(friendlyNpc as any).lastIntelShareTime = now
return report
}
/**
* 检查友好NPC是否应该邀请联合攻击
*/
export const shouldNPCInviteJointAttack = (npc: NPC, player: Player, currentTime: number): boolean => {
const { FRIENDLY_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const jointConfig = FRIENDLY_BEHAVIOR_CONFIG.JOINT_ATTACK
if (!jointConfig.ENABLED) {
return false
}
// 检查外交关系
const relation = npc.relations?.[player.id]
if (!relation || relation.status !== RelationStatus.Friendly) {
return false
}
// 检查好感度
if (relation.reputation < jointConfig.MIN_REPUTATION) {
return false
}
// 检查邀请冷却
const lastInviteTime = (npc as any).lastJointAttackInvite || 0
if (currentTime - lastInviteTime < jointConfig.INTERVAL * 1000) {
return false
}
// 概率判断
return Math.random() < jointConfig.PROBABILITY
}
/**
* 创建联合攻击邀请
*/
export const createJointAttackInvite = (friendlyNpc: NPC, allNpcs: NPC[], player: Player): JointAttackInvite | null => {
const { FRIENDLY_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const jointConfig = FRIENDLY_BEHAVIOR_CONFIG.JOINT_ATTACK
// 找到合适的攻击目标
let targetNpc: NPC | null = null
if (jointConfig.PREFER_COMMON_ENEMY) {
// 优先选择共同敌人对友好NPC也敌对的NPC
const commonEnemies = allNpcs.filter(n => {
const playerRelation = n.relations?.[player.id]
const npcRelation = n.relations?.[friendlyNpc.id]
return playerRelation?.status === RelationStatus.Hostile && npcRelation?.status === RelationStatus.Hostile
})
if (commonEnemies.length > 0) {
targetNpc = commonEnemies[Math.floor(Math.random() * commonEnemies.length)] || null
}
}
// 如果没有共同敌人选择任意敌对NPC
if (!targetNpc) {
const hostileNpcs = allNpcs.filter(n => {
const relation = n.relations?.[player.id]
return relation && relation.status === RelationStatus.Hostile
})
if (hostileNpcs.length > 0) {
targetNpc = hostileNpcs[Math.floor(Math.random() * hostileNpcs.length)] || null
}
}
if (!targetNpc) return null
const targetPlanet = targetNpc.planets[0]
if (!targetPlanet) return null
// 计算NPC承诺的舰队
const npcPlanet = friendlyNpc.planets[0]
if (!npcPlanet) return null
const fleetRatio = jointConfig.NPC_FLEET_RATIO.min + Math.random() * (jointConfig.NPC_FLEET_RATIO.max - jointConfig.NPC_FLEET_RATIO.min)
const combatShips = [
ShipType.LightFighter,
ShipType.HeavyFighter,
ShipType.Cruiser,
ShipType.Battleship,
ShipType.Bomber,
ShipType.Destroyer
]
const committedFleet: Partial<Fleet> = {}
let hasShips = false
for (const shipType of combatShips) {
const available = npcPlanet.fleet[shipType] || 0
if (available > 0) {
const commitCount = Math.floor(available * fleetRatio)
if (commitCount > 0) {
committedFleet[shipType] = commitCount
hasShips = true
}
}
}
if (!hasShips) return null
const now = Date.now()
const invite: JointAttackInvite = {
id: `joint-attack-${friendlyNpc.id}-${now}`,
fromNpcId: friendlyNpc.id,
fromNpcName: friendlyNpc.name,
timestamp: now,
targetNpcId: targetNpc.id,
targetNpcName: targetNpc.name,
targetPlanetId: targetPlanet.id,
targetPosition: targetPlanet.position,
npcFleetCommitment: committedFleet,
expectedLootRatio: jointConfig.PLAYER_LOOT_RATIO,
expiresAt: now + 2 * 60 * 60 * 1000, // 2小时后过期
status: 'pending'
}
// 更新NPC的邀请时间
;(friendlyNpc as any).lastJointAttackInvite = now
return invite
}
/**
* 检查友好NPC是否应该提供资源援助
*/
export const shouldNPCProvideAid = (npc: NPC, player: Player, currentTime: number): boolean => {
const { FRIENDLY_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const aidConfig = FRIENDLY_BEHAVIOR_CONFIG.RESOURCE_AID
if (!aidConfig.ENABLED) {
return false
}
// 检查外交关系
const relation = npc.relations?.[player.id]
if (!relation || relation.status !== RelationStatus.Friendly) {
return false
}
// 检查好感度
if (relation.reputation < aidConfig.MIN_REPUTATION) {
return false
}
// 检查援助冷却
const lastAidTime = (npc as any).lastAidTime || 0
if (currentTime - lastAidTime < aidConfig.CHECK_INTERVAL * 1000) {
return false
}
// 检查玩家是否资源紧张
const playerProduction = calculatePlayerTotalProduction(player)
const lowResourceThreshold = {
metal: playerProduction.metal * aidConfig.TRIGGER_LOW_RESOURCES_HOURS,
crystal: playerProduction.crystal * aidConfig.TRIGGER_LOW_RESOURCES_HOURS,
deuterium: playerProduction.deuterium * aidConfig.TRIGGER_LOW_RESOURCES_HOURS
}
// 检查玩家总资源
let totalPlayerResources = { metal: 0, crystal: 0, deuterium: 0 }
for (const planet of player.planets) {
totalPlayerResources.metal += planet.resources.metal
totalPlayerResources.crystal += planet.resources.crystal
totalPlayerResources.deuterium += planet.resources.deuterium
}
// 如果玩家资源充足,不援助
if (
totalPlayerResources.metal > lowResourceThreshold.metal &&
totalPlayerResources.crystal > lowResourceThreshold.crystal &&
totalPlayerResources.deuterium > lowResourceThreshold.deuterium
) {
return false
}
// 概率判断
return Math.random() < aidConfig.PROBABILITY
}
/**
* 执行资源援助
*/
export const executeResourceAid = (npc: NPC, player: Player): Resources | null => {
const { FRIENDLY_BEHAVIOR_CONFIG } = DIPLOMATIC_CONFIG
const aidConfig = FRIENDLY_BEHAVIOR_CONFIG.RESOURCE_AID
// 获取NPC主星球
const npcPlanet = npc.planets[0]
if (!npcPlanet) return null
// 计算援助量
const playerProduction = calculatePlayerTotalProduction(player)
const aidAmount = {
metal: Math.floor(playerProduction.metal * aidConfig.AID_AMOUNT_HOURS),
crystal: Math.floor(playerProduction.crystal * aidConfig.AID_AMOUNT_HOURS),
deuterium: Math.floor(playerProduction.deuterium * aidConfig.AID_AMOUNT_HOURS),
darkMatter: 0,
energy: 0
}
// 限制为NPC实际拥有的资源
aidAmount.metal = Math.min(aidAmount.metal, Math.floor(npcPlanet.resources.metal * 0.5))
aidAmount.crystal = Math.min(aidAmount.crystal, Math.floor(npcPlanet.resources.crystal * 0.5))
aidAmount.deuterium = Math.min(aidAmount.deuterium, Math.floor(npcPlanet.resources.deuterium * 0.5))
// 如果援助量太少,不援助
if (aidAmount.metal <= 0 && aidAmount.crystal <= 0 && aidAmount.deuterium <= 0) {
return null
}
// 从NPC扣除
npcPlanet.resources.metal -= aidAmount.metal
npcPlanet.resources.crystal -= aidAmount.crystal
npcPlanet.resources.deuterium -= aidAmount.deuterium
// 给玩家主星球
const playerMainPlanet = player.planets[0]
if (playerMainPlanet) {
playerMainPlanet.resources.metal += aidAmount.metal
playerMainPlanet.resources.crystal += aidAmount.crystal
playerMainPlanet.resources.deuterium += aidAmount.deuterium
}
// 更新援助时间
;(npc as any).lastAidTime = Date.now()
return aidAmount
}
/**
* 更新中立NPC行为
*/
export const updateNeutralNPCBehavior = (
npc: NPC,
_allNpcs: NPC[],
player: Player,
currentTime: number
): {
tradeOffer?: TradeOffer
swingDirection?: 'friendly' | 'hostile'
} => {
const result: {
tradeOffer?: TradeOffer
swingDirection?: 'friendly' | 'hostile'
} = {}
// 检查是否是中立NPC
const relation = npc.relations?.[player.id]
if (!relation || relation.status !== RelationStatus.Neutral) {
return result
}
// 1. 检查贸易提议
if (shouldNPCOfferTrade(npc, player, currentTime)) {
const offer = createTradeOffer(npc, player)
if (offer) {
result.tradeOffer = offer
}
}
// 2. 检查态度摇摆
const swingResult = shouldNPCSwingAttitude(npc, player, currentTime)
if (swingResult.shouldSwing && swingResult.direction) {
executeNPCSwing(npc, player, swingResult.direction)
result.swingDirection = swingResult.direction
}
return result
}
/**
* 更新友好NPC行为
*/
export const updateFriendlyNPCBehavior = (
npc: NPC,
allNpcs: NPC[],
player: Player,
currentTime: number
): {
intelReport?: IntelReport
jointAttackInvite?: JointAttackInvite
aidProvided?: Resources
} => {
const result: {
intelReport?: IntelReport
jointAttackInvite?: JointAttackInvite
aidProvided?: Resources
} = {}
// 检查是否是友好NPC
const relation = npc.relations?.[player.id]
if (!relation || relation.status !== RelationStatus.Friendly) {
return result
}
// 1. 检查情报分享
if (shouldNPCShareIntel(npc, player, currentTime)) {
const report = createIntelReport(npc, allNpcs, player)
if (report) {
result.intelReport = report
}
}
// 2. 检查联合攻击邀请
if (shouldNPCInviteJointAttack(npc, player, currentTime)) {
const invite = createJointAttackInvite(npc, allNpcs, player)
if (invite) {
result.jointAttackInvite = invite
}
}
// 3. 检查资源援助
if (shouldNPCProvideAid(npc, player, currentTime)) {
const aid = executeResourceAid(npc, player)
if (aid) {
result.aidProvided = aid
}
}
return result
}
/**
* 综合NPC行为更新函数
* 根据NPC与玩家的关系状态调用相应的行为更新
*/
export const updateAllNPCBehaviors = (
npcs: NPC[],
player: Player,
allPlanets: Planet[],
debrisFields: Record<string, DebrisField>,
currentTime: number,
activeSiege?: SiegeCoordination
): {
hostileResults: Map<string, ReturnType<typeof updateHostileNPCBehavior>>
neutralResults: Map<string, ReturnType<typeof updateNeutralNPCBehavior>>
friendlyResults: Map<string, ReturnType<typeof updateFriendlyNPCBehavior>>
newSiegeCoordination?: SiegeCoordination
} => {
const hostileResults = new Map<string, ReturnType<typeof updateHostileNPCBehavior>>()
const neutralResults = new Map<string, ReturnType<typeof updateNeutralNPCBehavior>>()
const friendlyResults = new Map<string, ReturnType<typeof updateFriendlyNPCBehavior>>()
let newSiegeCoordination: SiegeCoordination | undefined
for (const npc of npcs) {
const relation = npc.relations?.[player.id]
if (relation?.status === RelationStatus.Hostile) {
// 敌对NPC
const result = updateHostileNPCBehavior(npc, npcs, player, allPlanets, debrisFields, currentTime, activeSiege)
hostileResults.set(npc.id, result)
if (result.newSiegeCoordination) {
newSiegeCoordination = result.newSiegeCoordination
}
} else if (relation?.status === RelationStatus.Neutral) {
// 中立NPC
const result = updateNeutralNPCBehavior(npc, npcs, player, currentTime)
neutralResults.set(npc.id, result)
} else if (relation?.status === RelationStatus.Friendly) {
// 友好NPC
const result = updateFriendlyNPCBehavior(npc, npcs, player, currentTime)
friendlyResults.set(npc.id, result)
}
}
return {
hostileResults,
neutralResults,
friendlyResults,
newSiegeCoordination
}
}
// ========== NPC联盟系统 ==========
/**
* 获取NPC之间的AI类型兼容性分数
*/
export const getAITypeCompatibility = (type1?: NPCAIType, type2?: NPCAIType): number => {
const { NPC_ALLIANCE_CONFIG } = DIPLOMATIC_CONFIG
const compatibility = NPC_ALLIANCE_CONFIG.INTER_NPC_RELATIONS.TYPE_COMPATIBILITY
// 默认类型为平衡型
const t1 = type1 || NPCAIType.Balanced
const t2 = type2 || NPCAIType.Balanced
// 商人型与任何类型都友好
if (t1 === NPCAIType.Trader || t2 === NPCAIType.Trader) {
return compatibility.trader_any
}
// 侵略型与防守型互为敌人
if ((t1 === NPCAIType.Aggressive && t2 === NPCAIType.Defensive) || (t1 === NPCAIType.Defensive && t2 === NPCAIType.Aggressive)) {
return compatibility.aggressive_defensive
}
// 扩张型互相竞争
if (t1 === NPCAIType.Expansionist && t2 === NPCAIType.Expansionist) {
return compatibility.expansionist_expansionist
}
// 平衡型保持中立
if (t1 === NPCAIType.Balanced || t2 === NPCAIType.Balanced) {
return compatibility.balanced_any
}
// 默认中立
return 0
}
/**
* 初始化NPC之间的关系
*/
export const initializeInterNPCRelations = (npcs: NPC[]): void => {
const { NPC_ALLIANCE_CONFIG } = DIPLOMATIC_CONFIG
if (!NPC_ALLIANCE_CONFIG.ENABLED) return
const config = NPC_ALLIANCE_CONFIG.INTER_NPC_RELATIONS
for (const npc of npcs) {
if (!npc.allies) npc.allies = []
if (!npc.enemies) npc.enemies = []
const npcPlanet = npc.planets[0]
if (!npcPlanet) continue
for (const otherNpc of npcs) {
if (npc.id === otherNpc.id) continue
const otherPlanet = otherNpc.planets[0]
if (!otherPlanet) continue
// 计算关系分数
let relationScore = 0
// 1. AI类型兼容性
const typeCompatibility = getAITypeCompatibility(npc.aiType, otherNpc.aiType)
relationScore += typeCompatibility * 50 // 将-1到1映射到-50到50
// 2. 同一星系加成
if (npcPlanet.position.galaxy === otherPlanet.position.galaxy) {
relationScore += config.SAME_GALAXY_ALLY_BONUS * 100 // 30点加成
}
// 3. 随机因素如果是mixed模式
if (config.INIT_MODE === 'mixed' || config.INIT_MODE === 'random') {
relationScore += (Math.random() - 0.5) * 40 // -20到20的随机值
}
// 根据分数决定关系
if (relationScore > 30) {
// 盟友
if (!npc.allies.includes(otherNpc.id)) {
npc.allies.push(otherNpc.id)
}
} else if (relationScore < -30) {
// 敌人
if (!npc.enemies.includes(otherNpc.id)) {
npc.enemies.push(otherNpc.id)
}
}
// 否则保持中立
}
}
}
/**
* 传播连坐效应
* 当玩家攻击/帮助NPC时影响其盟友的好感度
*/
export const propagateGuiltByAssociation = (
targetNpc: NPC,
allNpcs: NPC[],
player: Player,
eventType: 'attack' | 'help',
depth: number = 0
): void => {
const { NPC_ALLIANCE_CONFIG } = DIPLOMATIC_CONFIG
const guiltConfig = NPC_ALLIANCE_CONFIG.GUILT_BY_ASSOCIATION
if (!guiltConfig.ENABLED) return
if (depth >= guiltConfig.MAX_PROPAGATION_DEPTH) return
// 获取目标NPC的盟友
const allies = targetNpc.allies || []
for (const allyId of allies) {
const allyNpc = allNpcs.find(n => n.id === allyId)
if (!allyNpc) continue
// 获取盟友与玩家的关系
const relation = allyNpc.relations?.[player.id]
if (!relation) continue
// 计算好感度变化
let reputationChange = eventType === 'attack' ? guiltConfig.ALLY_REPUTATION_PENALTY : guiltConfig.ALLY_REPUTATION_BONUS
// 如果启用强度乘数,根据传播深度减弱效果
if (guiltConfig.STRENGTH_MULTIPLIER) {
reputationChange = Math.floor(reputationChange * Math.pow(0.5, depth))
}
// 应用好感度变化
relation.reputation = Math.max(
DIPLOMATIC_CONFIG.MIN_REPUTATION,
Math.min(DIPLOMATIC_CONFIG.MAX_REPUTATION, relation.reputation + reputationChange)
)
relation.lastUpdated = Date.now()
// 更新关系状态
if (relation.reputation < DIPLOMATIC_CONFIG.HOSTILE_THRESHOLD) {
relation.status = RelationStatus.Hostile
} else if (relation.reputation > DIPLOMATIC_CONFIG.FRIENDLY_THRESHOLD) {
relation.status = RelationStatus.Friendly
} else {
relation.status = RelationStatus.Neutral
}
// 递归传播到盟友的盟友
propagateGuiltByAssociation(allyNpc, allNpcs, player, eventType, depth + 1)
}
}
/**
* NPC盟友互助当NPC被攻击时盟友可能响应
*/
export const checkAllyMutualDefense = (
attackedNpc: NPC,
attackerPlayerId: string,
allNpcs: NPC[],
allPlanets: Planet[],
currentTime: number
): FleetMission[] => {
const { NPC_ALLIANCE_CONFIG } = DIPLOMATIC_CONFIG
const defenseConfig = NPC_ALLIANCE_CONFIG.MUTUAL_DEFENSE
if (!defenseConfig.ENABLED) return []
const defenseMissions: FleetMission[] = []
const allies = attackedNpc.allies || []
// 找到攻击者的星球
const attackerPlanet = allPlanets.find(p => p.ownerId === attackerPlayerId)
if (!attackerPlanet) return []
for (const allyId of allies) {
const allyNpc = allNpcs.find(n => n.id === allyId)
if (!allyNpc) continue
// 检查响应冷却
const lastDefenseTime = (allyNpc as any).lastMutualDefenseTime || 0
if (currentTime - lastDefenseTime < defenseConfig.COOLDOWN * 1000) {
continue
}
// 概率检查
if (Math.random() > defenseConfig.RESPONSE_PROBABILITY) {
continue
}
// 选择盟友最佳星球
const allyPlanet = selectBestNPCPlanet(allyNpc, attackerPlanet.position)
if (!allyPlanet) continue
// 计算响应舰队
const fleetRatio = defenseConfig.FLEET_RATIO.min + Math.random() * (defenseConfig.FLEET_RATIO.max - defenseConfig.FLEET_RATIO.min)
const combatShips = [
ShipType.LightFighter,
ShipType.HeavyFighter,
ShipType.Cruiser,
ShipType.Battleship,
ShipType.Bomber,
ShipType.Destroyer
]
const defenseFleet: Partial<Fleet> = {}
let hasShips = false
for (const shipType of combatShips) {
const available = allyPlanet.fleet[shipType] || 0
if (available > 0) {
const sendCount = Math.max(1, Math.floor(available * fleetRatio))
defenseFleet[shipType] = sendCount
hasShips = true
}
}
if (!hasShips) continue
// 从盟友星球扣除舰队
for (const [shipType, count] of Object.entries(defenseFleet)) {
allyPlanet.fleet[shipType as ShipType] = (allyPlanet.fleet[shipType as ShipType] || 0) - (count as number)
}
// 计算飞行时间
const distance = fleetLogic.calculateDistance(allyPlanet.position, attackerPlanet.position)
const defenseMinSpeed = getFleetMinSpeed(defenseFleet)
const flightTime = fleetLogic.calculateFlightTime(distance, defenseMinSpeed)
const now = Date.now()
const mission: FleetMission = {
id: `npc-mutual-defense-${allyNpc.id}-${now}`,
playerId: allyNpc.id,
npcId: allyNpc.id,
isHostile: true,
originPlanetId: allyPlanet.id,
targetPosition: attackerPlanet.position,
targetPlanetId: attackerPlanet.id,
missionType: MissionType.Attack,
fleet: defenseFleet,
cargo: { metal: 0, crystal: 0, deuterium: 0, darkMatter: 0, energy: 0 },
departureTime: now,
arrivalTime: now + flightTime * 1000,
status: 'outbound'
}
// 更新响应时间
;(allyNpc as any).lastMutualDefenseTime = now
// 添加到盟友NPC任务列表
if (!allyNpc.fleetMissions) {
allyNpc.fleetMissions = []
}
allyNpc.fleetMissions.push(mission)
defenseMissions.push(mission)
}
return defenseMissions
}
/**
* NPC之间的资源共享
*/
export const executeNPCResourceSharing = (npcs: NPC[], currentTime: number): void => {
const { NPC_ALLIANCE_CONFIG } = DIPLOMATIC_CONFIG
const sharingConfig = NPC_ALLIANCE_CONFIG.RESOURCE_SHARING
if (!sharingConfig.ENABLED) return
for (const npc of npcs) {
// 检查共享冷却
const lastShareTime = (npc as any).lastResourceShareTime || 0
if (currentTime - lastShareTime < sharingConfig.INTERVAL * 1000) {
continue
}
const npcPlanet = npc.planets[0]
if (!npcPlanet) continue
const allies = npc.allies || []
if (allies.length === 0) continue
// 计算可共享资源
const shareAmount = {
metal: Math.floor(npcPlanet.resources.metal * sharingConfig.SHARE_RATIO),
crystal: Math.floor(npcPlanet.resources.crystal * sharingConfig.SHARE_RATIO),
deuterium: Math.floor(npcPlanet.resources.deuterium * sharingConfig.SHARE_RATIO)
}
// 平均分配给所有盟友
const perAlly = {
metal: Math.floor(shareAmount.metal / allies.length),
crystal: Math.floor(shareAmount.crystal / allies.length),
deuterium: Math.floor(shareAmount.deuterium / allies.length)
}
if (perAlly.metal <= 0 && perAlly.crystal <= 0 && perAlly.deuterium <= 0) {
continue
}
// 从NPC扣除
npcPlanet.resources.metal -= perAlly.metal * allies.length
npcPlanet.resources.crystal -= perAlly.crystal * allies.length
npcPlanet.resources.deuterium -= perAlly.deuterium * allies.length
// 分配给盟友
for (const allyId of allies) {
const allyNpc = npcs.find(n => n.id === allyId)
if (!allyNpc) continue
const allyPlanet = allyNpc.planets[0]
if (!allyPlanet) continue
allyPlanet.resources.metal += perAlly.metal
allyPlanet.resources.crystal += perAlly.crystal
allyPlanet.resources.deuterium += perAlly.deuterium
}
// 更新共享时间
;(npc as any).lastResourceShareTime = currentTime
}
}
/**
* 获取NPC的所有盟友信息
*/
export const getNPCAllies = (npc: NPC, allNpcs: NPC[]): NPC[] => {
const allies: NPC[] = []
const allyIds = npc.allies || []
for (const allyId of allyIds) {
const allyNpc = allNpcs.find(n => n.id === allyId)
if (allyNpc) {
allies.push(allyNpc)
}
}
return allies
}
/**
* 获取NPC的所有敌人信息
*/
export const getNPCEnemies = (npc: NPC, allNpcs: NPC[]): NPC[] => {
const enemies: NPC[] = []
const enemyIds = npc.enemies || []
for (const enemyId of enemyIds) {
const enemyNpc = allNpcs.find(n => n.id === enemyId)
if (enemyNpc) {
enemies.push(enemyNpc)
}
}
return enemies
}
/**
* 增强版NPC被攻击处理
* 包含连坐效应和盟友互助
*/
export const handleNPCAttackedWithAlliance = (
npc: NPC,
attackerId: string,
attackerPlanetId: string | undefined,
allNpcs: NPC[],
player: Player,
allPlanets: Planet[],
currentTime: number
): FleetMission[] => {
// 基础被攻击处理
handleNPCAttacked(npc, attackerId, attackerPlanetId)
// 传播连坐效应
propagateGuiltByAssociation(npc, allNpcs, player, 'attack')
// 检查盟友互助
const defenseMissions = checkAllyMutualDefense(npc, attackerId, allNpcs, allPlanets, currentTime)
return defenseMissions
}
/**
* 更新NPC联盟系统
* 在游戏循环中调用
*/
export const updateNPCAllianceSystem = (npcs: NPC[], currentTime: number): void => {
const { NPC_ALLIANCE_CONFIG } = DIPLOMATIC_CONFIG
if (!NPC_ALLIANCE_CONFIG.ENABLED) return
// 执行NPC之间的资源共享
executeNPCResourceSharing(npcs, currentTime)
}