feat: 重构战报弹窗与模拟器视图,优化UI与逻辑

重构BattleReportDialog和BattleSimulatorView相关静态资源,替换旧版JS/CSS文件,提升界面一致性和交互体验。新增和优化空状态、滚动区域等通用UI组件,移除部分冗余composable,完善多语言内容。引入导弹逻辑,补充版本检测工具,提升整体代码结构和可维护性。
This commit is contained in:
谦君
2025-12-15 20:04:40 +08:00
parent 9b9fda0400
commit 59dd7bfd05
126 changed files with 3944 additions and 1487 deletions

View File

@@ -1,5 +1,25 @@
<template>
<div class="container mx-auto p-4 sm:p-6 space-y-4 sm:space-y-6">
<!-- 无权限时显示404 -->
<div v-if="!gameStore.player.isGMEnabled" class="container mx-auto p-4 sm:p-6 flex items-center justify-center min-h-[60vh]">
<Empty class="border-0">
<EmptyMedia>
<div class="text-8xl sm:text-9xl font-bold text-muted-foreground/20">404</div>
</EmptyMedia>
<EmptyHeader>
<EmptyTitle>{{ t('notFound.title') }}</EmptyTitle>
<EmptyDescription>{{ t('notFound.description') }}</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<Button @click="goHome" size="lg">
<Home class="mr-2 h-4 w-4" />
{{ t('notFound.goHome') }}
</Button>
</EmptyContent>
</Empty>
</div>
<!-- 有权限时显示GM页面 -->
<div v-else class="container mx-auto p-4 sm:p-6 space-y-4 sm:space-y-6">
<div class="flex items-center justify-between">
<h1 class="text-2xl sm:text-3xl font-bold">{{ t('gmView.title') }}</h1>
<Badge variant="destructive">{{ t('gmView.adminOnly') }}</Badge>
@@ -12,7 +32,7 @@
</CardHeader>
<CardContent>
<Select v-model="selectedPlanetId">
<SelectTrigger>
<SelectTrigger class="w-full">
<SelectValue :placeholder="t('gmView.choosePlanet')" />
</SelectTrigger>
<SelectContent>
@@ -25,148 +45,144 @@
</Card>
<!-- 标签切换 -->
<div v-if="selectedPlanet" class="flex flex-wrap gap-2 border-b">
<Button
v-for="tab in tabs"
:key="tab.value"
@click="activeTab = tab.value"
:variant="activeTab === tab.value ? 'default' : 'ghost'"
class="rounded-b-none"
>
{{ t(tab.label) }}
</Button>
</div>
<Tabs v-if="selectedPlanet" default-value="resources" class="w-full">
<TabsList class="grid w-full" :style="{ gridTemplateColumns: `repeat(${tabs.length}, minmax(0, 1fr))` }">
<TabsTrigger v-for="tab in tabs" :key="tab.value" :value="tab.value">
{{ t(tab.label) }}
</TabsTrigger>
</TabsList>
<!-- 资源 -->
<div v-if="selectedPlanet && activeTab === 'resources'" class="space-y-4">
<Card>
<CardHeader>
<CardTitle>{{ t('gmView.modifyResources') }}</CardTitle>
<CardDescription>{{ t('gmView.resourcesDesc') }}</CardDescription>
</CardHeader>
<CardContent class="space-y-4">
<div v-for="resource in resourceTypes" :key="resource" class="space-y-2">
<Label>{{ t(`resources.${resource}`) }}</Label>
<div class="flex gap-2">
<Input v-model.number="selectedPlanet.resources[resource]" type="number" min="0" class="flex-1" />
<Button @click="setResourceAmount(resource, 1000000)" variant="outline" size="sm">+1M</Button>
<Button @click="setResourceAmount(resource, 10000000)" variant="outline" size="sm">+10M</Button>
</div>
</div>
</CardContent>
</Card>
</div>
<!-- 建筑 -->
<div v-if="selectedPlanet && activeTab === 'buildings'" class="space-y-4">
<Card>
<CardHeader>
<CardTitle>{{ t('gmView.modifyBuildings') }}</CardTitle>
<CardDescription>{{ t('gmView.buildingsDesc') }}</CardDescription>
</CardHeader>
<CardContent>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div v-for="building in buildingTypes" :key="building" class="space-y-2">
<Label>{{ BUILDINGS[building].name }}</Label>
<!-- 资源 -->
<TabsContent value="resources" class="space-y-4">
<Card>
<CardHeader>
<CardTitle>{{ t('gmView.modifyResources') }}</CardTitle>
<CardDescription>{{ t('gmView.resourcesDesc') }}</CardDescription>
</CardHeader>
<CardContent class="space-y-4">
<div v-for="resource in resourceTypes" :key="resource" class="space-y-2">
<Label>{{ t(`resources.${resource}`) }}</Label>
<div class="flex gap-2">
<Input v-model.number="selectedPlanet.buildings[building]" type="number" min="0" max="100" class="flex-1" />
<Button @click="setBuildingLevel(building, 10)" variant="outline" size="sm">Lv 10</Button>
<Button @click="setBuildingLevel(building, 30)" variant="outline" size="sm">Lv 30</Button>
<Input v-model.number="selectedPlanet.resources[resource]" type="number" min="0" class="flex-1" />
<Button @click="setResourceAmount(resource, 1000000)" variant="outline" size="sm">+1M</Button>
<Button @click="setResourceAmount(resource, 10000000)" variant="outline" size="sm">+10M</Button>
</div>
</div>
</div>
</CardContent>
</Card>
</div>
</CardContent>
</Card>
</TabsContent>
<!-- 科技 -->
<div v-if="activeTab === 'research'" class="space-y-4">
<Card>
<CardHeader>
<CardTitle>{{ t('gmView.modifyResearch') }}</CardTitle>
<CardDescription>{{ t('gmView.researchDesc') }}</CardDescription>
</CardHeader>
<CardContent>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div v-for="tech in technologyTypes" :key="tech" class="space-y-2">
<Label>{{ TECHNOLOGIES[tech].name }}</Label>
<div class="flex gap-2">
<Input v-model.number="gameStore.player.technologies[tech]" type="number" min="0" max="50" class="flex-1" />
<Button @click="setTechnologyLevel(tech, 10)" variant="outline" size="sm">Lv 10</Button>
<Button @click="setTechnologyLevel(tech, 20)" variant="outline" size="sm">Lv 20</Button>
<!-- 建筑 -->
<TabsContent value="buildings" class="space-y-4">
<Card>
<CardHeader>
<CardTitle>{{ t('gmView.modifyBuildings') }}</CardTitle>
<CardDescription>{{ t('gmView.buildingsDesc') }}</CardDescription>
</CardHeader>
<CardContent>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div v-for="building in buildingTypes" :key="building" class="space-y-2">
<Label>{{ BUILDINGS[building].name }}</Label>
<div class="flex gap-2">
<Input v-model.number="selectedPlanet.buildings[building]" type="number" min="0" max="100" class="flex-1" />
<Button @click="setBuildingLevel(building, 10)" variant="outline" size="sm">Lv 10</Button>
<Button @click="setBuildingLevel(building, 30)" variant="outline" size="sm">Lv 30</Button>
</div>
</div>
</div>
</div>
</CardContent>
</Card>
</div>
</CardContent>
</Card>
</TabsContent>
<!-- 舰船 -->
<div v-if="selectedPlanet && activeTab === 'ships'" class="space-y-4">
<Card>
<CardHeader>
<CardTitle>{{ t('gmView.modifyShips') }}</CardTitle>
<CardDescription>{{ t('gmView.shipsDesc') }}</CardDescription>
</CardHeader>
<CardContent>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div v-for="ship in shipTypes" :key="ship" class="space-y-2">
<Label>{{ SHIPS[ship].name }}</Label>
<div class="flex gap-2">
<Input v-model.number="selectedPlanet.fleet[ship]" type="number" min="0" class="flex-1" />
<Button @click="setShipCount(ship, 100)" variant="outline" size="sm">+100</Button>
<Button @click="setShipCount(ship, 1000)" variant="outline" size="sm">+1K</Button>
<!-- 科技 -->
<TabsContent value="research" class="space-y-4">
<Card>
<CardHeader>
<CardTitle>{{ t('gmView.modifyResearch') }}</CardTitle>
<CardDescription>{{ t('gmView.researchDesc') }}</CardDescription>
</CardHeader>
<CardContent>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div v-for="tech in technologyTypes" :key="tech" class="space-y-2">
<Label>{{ TECHNOLOGIES[tech].name }}</Label>
<div class="flex gap-2">
<Input v-model.number="gameStore.player.technologies[tech]" type="number" min="0" max="50" class="flex-1" />
<Button @click="setTechnologyLevel(tech, 10)" variant="outline" size="sm">Lv 10</Button>
<Button @click="setTechnologyLevel(tech, 20)" variant="outline" size="sm">Lv 20</Button>
</div>
</div>
</div>
</div>
</CardContent>
</Card>
</div>
</CardContent>
</Card>
</TabsContent>
<!-- 防御 -->
<div v-if="selectedPlanet && activeTab === 'defense'" class="space-y-4">
<Card>
<CardHeader>
<CardTitle>{{ t('gmView.modifyDefense') }}</CardTitle>
<CardDescription>{{ t('gmView.defenseDesc') }}</CardDescription>
</CardHeader>
<CardContent>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div v-for="defense in defenseTypes" :key="defense" class="space-y-2">
<Label>{{ DEFENSES[defense].name }}</Label>
<div class="flex gap-2">
<Input v-model.number="selectedPlanet.defense[defense]" type="number" min="0" class="flex-1" />
<Button @click="setDefenseCount(defense, 100)" variant="outline" size="sm">+100</Button>
<Button @click="setDefenseCount(defense, 1000)" variant="outline" size="sm">+1K</Button>
<!-- 舰船 -->
<TabsContent value="ships" class="space-y-4">
<Card>
<CardHeader>
<CardTitle>{{ t('gmView.modifyShips') }}</CardTitle>
<CardDescription>{{ t('gmView.shipsDesc') }}</CardDescription>
</CardHeader>
<CardContent>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div v-for="ship in shipTypes" :key="ship" class="space-y-2">
<Label>{{ SHIPS[ship].name }}</Label>
<div class="flex gap-2">
<Input v-model.number="selectedPlanet.fleet[ship]" type="number" min="0" class="flex-1" />
<Button @click="setShipCount(ship, 100)" variant="outline" size="sm">+100</Button>
<Button @click="setShipCount(ship, 1000)" variant="outline" size="sm">+1K</Button>
</div>
</div>
</div>
</div>
</CardContent>
</Card>
</div>
</CardContent>
</Card>
</TabsContent>
<!-- 军官 -->
<div v-if="activeTab === 'officers'" class="space-y-4">
<Card>
<CardHeader>
<CardTitle>{{ t('gmView.modifyOfficers') }}</CardTitle>
<CardDescription>{{ t('gmView.officersDesc') }}</CardDescription>
</CardHeader>
<CardContent>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div v-for="officer in officerTypes" :key="officer" class="space-y-2">
<Label>{{ OFFICERS[officer].name }}</Label>
<div class="flex gap-2">
<Input v-model.number="officerDays[officer]" type="number" min="0" :placeholder="t('gmView.days')" class="flex-1" />
<Button @click="setOfficerDays(officer, 7)" variant="outline" size="sm">7{{ t('gmView.days') }}</Button>
<Button @click="setOfficerDays(officer, 30)" variant="outline" size="sm">30{{ t('gmView.days') }}</Button>
<Button @click="setOfficerDays(officer, 365)" variant="outline" size="sm">365{{ t('gmView.days') }}</Button>
<!-- 防御 -->
<TabsContent value="defense" class="space-y-4">
<Card>
<CardHeader>
<CardTitle>{{ t('gmView.modifyDefense') }}</CardTitle>
<CardDescription>{{ t('gmView.defenseDesc') }}</CardDescription>
</CardHeader>
<CardContent>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div v-for="defense in defenseTypes" :key="defense" class="space-y-2">
<Label>{{ DEFENSES[defense].name }}</Label>
<div class="flex gap-2">
<Input v-model.number="selectedPlanet.defense[defense]" type="number" min="0" class="flex-1" />
<Button @click="setDefenseCount(defense, 100)" variant="outline" size="sm">+100</Button>
<Button @click="setDefenseCount(defense, 1000)" variant="outline" size="sm">+1K</Button>
</div>
</div>
</div>
</div>
</CardContent>
</Card>
</div>
</CardContent>
</Card>
</TabsContent>
<!-- 军官 -->
<TabsContent value="officers" class="space-y-4">
<Card>
<CardHeader>
<CardTitle>{{ t('gmView.modifyOfficers') }}</CardTitle>
<CardDescription>{{ t('gmView.officersDesc') }}</CardDescription>
</CardHeader>
<CardContent>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div v-for="officer in officerTypes" :key="officer" class="space-y-2">
<Label>{{ OFFICERS[officer].name }}</Label>
<div class="flex gap-2">
<Input v-model.number="officerDays[officer]" type="number" min="0" :placeholder="t('gmView.days')" class="flex-1" />
<Button @click="setOfficerDays(officer, 7)" variant="outline" size="sm">7{{ t('gmView.days') }}</Button>
<Button @click="setOfficerDays(officer, 30)" variant="outline" size="sm">30{{ t('gmView.days') }}</Button>
<Button @click="setOfficerDays(officer, 365)" variant="outline" size="sm">365{{ t('gmView.days') }}</Button>
</div>
</div>
</div>
</CardContent>
</Card>
</TabsContent>
</Tabs>
<!-- NPC测试 -->
<Card class="border-primary">
@@ -175,30 +191,32 @@
<CardDescription>{{ t('gmView.npcTestingDesc') || 'Test NPC spy and attack behavior' }}</CardDescription>
</CardHeader>
<CardContent class="space-y-3">
<div class="space-y-2">
<Label>{{ t('gmView.selectNPC') || 'Select NPC' }}</Label>
<Select v-model="selectedNPCId">
<SelectTrigger>
<SelectValue :placeholder="t('gmView.chooseNPC') || 'Choose NPC'" />
</SelectTrigger>
<SelectContent>
<SelectItem v-for="npc in npcStore.npcs" :key="npc.id" :value="npc.id">{{ npc.name }} ({{ npc.difficulty }})</SelectItem>
</SelectContent>
</Select>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
<div class="space-y-2">
<Label>{{ t('gmView.selectNPC') || 'Select NPC' }}</Label>
<Select v-model="selectedNPCId">
<SelectTrigger class="w-full">
<SelectValue :placeholder="t('gmView.chooseNPC') || 'Choose NPC'" />
</SelectTrigger>
<SelectContent>
<SelectItem v-for="npc in npcStore.npcs" :key="npc.id" :value="npc.id">{{ npc.name }} ({{ npc.difficulty }})</SelectItem>
</SelectContent>
</Select>
</div>
<div class="space-y-2">
<Label>{{ t('gmView.targetPlanet') || 'Target Planet' }}</Label>
<Select v-model="targetPlanetIndex">
<SelectTrigger>
<SelectValue :placeholder="t('gmView.chooseTarget') || 'Choose Target Planet'" />
</SelectTrigger>
<SelectContent>
<SelectItem v-for="(planet, index) in gameStore.player.planets" :key="planet.id" :value="index.toString()">
{{ planet.name }} ({{ planet.position.galaxy }}:{{ planet.position.system }}:{{ planet.position.position }})
</SelectItem>
</SelectContent>
</Select>
<div class="space-y-2">
<Label>{{ t('gmView.targetPlanet') || 'Target Planet' }}</Label>
<Select v-model="targetPlanetIndex">
<SelectTrigger class="w-full">
<SelectValue :placeholder="t('gmView.chooseTarget') || 'Choose Target Planet'" />
</SelectTrigger>
<SelectContent>
<SelectItem v-for="(planet, index) in gameStore.player.planets" :key="planet.id" :value="index.toString()">
{{ planet.name }} ({{ planet.position.galaxy }}:{{ planet.position.system }}:{{ planet.position.position }})
</SelectItem>
</SelectContent>
</Select>
</div>
</div>
<div class="grid grid-cols-2 gap-2">
@@ -231,14 +249,46 @@
<CardDescription>{{ t('gmView.dangerZoneDesc') }}</CardDescription>
</CardHeader>
<CardContent class="space-y-2">
<Button @click="resetGame" variant="destructive" class="w-full">{{ t('gmView.resetGame') }}</Button>
<Button @click="showResetConfirmDialog" variant="destructive" class="w-full">{{ t('gmView.resetGame') }}</Button>
</CardContent>
</Card>
<!-- Reset Game 确认对话框 -->
<AlertDialog :open="resetDialogOpen" @update:open="handleResetDialogClose">
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{{ t('gmView.resetGame') }}</AlertDialogTitle>
<AlertDialogDescription>
{{ t('gmView.resetGameConfirm') }}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel @click="handleResetCancel">{{ t('common.cancel') }}</AlertDialogCancel>
<AlertDialogAction @click="confirmResetGame">{{ t('common.confirm') }}</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<!-- AlertDialog 提示对话框 -->
<AlertDialog :open="alertDialogOpen" @update:open="alertDialogOpen = $event">
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{{ alertDialogTitle }}</AlertDialogTitle>
<AlertDialogDescription v-if="alertDialogMessage" class="whitespace-pre-line">
{{ alertDialogMessage }}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogAction @click="handleAlertConfirm">{{ t('common.confirm') }}</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useRouter } from 'vue-router'
import { useGameStore } from '@/stores/gameStore'
import { useNPCStore } from '@/stores/npcStore'
import { useUniverseStore } from '@/stores/universeStore'
@@ -250,21 +300,47 @@
import { Label } from '@/components/ui/label'
import { Badge } from '@/components/ui/badge'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from '@/components/ui/empty'
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle
} from '@/components/ui/alert-dialog'
import { BuildingType, TechnologyType, ShipType, DefenseType, OfficerType } from '@/types/game'
import * as npcBehaviorLogic from '@/logic/npcBehaviorLogic'
import { Home } from 'lucide-vue-next'
const router = useRouter()
const gameStore = useGameStore()
const npcStore = useNPCStore()
const universeStore = useUniverseStore()
const { t } = useI18n()
const { BUILDINGS, TECHNOLOGIES, SHIPS, DEFENSES, OFFICERS } = useGameConfig()
const goHome = () => {
router.push('/')
}
const selectedPlanetId = ref<string>(gameStore.player.planets[0]?.id || '')
const activeTab = ref<'resources' | 'buildings' | 'research' | 'ships' | 'defense' | 'officers'>('resources')
const officerDays = ref<Record<OfficerType, number>>({} as Record<OfficerType, number>)
const selectedNPCId = ref<string>(npcStore.npcs[0]?.id || '')
const targetPlanetIndex = ref<string>('0')
// AlertDialog 状态
const alertDialogOpen = ref(false)
const alertDialogTitle = ref('')
const alertDialogMessage = ref('')
const alertDialogCallback = ref<(() => void) | null>(null)
// Reset Dialog 状态
const resetDialogOpen = ref(false)
// 初始化军官天数显示
Object.values(OfficerType).forEach(officer => {
const officerData = gameStore.player.officers[officer]
@@ -354,17 +430,63 @@
}
}
const resetGame = () => {
if (confirm(t('gmView.resetGameConfirm'))) {
// 显示重置游戏确认对话框
const showResetConfirmDialog = () => {
// 暂停游戏
gameStore.isPaused = true
resetDialogOpen.value = true
}
// 处理重置对话框关闭
const handleResetDialogClose = (open: boolean) => {
if (!open) {
// 如果对话框关闭,恢复游戏
gameStore.isPaused = false
}
resetDialogOpen.value = open
}
// 取消重置
const handleResetCancel = () => {
resetDialogOpen.value = false
gameStore.isPaused = false
}
// 确认重置游戏
const confirmResetGame = () => {
gameStore.isPaused = true
resetDialogOpen.value = false
try {
gameStore.player.isGMEnabled = false
localStorage.clear()
location.reload()
} catch (error) {
console.error('Failed to reset game:', error)
window.location.reload()
}
}
// 显示AlertDialog的辅助函数
const showAlert = (title: string, message: string, callback?: () => void) => {
alertDialogTitle.value = title
alertDialogMessage.value = message
alertDialogCallback.value = callback || null
alertDialogOpen.value = true
}
// AlertDialog确认处理
const handleAlertConfirm = () => {
alertDialogOpen.value = false
if (alertDialogCallback.value) {
alertDialogCallback.value()
alertDialogCallback.value = null
}
}
// NPC测试函数
const testNPCSpy = () => {
if (!selectedNPC.value) {
alert(t('gmView.selectNPCFirst') || 'Please select an NPC first')
showAlert(t('gmView.selectNPCFirst') || 'Please select an NPC first', '')
return
}
@@ -376,17 +498,18 @@
)
if (mission) {
// 加速任务到5秒后到达
npcBehaviorLogic.accelerateNPCMission(selectedNPC.value, mission.id, 5)
alert(`${selectedNPC.value.name} will spy in 5 seconds`)
showAlert(t('gmView.npcWillSpyIn5s', { npcName: selectedNPC.value.name }), t('gmView.testSpyMessage'), () => {
// 加速任务到5秒后到达在确认后执行这样时间更准确
npcBehaviorLogic.accelerateNPCMission(selectedNPC.value!, mission.id, 5, gameStore.player)
})
} else {
alert(t('gmView.npcNoProbes') || 'NPC does not have spy probes')
showAlert(t('gmView.npcNoProbes') || 'NPC does not have spy probes', '')
}
}
const testNPCAttack = () => {
if (!selectedNPC.value) {
alert(t('gmView.selectNPCFirst') || 'Please select an NPC first')
showAlert(t('gmView.selectNPCFirst') || 'Please select an NPC first', '')
return
}
@@ -398,17 +521,18 @@
)
if (mission) {
// 加速任务到5秒后到达
npcBehaviorLogic.accelerateNPCMission(selectedNPC.value, mission.id, 5)
alert(`${selectedNPC.value.name} will attack in 5 seconds`)
showAlert(t('gmView.npcWillAttackIn5s', { npcName: selectedNPC.value.name }), t('gmView.testAttackMessage'), () => {
// 加速任务到5秒后到达在确认后执行这样时间更准确
npcBehaviorLogic.accelerateNPCMission(selectedNPC.value!, mission.id, 5, gameStore.player)
})
} else {
alert(t('gmView.npcNoSpyReport') || 'NPC needs to spy first')
showAlert(t('gmView.npcNoSpyReport') || 'NPC needs to spy first', '')
}
}
const testNPCSpyAndAttack = () => {
if (!selectedNPC.value) {
alert(t('gmView.selectNPCFirst') || 'Please select an NPC first')
showAlert(t('gmView.selectNPCFirst') || 'Please select an NPC first', '')
return
}
@@ -420,36 +544,37 @@
)
if (spyMission && attackMission) {
// 加速任务侦查5秒后到达攻击10秒后到达
npcBehaviorLogic.accelerateNPCMission(selectedNPC.value, spyMission.id, 5)
npcBehaviorLogic.accelerateNPCMission(selectedNPC.value, attackMission.id, 10)
alert(`${selectedNPC.value.name} will spy in 5s and attack in 10s`)
showAlert(t('gmView.npcWillSpyAndAttack', { npcName: selectedNPC.value.name }), t('gmView.testSpyAndAttackMessage'), () => {
// 加速任务侦查5秒后到达攻击10秒后到达在确认后执行这样时间更准确
npcBehaviorLogic.accelerateNPCMission(selectedNPC.value!, spyMission.id, 5, gameStore.player)
npcBehaviorLogic.accelerateNPCMission(selectedNPC.value!, attackMission.id, 10, gameStore.player)
})
} else {
alert(t('gmView.npcMissionFailed') || 'Failed to create missions')
showAlert(t('gmView.npcMissionFailed') || 'Failed to create missions', '')
}
}
const accelerateAllMissions = () => {
if (!selectedNPC.value) {
alert(t('gmView.selectNPCFirst') || 'Please select an NPC first')
showAlert(t('gmView.selectNPCFirst') || 'Please select an NPC first', '')
return
}
const count = npcBehaviorLogic.accelerateAllNPCMissions(selectedNPC.value, 5)
alert(`Accelerated ${count} missions to 5 seconds`)
const count = npcBehaviorLogic.accelerateAllNPCMissions(selectedNPC.value, 5, gameStore.player)
showAlert(t('gmView.acceleratedMissions', { count }), '')
}
// 初始化NPC舰队
const initializeNPCFleet = () => {
if (!selectedNPC.value) {
alert(t('gmView.selectNPCFirst') || 'Please select an NPC first')
showAlert(t('gmView.selectNPCFirst') || 'Please select an NPC first', '')
return
}
// 给NPC的第一个星球添加基础舰队
const npcPlanet = selectedNPC.value.planets[0]
if (!npcPlanet) {
alert('NPC has no planets')
showAlert(t('gmView.npcNoPlanets'), '')
return
}
@@ -465,8 +590,6 @@
npcPlanet.fleet[ShipType.Destroyer] = (npcPlanet.fleet[ShipType.Destroyer] || 0) + 30
npcPlanet.fleet[ShipType.Battlecruiser] = (npcPlanet.fleet[ShipType.Battlecruiser] || 0) + 20
alert(
`${selectedNPC.value.name} fleet initialized:\n- 100 Spy Probes\n- 500 Light Fighters\n- 300 Heavy Fighters\n- 200 Cruisers\n- 100 Battleships\n- 50 Bombers\n- 30 Destroyers\n- 20 Battlecruisers`
)
showAlert(t('gmView.npcFleetInitialized', { npcName: selectedNPC.value.name }), t('gmView.npcFleetDetails'))
}
</script>