mirror of
https://github.com/setube/ogame-vue-ts.git
synced 2026-05-12 07:55:11 +08:00
撤回
This commit is contained in:
1438
src/App.vue
1438
src/App.vue
@@ -414,8 +414,6 @@
|
||||
<HintToast />
|
||||
<!-- Toast 通知 -->
|
||||
<Sonner position="top-center" />
|
||||
<!-- 调试面板(仅开发环境) -->
|
||||
<DebugOverlay />
|
||||
<!-- 重命名星球对话框 -->
|
||||
<Dialog v-model:open="renameDialogOpen">
|
||||
<DialogContent class="sm:max-w-md">
|
||||
@@ -478,12 +476,6 @@
|
||||
import { useTheme } from '@/composables/useTheme'
|
||||
import { useI18n } from '@/composables/useI18n'
|
||||
import { useGameConfig } from '@/composables/useGameConfig'
|
||||
import { useGameLoop } from '@/composables/useGameLoop'
|
||||
import { createGameEngine, type GameEngine } from '@/services/gameEngine'
|
||||
import { createMissionEngine, type MissionEngine } from '@/services/missionEngine'
|
||||
import { createNpcEngine, type NpcEngine } from '@/services/npcEngine'
|
||||
import { createEconomyEngine, type EconomyEngine } from '@/services/economyEngine'
|
||||
import { createProgressionEngine, type ProgressionEngine } from '@/services/progressionEngine'
|
||||
import { localeNames, detectBrowserLocale, type Locale } from '@/locales'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
@@ -526,8 +518,9 @@
|
||||
import HintToast from '@/components/notifications/HintToast.vue'
|
||||
import BackToTop from '@/components/common/BackToTop.vue'
|
||||
import Sonner from '@/components/ui/sonner/Sonner.vue'
|
||||
import DebugOverlay from '@/components/debug/DebugOverlay.vue'
|
||||
import { BuildingType, TechnologyType } from '@/types/game'
|
||||
import { MissionType, BuildingType, TechnologyType, DiplomaticEventType, ShipType } from '@/types/game'
|
||||
import type { FleetMission, NPC, MissileAttack } from '@/types/game'
|
||||
import { DIPLOMATIC_CONFIG } from '@/config/gameConfig'
|
||||
import type { VersionInfo } from '@/utils/versionCheck'
|
||||
import { formatNumber, getResourceColor } from '@/utils/format'
|
||||
import { scaleNumber, scaleResources } from '@/utils/speed'
|
||||
@@ -557,15 +550,21 @@
|
||||
Crown,
|
||||
Scroll
|
||||
} from 'lucide-vue-next'
|
||||
import * as gameLogic from '@/logic/gameLogic'
|
||||
import * as planetLogic from '@/logic/planetLogic'
|
||||
import * as officerLogic from '@/logic/officerLogic'
|
||||
import * as buildingValidation from '@/logic/buildingValidation'
|
||||
import * as resourceLogic from '@/logic/resourceLogic'
|
||||
import * as researchValidation from '@/logic/researchValidation'
|
||||
import * as fleetLogic from '@/logic/fleetLogic'
|
||||
import * as shipLogic from '@/logic/shipLogic'
|
||||
import * as npcGrowthLogic from '@/logic/npcGrowthLogic'
|
||||
import * as npcBehaviorLogic from '@/logic/npcBehaviorLogic'
|
||||
import * as diplomaticLogic from '@/logic/diplomaticLogic'
|
||||
import * as publicLogic from '@/logic/publicLogic'
|
||||
import * as oreDepositLogic from '@/logic/oreDepositLogic'
|
||||
import { generateRandomPosition, generatePositionKey, shouldInitializeGame, initializePlayer } from '@/logic/gameLogic'
|
||||
import { countOldFormatNPCs, updateNPCName } from '@/logic/npcNameGenerator'
|
||||
import * as campaignLogic from '@/logic/campaignLogic'
|
||||
import { generateNPCName, countOldFormatNPCs, updateNPCName } from '@/logic/npcNameGenerator'
|
||||
import pkg from '../package.json'
|
||||
import { toast } from 'vue-sonner'
|
||||
import { migrateGameData } from '@/utils/migration'
|
||||
@@ -602,14 +601,14 @@
|
||||
const sidebarOpen = ref(window.innerWidth >= 1024)
|
||||
// 移动端资源栏展开状态
|
||||
const resourceBarExpanded = ref(false)
|
||||
// 游戏引擎
|
||||
let gameEngine: GameEngine | null = null
|
||||
let missionEngine: MissionEngine | null = null
|
||||
let npcEngine: NpcEngine | null = null
|
||||
let economyEngine: EconomyEngine | null = null
|
||||
let progressionEngine: ProgressionEngine | null = null
|
||||
const npcUpdateCounter = ref(0) // 累计秒数
|
||||
const NPC_UPDATE_INTERVAL = 5 // 每1秒更新一次NPC,确保发育速度与玩家相当
|
||||
// NPC行为系统更新函数(侦查和攻击决策)
|
||||
const npcBehaviorCounter = ref(0)
|
||||
const NPC_BEHAVIOR_INTERVAL = 5 // 每5秒检查一次NPC行为
|
||||
|
||||
// 游戏循环定时器
|
||||
const gameLoop = ref<ReturnType<typeof setInterval> | null>(null)
|
||||
const pointsUpdateInterval = ref<ReturnType<typeof setInterval> | null>(null)
|
||||
const konamiCleanup = ref<(() => void) | null>(null)
|
||||
const versionCheckInterval = ref<ReturnType<typeof setInterval> | null>(null) // 重命名星球相关状态
|
||||
@@ -819,7 +818,7 @@
|
||||
}
|
||||
|
||||
const initGame = async () => {
|
||||
const shouldInit = shouldInitializeGame(gameStore.player.planets)
|
||||
const shouldInit = gameLogic.shouldInitializeGame(gameStore.player.planets)
|
||||
if (!shouldInit) {
|
||||
const now = Date.now()
|
||||
// 迁移矿脉储量数据(为没有矿脉数据的星球初始化)
|
||||
@@ -859,7 +858,7 @@
|
||||
|
||||
return
|
||||
}
|
||||
gameStore.player = initializePlayer(gameStore.player.id, t('common.playerName'))
|
||||
gameStore.player = gameLogic.initializePlayer(gameStore.player.id, t('common.playerName'))
|
||||
const initialPlanet = planetLogic.createInitialPlanet(gameStore.player.id, t('planet.homePlanet'))
|
||||
gameStore.player.planets = [initialPlanet]
|
||||
gameStore.currentPlanetId = initialPlanet.id
|
||||
@@ -872,14 +871,926 @@
|
||||
const generateNPCPlanets = () => {
|
||||
const npcCount = 200
|
||||
for (let i = 0; i < npcCount; i++) {
|
||||
const position = generateRandomPosition()
|
||||
const key = generatePositionKey(position.galaxy, position.system, position.position)
|
||||
const position = gameLogic.generateRandomPosition()
|
||||
const key = gameLogic.generatePositionKey(position.galaxy, position.system, position.position)
|
||||
if (universeStore.planets[key]) continue
|
||||
const npcPlanet = planetLogic.createNPCPlanet(i, position, t('planet.planetPrefix'))
|
||||
universeStore.planets[key] = npcPlanet
|
||||
}
|
||||
}
|
||||
|
||||
const updateGame = async () => {
|
||||
const now = Date.now()
|
||||
if (gameStore.isPaused) return
|
||||
gameStore.gameTime = now
|
||||
// 检查军官过期
|
||||
gameLogic.checkOfficersExpiration(gameStore.player.officers, now)
|
||||
// 处理游戏更新(建造队列、研究队列等)
|
||||
const result = gameLogic.processGameUpdate(gameStore.player, now, gameStore.gameSpeed, handleNotification, handleUnlockNotification)
|
||||
gameStore.player.researchQueue = result.updatedResearchQueue
|
||||
// 处理舰队任务
|
||||
gameStore.player.fleetMissions.forEach(mission => {
|
||||
if (mission.status === 'outbound' && now >= mission.arrivalTime) {
|
||||
processMissionArrival(mission)
|
||||
} else if (mission.status === 'returning' && mission.returnTime && now >= mission.returnTime) {
|
||||
processMissionReturn(mission)
|
||||
}
|
||||
})
|
||||
|
||||
// 处理导弹攻击任务(使用反向循环以便安全删除)
|
||||
for (let i = gameStore.player.missileAttacks.length - 1; i >= 0; i--) {
|
||||
const missileAttack = gameStore.player.missileAttacks[i]
|
||||
if (missileAttack && missileAttack.status === 'flying' && now >= missileAttack.arrivalTime) {
|
||||
await processMissileAttackArrival(missileAttack)
|
||||
// 导弹攻击是单程的,到达后直接从数组中移除
|
||||
gameStore.player.missileAttacks.splice(i, 1)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理NPC舰队任务
|
||||
npcStore.npcs.forEach(npc => {
|
||||
if (npc.fleetMissions) {
|
||||
npc.fleetMissions.forEach(mission => {
|
||||
if (mission.status === 'outbound' && now >= mission.arrivalTime) {
|
||||
processNPCMissionArrival(npc, mission)
|
||||
} else if (mission.status === 'returning' && mission.returnTime && now >= mission.returnTime) {
|
||||
processNPCMissionReturn(npc, mission)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// NPC成长系统更新
|
||||
updateNPCGrowth(1)
|
||||
|
||||
// NPC行为系统更新(侦查和攻击决策)
|
||||
updateNPCBehavior(1)
|
||||
|
||||
// 检查成就解锁
|
||||
checkAchievementUnlocks()
|
||||
|
||||
// 检查战役任务进度
|
||||
if (gameStore.player.campaignProgress) {
|
||||
campaignLogic.checkAllActiveQuestsProgress(gameStore.player, npcStore.npcs)
|
||||
}
|
||||
|
||||
// 检查并处理被消灭的NPC(所有星球都被摧毁的NPC)
|
||||
const eliminatedNpcIds = diplomaticLogic.checkAndHandleEliminatedNPCs(npcStore.npcs, gameStore.player, gameStore.locale)
|
||||
if (eliminatedNpcIds.length > 0) {
|
||||
// 从universeStore中移除被消灭NPC的星球数据,并收集需要清理的任务ID
|
||||
const missionIdsToRemove: string[] = []
|
||||
eliminatedNpcIds.forEach(npcId => {
|
||||
const npc = npcStore.npcs.find(n => n.id === npcId)
|
||||
if (npc) {
|
||||
// 遍历NPC的所有星球,从universeStore中删除
|
||||
if (npc.planets) {
|
||||
npc.planets.forEach(planet => {
|
||||
const planetKey = gameLogic.generatePositionKey(planet.position.galaxy, planet.position.system, planet.position.position)
|
||||
if (universeStore.planets[planetKey]) {
|
||||
delete universeStore.planets[planetKey]
|
||||
}
|
||||
})
|
||||
}
|
||||
// 收集该NPC所有任务的ID(用于清理玩家的警报)
|
||||
if (npc.fleetMissions) {
|
||||
npc.fleetMissions.forEach(m => missionIdsToRemove.push(m.id))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 清理玩家的即将到来舰队警报(移除已消灭NPC的任务警报)
|
||||
if (gameStore.player.incomingFleetAlerts && missionIdsToRemove.length > 0) {
|
||||
gameStore.player.incomingFleetAlerts = gameStore.player.incomingFleetAlerts.filter(alert => !missionIdsToRemove.includes(alert.id))
|
||||
}
|
||||
|
||||
// 从NPC列表中移除被消灭的NPC
|
||||
npcStore.npcs = npcStore.npcs.filter(npc => !eliminatedNpcIds.includes(npc.id))
|
||||
}
|
||||
}
|
||||
|
||||
const processMissionArrival = async (mission: FleetMission) => {
|
||||
// 从宇宙星球地图中查找目标星球
|
||||
const targetKey = gameLogic.generatePositionKey(
|
||||
mission.targetPosition.galaxy,
|
||||
mission.targetPosition.system,
|
||||
mission.targetPosition.position
|
||||
)
|
||||
// 先从玩家星球中查找,再从宇宙地图中查找
|
||||
// 如果任务指定了targetIsMoon,需要精确匹配行星或月球
|
||||
const targetPlanet =
|
||||
gameStore.player.planets.find(p => {
|
||||
const positionMatch =
|
||||
p.position.galaxy === mission.targetPosition.galaxy &&
|
||||
p.position.system === mission.targetPosition.system &&
|
||||
p.position.position === mission.targetPosition.position
|
||||
// 如果任务明确指定目标类型,按类型匹配
|
||||
if (mission.targetIsMoon !== undefined) {
|
||||
return positionMatch && p.isMoon === mission.targetIsMoon
|
||||
}
|
||||
// 兼容旧任务:默认优先匹配行星(非月球)
|
||||
return positionMatch && !p.isMoon
|
||||
}) ||
|
||||
// 如果没有匹配到指定类型,尝试匹配同位置的任何星球
|
||||
gameStore.player.planets.find(
|
||||
p =>
|
||||
p.position.galaxy === mission.targetPosition.galaxy &&
|
||||
p.position.system === mission.targetPosition.system &&
|
||||
p.position.position === mission.targetPosition.position
|
||||
) ||
|
||||
universeStore.planets[targetKey]
|
||||
|
||||
// 获取起始星球名称(用于报告)
|
||||
const originPlanet = gameStore.player.planets.find(p => p.id === mission.originPlanetId)
|
||||
const originPlanetName = originPlanet?.name || t('fleetView.unknownPlanet')
|
||||
|
||||
if (mission.missionType === MissionType.Transport) {
|
||||
// 在处理任务之前保存货物信息(因为processTransportArrival会清空cargo)
|
||||
const transportedResources = { ...mission.cargo }
|
||||
const isGiftMission = mission.isGift && mission.giftTargetNpcId
|
||||
const result = fleetLogic.processTransportArrival(mission, targetPlanet, gameStore.player, npcStore.npcs)
|
||||
|
||||
// 更新成就统计(仅在成功时追踪)
|
||||
if (result.success) {
|
||||
const totalTransported =
|
||||
transportedResources.metal + transportedResources.crystal + transportedResources.deuterium + transportedResources.darkMatter
|
||||
if (isGiftMission) {
|
||||
// 送礼成功
|
||||
gameLogic.trackDiplomacyStats(gameStore.player, 'gift', { resourcesAmount: totalTransported })
|
||||
} else {
|
||||
// 普通运输任务成功
|
||||
gameLogic.trackMissionStats(gameStore.player, 'transport', { resourcesAmount: totalTransported })
|
||||
}
|
||||
}
|
||||
|
||||
// 生成失败原因消息
|
||||
let transportFailMessage = t('missionReports.transportFailed')
|
||||
if (!result.success && result.failReason) {
|
||||
if (result.failReason === 'targetNotFound') {
|
||||
transportFailMessage = t('missionReports.transportFailedTargetNotFound')
|
||||
} else if (result.failReason === 'giftRejected') {
|
||||
transportFailMessage = t('missionReports.transportFailedGiftRejected')
|
||||
}
|
||||
}
|
||||
|
||||
// 生成运输任务报告
|
||||
if (!gameStore.player.missionReports) {
|
||||
gameStore.player.missionReports = []
|
||||
}
|
||||
gameStore.player.missionReports.push({
|
||||
id: `mission-report-${mission.id}`,
|
||||
timestamp: Date.now(),
|
||||
missionType: MissionType.Transport,
|
||||
originPlanetId: mission.originPlanetId,
|
||||
originPlanetName,
|
||||
targetPosition: mission.targetPosition,
|
||||
targetPlanetId: targetPlanet?.id,
|
||||
targetPlanetName:
|
||||
targetPlanet?.name || `[${mission.targetPosition.galaxy}:${mission.targetPosition.system}:${mission.targetPosition.position}]`,
|
||||
success: result.success,
|
||||
message: result.success ? t('missionReports.transportSuccess') : transportFailMessage,
|
||||
details: {
|
||||
transportedResources,
|
||||
failReason: result.failReason
|
||||
},
|
||||
read: false
|
||||
})
|
||||
} else if (mission.missionType === MissionType.Attack) {
|
||||
const attackResult = await fleetLogic.processAttackArrival(mission, targetPlanet, gameStore.player, null, gameStore.player.planets)
|
||||
if (attackResult) {
|
||||
gameStore.player.battleReports.push(attackResult.battleResult)
|
||||
|
||||
// 更新成就统计 - 攻击
|
||||
const debrisValue = attackResult.debrisField
|
||||
? attackResult.debrisField.resources.metal + attackResult.debrisField.resources.crystal
|
||||
: 0
|
||||
const won = attackResult.battleResult.winner === 'attacker'
|
||||
gameLogic.trackAttackStats(gameStore.player, attackResult.battleResult, won, debrisValue)
|
||||
|
||||
// 检查是否攻击了NPC星球,更新外交关系
|
||||
if (targetPlanet) {
|
||||
const targetNpc = npcStore.npcs.find(npc => npc.planets.some(p => p.id === targetPlanet.id))
|
||||
if (targetNpc) {
|
||||
diplomaticLogic.handleAttackReputation(gameStore.player, targetNpc, attackResult.battleResult, npcStore.npcs, gameStore.locale)
|
||||
|
||||
// 同步战斗损失到NPC的实际星球数据
|
||||
const npcPlanet = targetNpc.planets.find(p => p.id === targetPlanet.id)
|
||||
if (npcPlanet) {
|
||||
// 同步舰队损失
|
||||
Object.entries(attackResult.battleResult.defenderLosses.fleet).forEach(([shipType, lost]) => {
|
||||
npcPlanet.fleet[shipType as ShipType] = Math.max(0, (npcPlanet.fleet[shipType as ShipType] || 0) - lost)
|
||||
})
|
||||
// 同步防御损失(修复后的数据已在targetPlanet中)
|
||||
npcPlanet.defense = { ...targetPlanet.defense }
|
||||
// 同步资源(被掠夺后的)
|
||||
npcPlanet.resources = { ...targetPlanet.resources }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (attackResult.moon) {
|
||||
gameStore.player.planets.push(attackResult.moon)
|
||||
}
|
||||
if (attackResult.debrisField) {
|
||||
// 将残骸场添加到游戏状态
|
||||
universeStore.debrisFields[attackResult.debrisField.id] = attackResult.debrisField
|
||||
}
|
||||
}
|
||||
} else if (mission.missionType === MissionType.Colonize) {
|
||||
const colonizeResult = fleetLogic.processColonizeArrival(mission, targetPlanet, gameStore.player, t('planet.colonyPrefix'))
|
||||
const newPlanet = colonizeResult.planet
|
||||
|
||||
// 更新成就统计 - 殖民
|
||||
if (colonizeResult.success && newPlanet) {
|
||||
gameLogic.trackMissionStats(gameStore.player, 'colonize')
|
||||
}
|
||||
|
||||
// 生成失败原因消息
|
||||
let failMessage = t('missionReports.colonizeFailed')
|
||||
if (!colonizeResult.success && colonizeResult.failReason) {
|
||||
if (colonizeResult.failReason === 'positionOccupied') {
|
||||
failMessage = t('missionReports.colonizeFailedOccupied')
|
||||
} else if (colonizeResult.failReason === 'maxColoniesReached') {
|
||||
failMessage = t('missionReports.colonizeFailedMaxColonies')
|
||||
}
|
||||
}
|
||||
|
||||
// 生成殖民任务报告
|
||||
if (!gameStore.player.missionReports) {
|
||||
gameStore.player.missionReports = []
|
||||
}
|
||||
gameStore.player.missionReports.push({
|
||||
id: `mission-report-${mission.id}`,
|
||||
timestamp: Date.now(),
|
||||
missionType: MissionType.Colonize,
|
||||
originPlanetId: mission.originPlanetId,
|
||||
originPlanetName,
|
||||
targetPosition: mission.targetPosition,
|
||||
targetPlanetId: newPlanet?.id,
|
||||
targetPlanetName: newPlanet?.name,
|
||||
success: colonizeResult.success,
|
||||
message: colonizeResult.success ? t('missionReports.colonizeSuccess') : failMessage,
|
||||
details: newPlanet
|
||||
? {
|
||||
newPlanetId: newPlanet.id,
|
||||
newPlanetName: newPlanet.name
|
||||
}
|
||||
: { failReason: colonizeResult.failReason },
|
||||
read: false
|
||||
})
|
||||
if (newPlanet) {
|
||||
gameStore.player.planets.push(newPlanet)
|
||||
}
|
||||
} else if (mission.missionType === MissionType.Spy) {
|
||||
const spyResult = fleetLogic.processSpyArrival(mission, targetPlanet, gameStore.player, null, npcStore.npcs)
|
||||
if (spyResult.success && spyResult.report) {
|
||||
gameStore.player.spyReports.push(spyResult.report)
|
||||
// 更新成就统计 - 侦查
|
||||
gameLogic.trackMissionStats(gameStore.player, 'spy')
|
||||
}
|
||||
|
||||
// 生成侦查任务报告(即使失败也生成)
|
||||
if (!gameStore.player.missionReports) {
|
||||
gameStore.player.missionReports = []
|
||||
}
|
||||
|
||||
let spyFailMessage = t('missionReports.spyFailed')
|
||||
if (!spyResult.success && spyResult.failReason) {
|
||||
if (spyResult.failReason === 'targetNotFound') {
|
||||
spyFailMessage = t('missionReports.spyFailedTargetNotFound')
|
||||
}
|
||||
}
|
||||
|
||||
gameStore.player.missionReports.push({
|
||||
id: `mission-report-${mission.id}`,
|
||||
timestamp: Date.now(),
|
||||
missionType: MissionType.Spy,
|
||||
originPlanetId: mission.originPlanetId,
|
||||
originPlanetName,
|
||||
targetPosition: mission.targetPosition,
|
||||
targetPlanetId: targetPlanet?.id,
|
||||
targetPlanetName:
|
||||
targetPlanet?.name || `[${mission.targetPosition.galaxy}:${mission.targetPosition.system}:${mission.targetPosition.position}]`,
|
||||
success: spyResult.success,
|
||||
message: spyResult.success ? t('missionReports.spySuccess') : spyFailMessage,
|
||||
details: spyResult.success ? { spyReportId: spyResult.report?.id } : { failReason: spyResult.failReason },
|
||||
read: false
|
||||
})
|
||||
} else if (mission.missionType === MissionType.Deploy) {
|
||||
const deployed = fleetLogic.processDeployArrival(mission, targetPlanet, gameStore.player.id, gameStore.player.technologies)
|
||||
|
||||
// 更新成就统计 - 部署
|
||||
if (deployed.success) {
|
||||
gameLogic.trackMissionStats(gameStore.player, 'deploy')
|
||||
}
|
||||
|
||||
// 生成失败原因消息
|
||||
let deployFailMessage = t('missionReports.deployFailed')
|
||||
if (!deployed.success && deployed.failReason) {
|
||||
if (deployed.failReason === 'targetNotFound') {
|
||||
deployFailMessage = t('missionReports.deployFailedTargetNotFound')
|
||||
} else if (deployed.failReason === 'notOwnPlanet') {
|
||||
deployFailMessage = t('missionReports.deployFailedNotOwnPlanet')
|
||||
}
|
||||
}
|
||||
|
||||
// 生成部署任务报告
|
||||
if (!gameStore.player.missionReports) {
|
||||
gameStore.player.missionReports = []
|
||||
}
|
||||
gameStore.player.missionReports.push({
|
||||
id: `mission-report-${mission.id}`,
|
||||
timestamp: Date.now(),
|
||||
missionType: MissionType.Deploy,
|
||||
originPlanetId: mission.originPlanetId,
|
||||
originPlanetName,
|
||||
targetPosition: mission.targetPosition,
|
||||
targetPlanetId: targetPlanet?.id,
|
||||
targetPlanetName:
|
||||
targetPlanet?.name || `[${mission.targetPosition.galaxy}:${mission.targetPosition.system}:${mission.targetPosition.position}]`,
|
||||
success: deployed.success,
|
||||
message: deployed.success ? t('missionReports.deploySuccess') : deployFailMessage,
|
||||
details: {
|
||||
deployedFleet: mission.fleet,
|
||||
failReason: deployed.failReason
|
||||
},
|
||||
read: false
|
||||
})
|
||||
if (deployed.success && !deployed.overflow) {
|
||||
const missionIndex = gameStore.player.fleetMissions.indexOf(mission)
|
||||
if (missionIndex > -1) gameStore.player.fleetMissions.splice(missionIndex, 1)
|
||||
return
|
||||
}
|
||||
} else if (mission.missionType === MissionType.Recycle) {
|
||||
// 处理回收任务
|
||||
const debrisId = `debris_${mission.targetPosition.galaxy}_${mission.targetPosition.system}_${mission.targetPosition.position}`
|
||||
const debrisField = universeStore.debrisFields[debrisId]
|
||||
const recycleResult = fleetLogic.processRecycleArrival(mission, debrisField)
|
||||
|
||||
// 更新成就统计 - 回收(无论是否有残骸都算飞行任务,但只有成功回收才计入回收资源量)
|
||||
const totalRecycled =
|
||||
recycleResult.success && recycleResult.collectedResources
|
||||
? recycleResult.collectedResources.metal + recycleResult.collectedResources.crystal
|
||||
: 0
|
||||
gameLogic.trackMissionStats(gameStore.player, 'recycle', { resourcesAmount: totalRecycled })
|
||||
|
||||
// 生成失败原因消息
|
||||
let recycleFailMessage = t('missionReports.recycleFailed')
|
||||
if (!recycleResult.success && recycleResult.failReason) {
|
||||
if (recycleResult.failReason === 'noDebrisField') {
|
||||
recycleFailMessage = t('missionReports.recycleFailedNoDebris')
|
||||
} else if (recycleResult.failReason === 'debrisEmpty') {
|
||||
recycleFailMessage = t('missionReports.recycleFailedDebrisEmpty')
|
||||
}
|
||||
}
|
||||
|
||||
// 生成回收任务报告
|
||||
if (!gameStore.player.missionReports) {
|
||||
gameStore.player.missionReports = []
|
||||
}
|
||||
gameStore.player.missionReports.push({
|
||||
id: `mission-report-${mission.id}`,
|
||||
timestamp: Date.now(),
|
||||
missionType: MissionType.Recycle,
|
||||
originPlanetId: mission.originPlanetId,
|
||||
originPlanetName,
|
||||
targetPosition: mission.targetPosition,
|
||||
success: recycleResult.success,
|
||||
message: recycleResult.success ? t('missionReports.recycleSuccess') : recycleFailMessage,
|
||||
details: recycleResult.success
|
||||
? {
|
||||
recycledResources: recycleResult.collectedResources,
|
||||
remainingDebris: recycleResult.remainingDebris || undefined
|
||||
}
|
||||
: { failReason: recycleResult.failReason },
|
||||
read: false
|
||||
})
|
||||
|
||||
if (recycleResult.success && recycleResult.collectedResources && debrisField) {
|
||||
if (recycleResult.remainingDebris && (recycleResult.remainingDebris.metal > 0 || recycleResult.remainingDebris.crystal > 0)) {
|
||||
// 更新残骸场
|
||||
universeStore.debrisFields[debrisId] = {
|
||||
id: debrisField.id,
|
||||
position: debrisField.position,
|
||||
resources: recycleResult.remainingDebris,
|
||||
createdAt: debrisField.createdAt,
|
||||
expiresAt: debrisField.expiresAt
|
||||
}
|
||||
} else {
|
||||
// 残骸场已被完全收集,删除
|
||||
delete universeStore.debrisFields[debrisId]
|
||||
}
|
||||
}
|
||||
} else if (mission.missionType === MissionType.Destroy) {
|
||||
// 处理行星毁灭任务(需要先战斗,再计算毁灭概率)
|
||||
const destroyResult = await fleetLogic.processDestroyArrival(mission, targetPlanet, gameStore.player, null, gameStore.player.planets)
|
||||
|
||||
// 处理战斗报告(如果发生了战斗)
|
||||
if (destroyResult.battleResult) {
|
||||
gameStore.player.battleReports.push(destroyResult.battleResult)
|
||||
|
||||
// 处理战斗对NPC的影响
|
||||
if (targetPlanet) {
|
||||
const targetNpc = npcStore.npcs.find(npc => npc.planets.some(p => p.id === targetPlanet.id))
|
||||
if (targetNpc) {
|
||||
diplomaticLogic.handleAttackReputation(gameStore.player, targetNpc, destroyResult.battleResult, npcStore.npcs, gameStore.locale)
|
||||
|
||||
// 同步战斗损失到NPC的实际星球数据
|
||||
const npcPlanet = targetNpc.planets.find(p => p.id === targetPlanet.id)
|
||||
if (npcPlanet) {
|
||||
Object.entries(destroyResult.battleResult.defenderLosses.fleet).forEach(([shipType, lost]) => {
|
||||
npcPlanet.fleet[shipType as ShipType] = Math.max(0, (npcPlanet.fleet[shipType as ShipType] || 0) - lost)
|
||||
})
|
||||
npcPlanet.defense = { ...targetPlanet.defense }
|
||||
npcPlanet.resources = { ...targetPlanet.resources }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理新生成的月球
|
||||
if (destroyResult.moon) {
|
||||
gameStore.player.planets.push(destroyResult.moon)
|
||||
}
|
||||
|
||||
// 处理残骸场
|
||||
if (destroyResult.debrisField) {
|
||||
universeStore.debrisFields[destroyResult.debrisField.id] = destroyResult.debrisField
|
||||
}
|
||||
|
||||
// 更新成就统计 - 行星毁灭
|
||||
if (destroyResult.success) {
|
||||
gameLogic.trackMissionStats(gameStore.player, 'destroy')
|
||||
}
|
||||
|
||||
// 生成失败原因消息
|
||||
let destroyFailMessage = t('missionReports.destroyFailed')
|
||||
if (!destroyResult.success && destroyResult.failReason) {
|
||||
if (destroyResult.failReason === 'targetNotFound') {
|
||||
destroyFailMessage = t('missionReports.destroyFailedTargetNotFound')
|
||||
} else if (destroyResult.failReason === 'ownPlanet') {
|
||||
destroyFailMessage = t('missionReports.destroyFailedOwnPlanet')
|
||||
} else if (destroyResult.failReason === 'noDeathstar') {
|
||||
destroyFailMessage = t('missionReports.destroyFailedNoDeathstar')
|
||||
} else if (destroyResult.failReason === 'chanceFailed') {
|
||||
destroyFailMessage = t('missionReports.destroyFailedChance', { chance: destroyResult.destructionChance.toFixed(1) })
|
||||
}
|
||||
}
|
||||
|
||||
// 生成毁灭任务报告
|
||||
if (!gameStore.player.missionReports) {
|
||||
gameStore.player.missionReports = []
|
||||
}
|
||||
gameStore.player.missionReports.push({
|
||||
id: `mission-report-${mission.id}`,
|
||||
timestamp: Date.now(),
|
||||
missionType: MissionType.Destroy,
|
||||
originPlanetId: mission.originPlanetId,
|
||||
originPlanetName,
|
||||
targetPosition: mission.targetPosition,
|
||||
targetPlanetId: targetPlanet?.id,
|
||||
targetPlanetName: targetPlanet?.name,
|
||||
success: destroyResult.success,
|
||||
message: destroyResult.success ? t('missionReports.destroySuccess') : destroyFailMessage,
|
||||
details: destroyResult.success
|
||||
? {
|
||||
destroyedPlanetName:
|
||||
targetPlanet?.name ||
|
||||
`[${mission.targetPosition.galaxy}:${mission.targetPosition.system}:${mission.targetPosition.position}]`,
|
||||
hadBattle: !!destroyResult.battleResult
|
||||
}
|
||||
: {
|
||||
failReason: destroyResult.failReason,
|
||||
destructionChance: destroyResult.destructionChance,
|
||||
deathstarsLost: destroyResult.deathstarsLost,
|
||||
hadBattle: !!destroyResult.battleResult
|
||||
},
|
||||
read: false
|
||||
})
|
||||
|
||||
if (destroyResult.success && destroyResult.planetId) {
|
||||
// 星球被摧毁
|
||||
|
||||
// 处理外交关系(如果目标是NPC星球)
|
||||
if (targetPlanet && targetPlanet.ownerId) {
|
||||
const planetOwner = npcStore.npcs.find(npc => npc.id === targetPlanet.ownerId)
|
||||
if (planetOwner) {
|
||||
diplomaticLogic.handlePlanetDestructionReputation(gameStore.player, targetPlanet, planetOwner, npcStore.npcs, gameStore.locale)
|
||||
|
||||
// 从NPC的星球列表中移除被摧毁的星球
|
||||
const npcPlanetIndex = planetOwner.planets.findIndex(p => p.id === destroyResult.planetId)
|
||||
if (npcPlanetIndex > -1) {
|
||||
planetOwner.planets.splice(npcPlanetIndex, 1)
|
||||
}
|
||||
|
||||
// 检查并处理被消灭的NPC(所有星球都被摧毁的NPC)
|
||||
const eliminatedNpcIds = diplomaticLogic.checkAndHandleEliminatedNPCs(npcStore.npcs, gameStore.player, gameStore.locale)
|
||||
|
||||
// 从npcStore中移除被消灭的NPC
|
||||
if (eliminatedNpcIds.length > 0) {
|
||||
npcStore.npcs = npcStore.npcs.filter(npc => !eliminatedNpcIds.includes(npc.id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 从玩家星球列表中移除(如果是玩家的星球)
|
||||
const planetIndex = gameStore.player.planets.findIndex(p => p.id === destroyResult.planetId)
|
||||
if (planetIndex > -1) {
|
||||
gameStore.player.planets.splice(planetIndex, 1)
|
||||
} else {
|
||||
// 不是玩家星球,从宇宙地图中移除
|
||||
delete universeStore.planets[targetKey]
|
||||
}
|
||||
|
||||
// 取消所有前往该位置的NPC任务(回收、攻击、侦查等)
|
||||
const destroyedDebrisId = `debris_${mission.targetPosition.galaxy}_${mission.targetPosition.system}_${mission.targetPosition.position}`
|
||||
npcStore.npcs.forEach(npc => {
|
||||
if (npc.fleetMissions) {
|
||||
// 找到需要取消的任务(前往已摧毁星球位置的outbound任务)
|
||||
const missionsToCancel = npc.fleetMissions.filter(m => {
|
||||
if (m.status !== 'outbound') return false
|
||||
// 检查回收任务的残骸场ID
|
||||
if (m.missionType === MissionType.Recycle && m.debrisFieldId === destroyedDebrisId) {
|
||||
return true
|
||||
}
|
||||
// 检查其他任务的目标星球ID
|
||||
if (m.targetPlanetId === destroyResult.planetId) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
// 将这些任务的舰队返回给NPC
|
||||
missionsToCancel.forEach(m => {
|
||||
const npcOriginPlanet = npc.planets.find(p => p.id === m.originPlanetId)
|
||||
if (npcOriginPlanet) {
|
||||
shipLogic.addFleet(npcOriginPlanet.fleet, m.fleet)
|
||||
}
|
||||
})
|
||||
|
||||
// 从任务列表中移除这些任务
|
||||
npc.fleetMissions = npc.fleetMissions.filter(m => !missionsToCancel.includes(m))
|
||||
}
|
||||
|
||||
// 清理关于被摧毁星球的侦查报告
|
||||
if (npc.playerSpyReports && destroyResult.planetId && destroyResult.planetId in npc.playerSpyReports) {
|
||||
delete npc.playerSpyReports[destroyResult.planetId]
|
||||
}
|
||||
})
|
||||
|
||||
// 同时删除该位置的残骸场(星球被摧毁后残骸场也消失)
|
||||
delete universeStore.debrisFields[destroyedDebrisId]
|
||||
}
|
||||
} else if (mission.missionType === MissionType.Expedition) {
|
||||
// 处理探险任务
|
||||
const expeditionResult = fleetLogic.processExpeditionArrival(mission)
|
||||
|
||||
// 确保返回时间正确设置(兼容旧版本任务数据)
|
||||
// 如果 returnTime 不存在或已过期,重新计算
|
||||
const now = Date.now()
|
||||
if (!mission.returnTime || mission.returnTime <= now) {
|
||||
// 返回时间应该等于当前时间加上单程飞行时间
|
||||
const flightDuration = mission.arrivalTime - mission.departureTime
|
||||
mission.returnTime = now + flightDuration
|
||||
}
|
||||
|
||||
// 更新成就统计 - 探险
|
||||
const isSuccessful =
|
||||
expeditionResult.eventType === 'resources' || expeditionResult.eventType === 'darkMatter' || expeditionResult.eventType === 'fleet'
|
||||
gameLogic.trackMissionStats(gameStore.player, 'expedition', { successful: isSuccessful })
|
||||
|
||||
// 生成探险任务报告
|
||||
if (!gameStore.player.missionReports) {
|
||||
gameStore.player.missionReports = []
|
||||
}
|
||||
|
||||
// 根据事件类型生成不同的报告消息
|
||||
let reportMessage = ''
|
||||
let reportDetails: Record<string, unknown> = {
|
||||
// 保存探险区域信息
|
||||
expeditionZone: mission.expeditionZone
|
||||
}
|
||||
|
||||
switch (expeditionResult.eventType) {
|
||||
case 'resources':
|
||||
reportMessage = t('missionReports.expeditionResources')
|
||||
reportDetails.foundResources = expeditionResult.resources
|
||||
break
|
||||
case 'darkMatter':
|
||||
reportMessage = t('missionReports.expeditionDarkMatter')
|
||||
reportDetails.foundResources = expeditionResult.resources
|
||||
break
|
||||
case 'fleet':
|
||||
reportMessage = t('missionReports.expeditionFleet')
|
||||
reportDetails.foundFleet = expeditionResult.fleet
|
||||
break
|
||||
case 'pirates':
|
||||
reportMessage = expeditionResult.fleetLost
|
||||
? t('missionReports.expeditionPiratesAttack')
|
||||
: t('missionReports.expeditionPiratesEscaped')
|
||||
if (expeditionResult.fleetLost) reportDetails.fleetLost = expeditionResult.fleetLost
|
||||
break
|
||||
case 'aliens':
|
||||
reportMessage = expeditionResult.fleetLost
|
||||
? t('missionReports.expeditionAliensAttack')
|
||||
: t('missionReports.expeditionAliensEscaped')
|
||||
if (expeditionResult.fleetLost) reportDetails.fleetLost = expeditionResult.fleetLost
|
||||
break
|
||||
default:
|
||||
reportMessage = t('missionReports.expeditionNothing')
|
||||
}
|
||||
|
||||
gameStore.player.missionReports.push({
|
||||
id: `mission-report-${mission.id}`,
|
||||
timestamp: Date.now(),
|
||||
missionType: MissionType.Expedition,
|
||||
originPlanetId: mission.originPlanetId,
|
||||
originPlanetName,
|
||||
targetPosition: mission.targetPosition,
|
||||
success: expeditionResult.eventType !== 'nothing',
|
||||
message: reportMessage,
|
||||
details: reportDetails,
|
||||
read: false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const processMissionReturn = (mission: FleetMission) => {
|
||||
const originPlanet = gameStore.player.planets.find(p => p.id === mission.originPlanetId)
|
||||
if (!originPlanet) return
|
||||
shipLogic.addFleet(originPlanet.fleet, mission.fleet)
|
||||
resourceLogic.addResources(originPlanet.resources, mission.cargo)
|
||||
const missionIndex = gameStore.player.fleetMissions.indexOf(mission)
|
||||
if (missionIndex > -1) gameStore.player.fleetMissions.splice(missionIndex, 1)
|
||||
}
|
||||
|
||||
// NPC任务处理
|
||||
const processNPCMissionArrival = (npc: NPC, mission: FleetMission) => {
|
||||
if (mission.missionType === MissionType.Recycle) {
|
||||
// NPC回收任务到达
|
||||
const debrisId = mission.debrisFieldId
|
||||
if (!debrisId) {
|
||||
console.warn('[NPC Mission] Recycle mission missing debrisFieldId')
|
||||
mission.status = 'returning'
|
||||
mission.returnTime = Date.now() + (mission.arrivalTime - mission.departureTime)
|
||||
return
|
||||
}
|
||||
|
||||
const debrisField = universeStore.debrisFields[debrisId]
|
||||
const recycleResult = fleetLogic.processRecycleArrival(mission, debrisField)
|
||||
|
||||
if (recycleResult && debrisField && recycleResult.collectedResources) {
|
||||
// 更新成就统计 - 被NPC回收残骸(如果残骸是玩家战斗产生的)
|
||||
const totalRecycled = recycleResult.collectedResources.metal + recycleResult.collectedResources.crystal
|
||||
if (totalRecycled > 0) {
|
||||
gameLogic.trackDiplomacyStats(gameStore.player, 'debrisRecycledByNPC', { resourcesAmount: totalRecycled })
|
||||
}
|
||||
|
||||
if (recycleResult.remainingDebris && (recycleResult.remainingDebris.metal > 0 || recycleResult.remainingDebris.crystal > 0)) {
|
||||
// 更新残骸场
|
||||
universeStore.debrisFields[debrisId] = {
|
||||
id: debrisField.id,
|
||||
position: debrisField.position,
|
||||
resources: recycleResult.remainingDebris,
|
||||
createdAt: debrisField.createdAt
|
||||
}
|
||||
} else {
|
||||
// 残骸已被完全回收,从宇宙中删除
|
||||
delete universeStore.debrisFields[debrisId]
|
||||
}
|
||||
}
|
||||
|
||||
// 移除即将到来的警告(回收任务已到达)
|
||||
removeIncomingFleetAlertById(mission.id)
|
||||
|
||||
// 设置返回时间
|
||||
mission.returnTime = Date.now() + (mission.arrivalTime - mission.departureTime)
|
||||
return
|
||||
}
|
||||
|
||||
// 找到目标星球
|
||||
const targetKey = gameLogic.generatePositionKey(
|
||||
mission.targetPosition.galaxy,
|
||||
mission.targetPosition.system,
|
||||
mission.targetPosition.position
|
||||
)
|
||||
const targetPlanet =
|
||||
gameStore.player.planets.find(
|
||||
p =>
|
||||
p.position.galaxy === mission.targetPosition.galaxy &&
|
||||
p.position.system === mission.targetPosition.system &&
|
||||
p.position.position === mission.targetPosition.position
|
||||
) || universeStore.planets[targetKey]
|
||||
|
||||
if (!targetPlanet) {
|
||||
console.warn('[NPC Mission] Target planet not found')
|
||||
return
|
||||
}
|
||||
|
||||
if (mission.missionType === MissionType.Spy) {
|
||||
// NPC侦查到达
|
||||
const { spiedNotification, spyReport } = npcBehaviorLogic.processNPCSpyArrival(npc, mission, targetPlanet, gameStore.player)
|
||||
|
||||
// 更新成就统计 - 被NPC侦查
|
||||
gameLogic.trackDiplomacyStats(gameStore.player, 'spiedByNPC')
|
||||
|
||||
// 保存侦查报告到NPC(用于后续攻击决策)
|
||||
if (!npc.playerSpyReports) {
|
||||
npc.playerSpyReports = {}
|
||||
}
|
||||
npc.playerSpyReports[targetPlanet.id] = spyReport
|
||||
|
||||
// 添加被侦查通知给玩家
|
||||
if (!gameStore.player.spiedNotifications) {
|
||||
gameStore.player.spiedNotifications = []
|
||||
}
|
||||
gameStore.player.spiedNotifications.push(spiedNotification)
|
||||
|
||||
// 移除即将到来的警告(侦查已到达)
|
||||
removeIncomingFleetAlertById(mission.id)
|
||||
} else if (mission.missionType === MissionType.Attack) {
|
||||
// NPC攻击到达 - 使用专门的NPC攻击处理逻辑
|
||||
fleetLogic.processNPCAttackArrival(npc, mission, targetPlanet, gameStore.player, gameStore.player.planets).then(attackResult => {
|
||||
if (attackResult) {
|
||||
// 更新成就统计 - 被NPC攻击 + 防御统计
|
||||
gameLogic.trackDiplomacyStats(gameStore.player, 'attackedByNPC')
|
||||
const debrisValue = attackResult.debrisField
|
||||
? attackResult.debrisField.resources.metal + attackResult.debrisField.resources.crystal
|
||||
: 0
|
||||
const won = attackResult.battleResult.winner === 'defender'
|
||||
gameLogic.trackDefenseStats(gameStore.player, attackResult.battleResult, won, debrisValue)
|
||||
|
||||
// 添加战斗报告给玩家
|
||||
gameStore.player.battleReports.push(attackResult.battleResult)
|
||||
|
||||
// 如果生成月球,添加到玩家星球列表
|
||||
if (attackResult.moon) {
|
||||
gameStore.player.planets.push(attackResult.moon)
|
||||
}
|
||||
|
||||
// 如果生成残骸场,添加到宇宙残骸场列表
|
||||
if (attackResult.debrisField) {
|
||||
const existingDebris = universeStore.debrisFields[attackResult.debrisField.id]
|
||||
if (existingDebris) {
|
||||
// 累加残骸资源
|
||||
universeStore.debrisFields[attackResult.debrisField.id] = {
|
||||
...existingDebris,
|
||||
resources: {
|
||||
metal: existingDebris.resources.metal + attackResult.debrisField.resources.metal,
|
||||
crystal: existingDebris.resources.crystal + attackResult.debrisField.resources.crystal
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 新残骸场
|
||||
universeStore.debrisFields[attackResult.debrisField.id] = attackResult.debrisField
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 移除即将到来的警告(攻击已到达)
|
||||
removeIncomingFleetAlertById(mission.id)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const processNPCMissionReturn = (npc: NPC, mission: FleetMission) => {
|
||||
// 找到NPC的起始星球
|
||||
const originPlanet = npc.planets.find(p => p.id === mission.originPlanetId)
|
||||
if (!originPlanet) return
|
||||
|
||||
// 返还舰队
|
||||
shipLogic.addFleet(originPlanet.fleet, mission.fleet)
|
||||
|
||||
// 如果携带掠夺资源,给NPC添加资源
|
||||
if (mission.cargo) {
|
||||
originPlanet.resources.metal += mission.cargo.metal
|
||||
originPlanet.resources.crystal += mission.cargo.crystal
|
||||
originPlanet.resources.deuterium += mission.cargo.deuterium
|
||||
}
|
||||
|
||||
// 从NPC任务列表中移除
|
||||
if (npc.fleetMissions) {
|
||||
const missionIndex = npc.fleetMissions.indexOf(mission)
|
||||
if (missionIndex > -1) {
|
||||
npc.fleetMissions.splice(missionIndex, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理导弹攻击到达
|
||||
const processMissileAttackArrival = async (missileAttack: MissileAttack) => {
|
||||
// 动态导入导弹逻辑
|
||||
const missileLogic = await import('@/logic/missileLogic')
|
||||
|
||||
// 找到目标星球
|
||||
const targetKey = gameLogic.generatePositionKey(
|
||||
missileAttack.targetPosition.galaxy,
|
||||
missileAttack.targetPosition.system,
|
||||
missileAttack.targetPosition.position
|
||||
)
|
||||
const targetPlanet =
|
||||
gameStore.player.planets.find(
|
||||
p =>
|
||||
p.position.galaxy === missileAttack.targetPosition.galaxy &&
|
||||
p.position.system === missileAttack.targetPosition.system &&
|
||||
p.position.position === missileAttack.targetPosition.position
|
||||
) || universeStore.planets[targetKey]
|
||||
|
||||
// 如果目标星球不存在,导弹失败
|
||||
if (!targetPlanet) {
|
||||
missileAttack.status = 'arrived'
|
||||
// 生成失败报告
|
||||
if (!gameStore.player.missionReports) {
|
||||
gameStore.player.missionReports = []
|
||||
}
|
||||
gameStore.player.missionReports.push({
|
||||
id: `missile-report-${missileAttack.id}`,
|
||||
timestamp: Date.now(),
|
||||
missionType: MissionType.MissileAttack,
|
||||
originPlanetId: missileAttack.originPlanetId,
|
||||
originPlanetName: gameStore.player.planets.find(p => p.id === missileAttack.originPlanetId)?.name || t('fleetView.unknownPlanet'),
|
||||
targetPosition: missileAttack.targetPosition,
|
||||
targetPlanetId: undefined,
|
||||
targetPlanetName: `[${missileAttack.targetPosition.galaxy}:${missileAttack.targetPosition.system}:${missileAttack.targetPosition.position}]`,
|
||||
success: false,
|
||||
message: t('missionReports.missileAttackFailed'),
|
||||
details: {
|
||||
missileCount: missileAttack.missileCount,
|
||||
missileHits: 0,
|
||||
missileIntercepted: 0,
|
||||
defenseLosses: {}
|
||||
},
|
||||
read: false
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 计算导弹攻击结果
|
||||
const impactResult = missileLogic.calculateMissileImpact(missileAttack.missileCount, targetPlanet)
|
||||
|
||||
// 应用损失到目标星球
|
||||
missileLogic.applyMissileAttackResult(targetPlanet, impactResult.defenseLosses)
|
||||
|
||||
// 如果目标是NPC的星球,同步损失到NPC实际数据并扣除外交好感度
|
||||
if (targetPlanet.ownerId && targetPlanet.ownerId !== gameStore.player.id) {
|
||||
const targetNpc = npcStore.npcs.find(npc => npc.id === targetPlanet.ownerId)
|
||||
if (targetNpc) {
|
||||
// 同步防御损失到NPC的实际星球数据
|
||||
const npcPlanet = targetNpc.planets.find(p => p.id === targetPlanet.id)
|
||||
if (npcPlanet) {
|
||||
missileLogic.applyMissileAttackResult(npcPlanet, impactResult.defenseLosses)
|
||||
}
|
||||
|
||||
// 导弹攻击扣除好感度
|
||||
const { REPUTATION_CHANGES } = DIPLOMATIC_CONFIG
|
||||
const reputationLoss = REPUTATION_CHANGES.ATTACK / 2 // 导弹攻击的好感度惩罚是普通攻击的一半
|
||||
|
||||
// 更新NPC对玩家的关系(统一使用 npc.relations 作为唯一数据源)
|
||||
if (!targetNpc.relations) {
|
||||
targetNpc.relations = {}
|
||||
}
|
||||
const npcRelation = diplomaticLogic.getOrCreateRelation(targetNpc.relations, targetNpc.id, gameStore.player.id)
|
||||
targetNpc.relations[gameStore.player.id] = diplomaticLogic.updateReputation(
|
||||
npcRelation,
|
||||
reputationLoss,
|
||||
DiplomaticEventType.Attack,
|
||||
t('diplomacy.reports.wasAttackedByMissile')
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 标记导弹攻击为已到达
|
||||
missileAttack.status = 'arrived'
|
||||
|
||||
// 生成导弹攻击报告
|
||||
if (!gameStore.player.missionReports) {
|
||||
gameStore.player.missionReports = []
|
||||
}
|
||||
const reportMessage =
|
||||
impactResult.missileHits > 0
|
||||
? `${t('missionReports.missileAttackSuccess')}: ${impactResult.missileHits} ${t('missionReports.hits')}`
|
||||
: t('missionReports.missileAttackIntercepted')
|
||||
|
||||
gameStore.player.missionReports.push({
|
||||
id: `missile-report-${missileAttack.id}`,
|
||||
timestamp: Date.now(),
|
||||
missionType: MissionType.MissileAttack,
|
||||
originPlanetId: missileAttack.originPlanetId,
|
||||
originPlanetName: gameStore.player.planets.find(p => p.id === missileAttack.originPlanetId)?.name || t('fleetView.unknownPlanet'),
|
||||
targetPosition: missileAttack.targetPosition,
|
||||
targetPlanetId: targetPlanet.id,
|
||||
targetPlanetName: targetPlanet.name,
|
||||
success: true,
|
||||
message: reportMessage,
|
||||
details: {
|
||||
missileCount: missileAttack.missileCount,
|
||||
missileHits: impactResult.missileHits,
|
||||
missileIntercepted: impactResult.missileIntercepted,
|
||||
defenseLosses: impactResult.defenseLosses
|
||||
},
|
||||
read: false
|
||||
})
|
||||
}
|
||||
|
||||
// 打开敌方警报面板
|
||||
const openEnemyAlertPanel = () => {
|
||||
enemyAlertNotificationsRef.value?.open()
|
||||
@@ -893,116 +1804,391 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 创建任务引擎(处理舰队任务和导弹攻击)
|
||||
missionEngine = createMissionEngine({
|
||||
removeIncomingFleetAlert: removeIncomingFleetAlertById
|
||||
})
|
||||
/**
|
||||
* 同步NPC星球数据到universeStore
|
||||
* 解决npcStore和universeStore数据不同步的问题
|
||||
*/
|
||||
const syncNPCPlanetToUniverse = (npc: any) => {
|
||||
npc.planets.forEach((npcPlanet: any) => {
|
||||
const planetKey = gameLogic.generatePositionKey(npcPlanet.position.galaxy, npcPlanet.position.system, npcPlanet.position.position)
|
||||
const universePlanet = universeStore.planets[planetKey]
|
||||
if (universePlanet) {
|
||||
// 同步所有关键数据
|
||||
universePlanet.resources = { ...npcPlanet.resources }
|
||||
universePlanet.buildings = { ...npcPlanet.buildings }
|
||||
universePlanet.fleet = { ...npcPlanet.fleet }
|
||||
universePlanet.defense = { ...npcPlanet.defense }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 创建NPC引擎(处理NPC成长和行为,支持分片更新)
|
||||
npcEngine = createNpcEngine({
|
||||
sliceSize: 20, // 每 tick 最多更新 20 个 NPC
|
||||
growthInterval: 5, // 成长更新间隔 5 秒
|
||||
behaviorInterval: 5 // 行为更新间隔 5 秒
|
||||
})
|
||||
const updateNPCGrowth = (deltaSeconds: number) => {
|
||||
// 累积时间
|
||||
npcUpdateCounter.value += deltaSeconds
|
||||
|
||||
// 创建经济引擎(处理资源生产、建造/研究队列)
|
||||
economyEngine = createEconomyEngine({
|
||||
onNotification: handleNotification,
|
||||
onUnlock: handleUnlockNotification
|
||||
})
|
||||
// 只在达到更新间隔时才执行
|
||||
if (npcUpdateCounter.value < NPC_UPDATE_INTERVAL) {
|
||||
return
|
||||
}
|
||||
|
||||
// 创建进度引擎(处理成就检查、战役进度、外交清理等低频任务)
|
||||
progressionEngine = createProgressionEngine({
|
||||
achievementInterval: 5000, // 每5秒检查成就
|
||||
campaignInterval: 5000, // 每5秒检查战役进度
|
||||
diplomacyCleanupInterval: 15000, // 每15秒清理外交数据
|
||||
onAchievementUnlock: unlock => {
|
||||
// 获取所有星球
|
||||
const allPlanets = Object.values(universeStore.planets)
|
||||
|
||||
// 如果NPC store为空,从星球数据中初始化NPC
|
||||
if (npcStore.npcs.length === 0) {
|
||||
const npcMap = new Map<string, any>()
|
||||
|
||||
allPlanets.forEach(planet => {
|
||||
// 跳过玩家的星球
|
||||
if (planet.ownerId === gameStore.player.id || !planet.ownerId) return
|
||||
|
||||
// 这是NPC的星球
|
||||
if (!npcMap.has(planet.ownerId)) {
|
||||
// 为每个NPC设置随机的初始冷却时间,避免所有NPC同时行动
|
||||
const now = Date.now()
|
||||
const randomSpyOffset = Math.random() * 240 * 1000 // 0-4分钟的随机延迟
|
||||
const randomAttackOffset = Math.random() * 480 * 1000 // 0-8分钟的随机延迟
|
||||
|
||||
// 初始化NPC与玩家的中立关系
|
||||
const initialRelations: Record<string, any> = {}
|
||||
initialRelations[gameStore.player.id] = {
|
||||
fromId: planet.ownerId,
|
||||
toId: gameStore.player.id,
|
||||
reputation: 0,
|
||||
status: 'neutral' as const,
|
||||
lastUpdated: now,
|
||||
history: []
|
||||
}
|
||||
|
||||
npcMap.set(planet.ownerId, {
|
||||
id: planet.ownerId,
|
||||
name: generateNPCName(planet.ownerId, gameStore.locale),
|
||||
planets: [],
|
||||
technologies: {}, // 初始化空科技树
|
||||
difficulty: 'medium' as const, // 默认中等难度
|
||||
relations: initialRelations, // 外交关系(默认与玩家中立)
|
||||
allies: [], // 盟友列表
|
||||
enemies: [], // 敌人列表
|
||||
lastSpyTime: now - randomSpyOffset, // 设置随机的上次侦查时间
|
||||
lastAttackTime: now - randomAttackOffset, // 设置随机的上次攻击时间
|
||||
fleetMissions: [], // 舰队任务
|
||||
playerSpyReports: {} // 对玩家的侦查报告
|
||||
})
|
||||
}
|
||||
|
||||
npcMap.get(planet.ownerId)!.planets.push(planet)
|
||||
})
|
||||
|
||||
// 保存到store
|
||||
npcStore.npcs = Array.from(npcMap.values())
|
||||
|
||||
// 如果有NPC,基于距离初始化NPC实力
|
||||
if (npcStore.npcs.length > 0) {
|
||||
// 获取玩家母星(第一个非月球星球)
|
||||
const homeworld = gameStore.player.planets.find(p => !p.isMoon)
|
||||
|
||||
if (homeworld) {
|
||||
npcStore.npcs.forEach(npc => {
|
||||
// 基于距离初始化NPC实力
|
||||
npcGrowthLogic.initializeNPCByDistance(npc, homeworld.position)
|
||||
// 同步NPC星球数据到universeStore
|
||||
syncNPCPlanetToUniverse(npc)
|
||||
})
|
||||
}
|
||||
|
||||
// 初始化NPC之间的外交关系(盟友/敌人)
|
||||
npcGrowthLogic.initializeNPCDiplomacy(npcStore.npcs)
|
||||
}
|
||||
}
|
||||
|
||||
// 确保所有NPC都有间谍探测器(修复旧版本保存的数据)
|
||||
if (npcStore.npcs.length > 0) {
|
||||
npcGrowthLogic.ensureNPCSpyProbes(npcStore.npcs)
|
||||
}
|
||||
|
||||
// 确保所有NPC都有AI类型(修复旧版本保存的数据)
|
||||
if (npcStore.npcs.length > 0) {
|
||||
npcGrowthLogic.ensureAllNPCsAIType(npcStore.npcs)
|
||||
}
|
||||
|
||||
// 确保所有NPC都与玩家建立了关系(修复旧版本保存的数据)
|
||||
if (npcStore.npcs.length > 0) {
|
||||
const now = Date.now()
|
||||
// 获取玩家母星(用于计算距离)
|
||||
const homeworld = gameStore.player.planets.find(p => !p.isMoon)
|
||||
|
||||
npcStore.npcs.forEach(npc => {
|
||||
if (!npc.relations) {
|
||||
npc.relations = {}
|
||||
}
|
||||
// 如果NPC没有与玩家的关系,建立中立关系
|
||||
if (!npc.relations[gameStore.player.id]) {
|
||||
npc.relations[gameStore.player.id] = {
|
||||
fromId: npc.id,
|
||||
toId: gameStore.player.id,
|
||||
reputation: 0,
|
||||
status: 'neutral' as const,
|
||||
lastUpdated: now,
|
||||
history: []
|
||||
}
|
||||
}
|
||||
|
||||
// 迁移旧存档:如果NPC没有距离数据,计算并设置
|
||||
if (homeworld && npc.distanceToHomeworld === undefined) {
|
||||
const npcPlanet = npc.planets[0]
|
||||
if (npcPlanet) {
|
||||
npc.distanceToHomeworld = npcGrowthLogic.calculateDistanceToHomeworld(npcPlanet.position, homeworld.position)
|
||||
npc.difficultyLevel = npcGrowthLogic.calculateDifficultyLevel(npc.distanceToHomeworld)
|
||||
// 重新初始化NPC实力以匹配新的距离难度系统
|
||||
npcGrowthLogic.initializeNPCByDistance(npc, homeworld.position)
|
||||
// 同步NPC星球数据到universeStore
|
||||
syncNPCPlanetToUniverse(npc)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 如果没有NPC,直接返回
|
||||
if (npcStore.npcs.length === 0) {
|
||||
npcUpdateCounter.value = 0
|
||||
return
|
||||
}
|
||||
|
||||
// 获取玩家母星用于距离计算
|
||||
const homeworldForGrowth = gameStore.player.planets.find(p => !p.isMoon)
|
||||
|
||||
// 使用累积的时间更新每个NPC(基于距离的成长系统)
|
||||
npcStore.npcs.forEach(npc => {
|
||||
if (homeworldForGrowth) {
|
||||
npcGrowthLogic.updateNPCGrowthByDistance(npc, homeworldForGrowth.position, npcUpdateCounter.value, gameStore.gameSpeed)
|
||||
// 同步NPC星球数据到universeStore(确保侦查报告显示正确数据)
|
||||
syncNPCPlanetToUniverse(npc)
|
||||
}
|
||||
})
|
||||
|
||||
// 重置计数器
|
||||
npcUpdateCounter.value = 0
|
||||
}
|
||||
|
||||
const updateNPCBehavior = (deltaSeconds: number) => {
|
||||
// 累积时间
|
||||
npcBehaviorCounter.value += deltaSeconds
|
||||
|
||||
// 只在达到更新间隔时才执行
|
||||
if (npcBehaviorCounter.value < NPC_BEHAVIOR_INTERVAL) {
|
||||
return
|
||||
}
|
||||
|
||||
// 如果没有NPC,直接返回
|
||||
if (npcStore.npcs.length === 0) {
|
||||
npcBehaviorCounter.value = 0
|
||||
return
|
||||
}
|
||||
|
||||
const now = Date.now()
|
||||
// 合并玩家星球和NPC星球到allPlanets(NPC需要能够侦查和攻击玩家星球)
|
||||
const allPlanets = [...gameStore.player.planets, ...Object.values(universeStore.planets)]
|
||||
|
||||
// 计算当前所有正在进行的侦查和攻击任务数量
|
||||
let activeSpyMissions = 0
|
||||
let activeAttackMissions = 0
|
||||
npcStore.npcs.forEach(npc => {
|
||||
if (npc.fleetMissions) {
|
||||
npc.fleetMissions.forEach(mission => {
|
||||
if (mission.status === 'outbound') {
|
||||
if (mission.missionType === 'spy') {
|
||||
activeSpyMissions++
|
||||
} else if (mission.missionType === 'attack') {
|
||||
activeAttackMissions++
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 获取并发限制配置
|
||||
const config = npcBehaviorLogic.calculateDynamicBehavior(gameStore.player.points)
|
||||
|
||||
// 更新每个NPC的行为(随机顺序,避免总是优先处理同一批NPC)
|
||||
const shuffledNpcs = [...npcStore.npcs].sort(() => Math.random() - 0.5)
|
||||
shuffledNpcs.forEach(npc => {
|
||||
// 在更新前检查当前并发数,如果已达上限则跳过该NPC
|
||||
npcBehaviorLogic.updateNPCBehaviorWithLimit(npc, gameStore.player, allPlanets, universeStore.debrisFields, now, {
|
||||
activeSpyMissions,
|
||||
activeAttackMissions,
|
||||
config
|
||||
})
|
||||
|
||||
// 重新计算当前并发数(因为可能新增了任务)
|
||||
activeSpyMissions = 0
|
||||
activeAttackMissions = 0
|
||||
npcStore.npcs.forEach(n => {
|
||||
if (n.fleetMissions) {
|
||||
n.fleetMissions.forEach(mission => {
|
||||
if (mission.status === 'outbound') {
|
||||
if (mission.missionType === 'spy') activeSpyMissions++
|
||||
else if (mission.missionType === 'attack') activeAttackMissions++
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 处理增强NPC行为(中立和友好NPC的特殊行为)
|
||||
const relation = npc.relations?.[gameStore.player.id]
|
||||
if (relation?.status === 'neutral') {
|
||||
const neutralResult = npcBehaviorLogic.updateNeutralNPCBehavior(npc, npcStore.npcs, gameStore.player, now)
|
||||
|
||||
// 处理贸易提议
|
||||
if (neutralResult.tradeOffer) {
|
||||
if (!gameStore.player.tradeOffers) {
|
||||
gameStore.player.tradeOffers = []
|
||||
}
|
||||
gameStore.player.tradeOffers.push(neutralResult.tradeOffer)
|
||||
toast.info(t('npcBehavior.tradeOfferReceived'), {
|
||||
description: t('npcBehavior.tradeOfferDesc', { npcName: neutralResult.tradeOffer.npcName })
|
||||
})
|
||||
}
|
||||
|
||||
// 处理态度摇摆
|
||||
if (neutralResult.swingDirection) {
|
||||
if (!gameStore.player.attitudeChangeNotifications) {
|
||||
gameStore.player.attitudeChangeNotifications = []
|
||||
}
|
||||
gameStore.player.attitudeChangeNotifications.push({
|
||||
id: `attitude_${Date.now()}_${npc.id}`,
|
||||
timestamp: now,
|
||||
npcId: npc.id,
|
||||
npcName: npc.name,
|
||||
previousStatus: 'neutral',
|
||||
newStatus: neutralResult.swingDirection,
|
||||
reason: 'attitude_swing',
|
||||
read: false
|
||||
})
|
||||
const statusKey = neutralResult.swingDirection === 'friendly' ? 'npcBehavior.becameFriendly' : 'npcBehavior.becameHostile'
|
||||
toast.info(t('npcBehavior.attitudeChanged'), {
|
||||
description: t(statusKey, { npcName: npc.name })
|
||||
})
|
||||
}
|
||||
} else if (relation?.status === 'friendly') {
|
||||
const friendlyResult = npcBehaviorLogic.updateFriendlyNPCBehavior(npc, npcStore.npcs, gameStore.player, now)
|
||||
|
||||
// 处理情报报告
|
||||
if (friendlyResult.intelReport) {
|
||||
if (!gameStore.player.intelReports) {
|
||||
gameStore.player.intelReports = []
|
||||
}
|
||||
gameStore.player.intelReports.push(friendlyResult.intelReport)
|
||||
toast.info(t('npcBehavior.intelReceived'), {
|
||||
description: t('npcBehavior.intelReceivedDesc', { npcName: friendlyResult.intelReport.fromNpcName })
|
||||
})
|
||||
}
|
||||
|
||||
// 处理联合攻击邀请
|
||||
if (friendlyResult.jointAttackInvite) {
|
||||
if (!gameStore.player.jointAttackInvites) {
|
||||
gameStore.player.jointAttackInvites = []
|
||||
}
|
||||
gameStore.player.jointAttackInvites.push(friendlyResult.jointAttackInvite)
|
||||
toast.info(t('npcBehavior.jointAttackInvite'), {
|
||||
description: t('npcBehavior.jointAttackInviteDesc', { npcName: friendlyResult.jointAttackInvite.fromNpcName })
|
||||
})
|
||||
}
|
||||
|
||||
// 处理资源援助
|
||||
if (friendlyResult.aidProvided) {
|
||||
if (!gameStore.player.aidNotifications) {
|
||||
gameStore.player.aidNotifications = []
|
||||
}
|
||||
gameStore.player.aidNotifications.push({
|
||||
id: `aid_${Date.now()}_${npc.id}`,
|
||||
timestamp: now,
|
||||
npcId: npc.id,
|
||||
npcName: npc.name,
|
||||
aidResources: friendlyResult.aidProvided,
|
||||
read: false
|
||||
})
|
||||
const totalAid = friendlyResult.aidProvided.metal + friendlyResult.aidProvided.crystal + friendlyResult.aidProvided.deuterium
|
||||
toast.success(t('npcBehavior.aidReceived'), {
|
||||
description: t('npcBehavior.aidReceivedDesc', { npcName: npc.name, amount: totalAid.toLocaleString() })
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
npcBehaviorCounter.value = 0
|
||||
}
|
||||
|
||||
// 更新NPC关系统计(友好/敌对数量)
|
||||
const updateNPCRelationStats = () => {
|
||||
let friendlyCount = 0
|
||||
let hostileCount = 0
|
||||
const playerId = gameStore.player.id
|
||||
npcStore.npcs.forEach(npc => {
|
||||
const relation = npc.relations?.[playerId]
|
||||
if (relation) {
|
||||
const status = diplomaticLogic.calculateRelationStatus(relation.reputation)
|
||||
if (status === 'friendly') {
|
||||
friendlyCount++
|
||||
} else if (status === 'hostile') {
|
||||
hostileCount++
|
||||
}
|
||||
}
|
||||
})
|
||||
gameLogic.trackDiplomacyStats(gameStore.player, 'updateRelations', { friendlyCount, hostileCount })
|
||||
}
|
||||
|
||||
// 检查成就解锁
|
||||
const achievementCheckCounter = ref(0)
|
||||
const ACHIEVEMENT_CHECK_INTERVAL = 5 // 每5秒检查一次成就
|
||||
|
||||
const checkAchievementUnlocks = () => {
|
||||
achievementCheckCounter.value += 1
|
||||
|
||||
// 只在达到更新间隔时才执行
|
||||
if (achievementCheckCounter.value < ACHIEVEMENT_CHECK_INTERVAL) {
|
||||
return
|
||||
}
|
||||
|
||||
// 更新NPC关系统计
|
||||
updateNPCRelationStats()
|
||||
|
||||
// 检查并解锁成就
|
||||
const unlocks = gameLogic.checkAndUnlockAchievements(gameStore.player)
|
||||
|
||||
// 显示成就解锁通知(奖励已在 checkAndUnlockAchievements 中应用)
|
||||
unlocks.forEach(unlock => {
|
||||
// 显示 toast 通知
|
||||
const tierName = t(`achievements.tiers.${unlock.tier}`)
|
||||
const achievementName = t(`achievements.names.${unlock.id}`)
|
||||
toast.success(t('achievements.unlocked'), {
|
||||
description: `${achievementName} (${tierName})`
|
||||
})
|
||||
})
|
||||
|
||||
achievementCheckCounter.value = 0
|
||||
}
|
||||
|
||||
// 启动游戏循环
|
||||
const startGameLoop = () => {
|
||||
if (gameStore.isPaused) return
|
||||
// 清理旧的定时器
|
||||
if (gameLoop.value) {
|
||||
clearInterval(gameLoop.value)
|
||||
}
|
||||
})
|
||||
|
||||
// 创建游戏引擎
|
||||
gameEngine = createGameEngine({
|
||||
t,
|
||||
onTick: async ctx => {
|
||||
const { profiler } = ctx
|
||||
|
||||
// 初始化 ProgressionEngine(首次 tick 时)
|
||||
progressionEngine?.init(ctx)
|
||||
|
||||
// 使用 EconomyEngine 处理资源生产和队列完成
|
||||
profiler.start('tick:economy')
|
||||
economyEngine?.tick(ctx)
|
||||
profiler.end('tick:economy')
|
||||
|
||||
// 使用 MissionEngine 处理任务(玩家任务到达/返回、NPC任务到达/返回、导弹攻击)
|
||||
profiler.start('tick:mission')
|
||||
await missionEngine?.tick(ctx)
|
||||
profiler.end('tick:mission')
|
||||
|
||||
// 使用 NpcEngine 处理NPC成长和行为(分片更新)
|
||||
profiler.start('tick:npc')
|
||||
npcEngine?.tick(ctx)
|
||||
profiler.end('tick:npc')
|
||||
|
||||
// 使用 ProgressionEngine 处理低频任务(成就、战役、外交清理)
|
||||
profiler.start('tick:progression')
|
||||
progressionEngine?.tick(ctx)
|
||||
profiler.end('tick:progression')
|
||||
},
|
||||
onPauseChange: paused => {
|
||||
if (paused) {
|
||||
stopLoop()
|
||||
} else {
|
||||
startLoop()
|
||||
}
|
||||
},
|
||||
notify: (message, type = 'info') => {
|
||||
toast[type](message)
|
||||
},
|
||||
notifyUnlock: handleUnlockNotification
|
||||
})
|
||||
|
||||
// 游戏循环(使用 composable 管理)
|
||||
// gameSpeed 只作用于资源产出和时间消耗的倍率,循环固定为1秒
|
||||
const { start: startLoop, stop: stopLoop } = useGameLoop((now, deltaMs) => {
|
||||
gameEngine?.tick(now, deltaMs)
|
||||
}, 1000)
|
||||
// 游戏循环固定为1秒,避免高倍速时的卡顿
|
||||
// gameSpeed 只作用于资源产出和时间消耗的倍率
|
||||
const interval = 1000
|
||||
// 启动新的游戏循环
|
||||
gameLoop.value = setInterval(() => {
|
||||
updateGame()
|
||||
}, interval)
|
||||
}
|
||||
|
||||
// 停止游戏循环
|
||||
const stopGameLoop = () => {
|
||||
stopLoop()
|
||||
}
|
||||
|
||||
// 启动游戏循环(带暂停检查)
|
||||
const startGameLoop = () => {
|
||||
if (gameEngine?.isPaused()) return
|
||||
startLoop()
|
||||
}
|
||||
|
||||
// 处理页面可见性变化(解决离线进度问题)
|
||||
// 当页面隐藏时停止游戏循环,避免浏览器限流期间浪费离线时间
|
||||
// 当页面恢复可见时,立即处理离线进度并重启游戏循环
|
||||
const handleVisibilityChange = () => {
|
||||
if (document.hidden) {
|
||||
// 页面隐藏,停止游戏循环
|
||||
// 这样 lastUpdate 不会被更新,离线时间会被保留
|
||||
stopGameLoop()
|
||||
if (pointsUpdateInterval.value) {
|
||||
clearInterval(pointsUpdateInterval.value)
|
||||
pointsUpdateInterval.value = null
|
||||
}
|
||||
} else {
|
||||
// 页面恢复可见,立即处理离线进度
|
||||
if (!gameStore.isPaused) {
|
||||
// 重新启动游戏循环(离线时间的资源累积会在下一次 tick 时自动处理)
|
||||
startGameLoop()
|
||||
startPointsUpdate()
|
||||
}
|
||||
if (gameLoop.value) {
|
||||
clearInterval(gameLoop.value)
|
||||
gameLoop.value = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1179,8 +2365,6 @@
|
||||
gameStore.locale = detectBrowserLocale()
|
||||
}
|
||||
await initGame()
|
||||
// 初始化游戏引擎
|
||||
gameEngine?.init()
|
||||
// 启动游戏循环
|
||||
startGameLoop()
|
||||
// 启动积分更新定时器
|
||||
@@ -1192,9 +2376,6 @@
|
||||
window.addEventListener('cancel-build', handleCancelBuildEvent as EventListener)
|
||||
window.addEventListener('cancel-research', handleCancelResearchEvent as EventListener)
|
||||
|
||||
// 添加页面可见性变化监听(解决离线进度问题)
|
||||
document.addEventListener('visibilitychange', handleVisibilityChange)
|
||||
|
||||
// 首次检查版本(被动检测)
|
||||
const versionInfo = await checkLatestVersion(gameStore.player.lastVersionCheckTime || 0, (time: number) => {
|
||||
gameStore.player.lastVersionCheckTime = time
|
||||
@@ -1259,18 +2440,15 @@
|
||||
}
|
||||
})
|
||||
|
||||
// 清理定时器和游戏引擎
|
||||
// 清理定时器
|
||||
onUnmounted(() => {
|
||||
stopGameLoop()
|
||||
gameEngine?.dispose()
|
||||
if (gameLoop.value) clearInterval(gameLoop.value)
|
||||
if (pointsUpdateInterval.value) clearInterval(pointsUpdateInterval.value)
|
||||
if (konamiCleanup.value) konamiCleanup.value()
|
||||
if (versionCheckInterval.value) clearInterval(versionCheckInterval.value)
|
||||
// 移除队列取消事件监听
|
||||
window.removeEventListener('cancel-build', handleCancelBuildEvent as EventListener)
|
||||
window.removeEventListener('cancel-research', handleCancelResearchEvent as EventListener)
|
||||
// 移除页面可见性变化监听
|
||||
document.removeEventListener('visibilitychange', handleVisibilityChange)
|
||||
// 移除 Android 返回键监听
|
||||
if (Capacitor.isNativePlatform()) {
|
||||
CapacitorApp.removeAllListeners()
|
||||
|
||||
Reference in New Issue
Block a user