+
+
+
+
+
{{ t('fleetView.totalCargoCapacity') }}: {{ formatNumber(getTotalCargoCapacity()) }} | {{ t('fleetView.used') }}:
@@ -344,7 +358,7 @@
import { useGameConfig } from '@/composables/useGameConfig'
import { computed, ref, onMounted, onUnmounted, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
- import { ShipType, MissionType, BuildingType } from '@/types/game'
+ import { ShipType, MissionType, BuildingType, TechnologyType } from '@/types/game'
import type { Fleet, Resources } from '@/types/game'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
@@ -366,7 +380,7 @@
AlertDialogTitle
} from '@/components/ui/alert-dialog'
import UnlockRequirement from '@/components/UnlockRequirement.vue'
- import { Sword, Package, Rocket as RocketIcon, Eye, Users, Recycle, Skull, Gift } from 'lucide-vue-next'
+ import { Sword, Package, Rocket as RocketIcon, Eye, Users, Recycle, Skull, Gift, Compass } from 'lucide-vue-next'
import { formatNumber, formatTime } from '@/utils/format'
import * as shipValidation from '@/logic/shipValidation'
import * as fleetLogic from '@/logic/fleetLogic'
@@ -397,7 +411,8 @@
// 计算最大舰队任务槽位
const maxFleetMissions = computed(() => {
const bonuses = officerLogic.calculateActiveBonuses(gameStore.player.officers, Date.now())
- return publicLogic.getMaxFleetMissions(bonuses.additionalFleetSlots)
+ const computerTechLevel = gameStore.player.technologies[TechnologyType.ComputerTechnology] || 0
+ return publicLogic.getMaxFleetMissions(bonuses.additionalFleetSlots, computerTechLevel)
})
const activeTab = ref<'fleet' | 'send' | 'missions'>('fleet')
@@ -504,6 +519,7 @@
{ type: MissionType.Colonize, name: t('fleetView.colonize'), icon: RocketIcon },
{ type: MissionType.Spy, name: t('fleetView.spy'), icon: Eye },
{ type: MissionType.Deploy, name: t('fleetView.deploy'), icon: Users },
+ { type: MissionType.Expedition, name: t('fleetView.expedition'), icon: Compass },
{ type: MissionType.Recycle, name: t('fleetView.recycle'), icon: Recycle },
{ type: MissionType.Destroy, name: t('fleetView.destroy'), icon: Skull }
])
@@ -616,7 +632,8 @@
fleet,
cargo,
gameStore.player.officers,
- currentMissions
+ currentMissions,
+ gameStore.player.technologies
)
if (!validation.valid) return false
const shouldDeductCargo = missionType === MissionType.Transport
diff --git a/src/views/GMView.vue b/src/views/GMView.vue
index 788c2c3..68c93e5 100644
--- a/src/views/GMView.vue
+++ b/src/views/GMView.vue
@@ -331,6 +331,7 @@
} from '@/components/ui/alert-dialog'
import { BuildingType, TechnologyType, ShipType, DefenseType, OfficerType } from '@/types/game'
import * as npcBehaviorLogic from '@/logic/npcBehaviorLogic'
+ import * as publicLogic from '@/logic/publicLogic'
import { Home } from 'lucide-vue-next'
const router = useRouter()
@@ -340,6 +341,11 @@
const { t } = useI18n()
const { BUILDINGS, TECHNOLOGIES, SHIPS, DEFENSES, OFFICERS } = useGameConfig()
+ // 更新玩家积分的辅助函数
+ const updatePlayerPoints = () => {
+ gameStore.player.points = publicLogic.calculatePlayerPoints(gameStore.player)
+ }
+
const goHome = () => {
router.push('/')
}
@@ -407,22 +413,26 @@
const setBuildingLevel = (building: BuildingType, level: number) => {
if (selectedPlanet.value) {
selectedPlanet.value.buildings[building] = level
+ updatePlayerPoints()
}
}
const setTechnologyLevel = (tech: TechnologyType, level: number) => {
gameStore.player.technologies[tech] = level
+ updatePlayerPoints()
}
const setShipCount = (ship: ShipType, count: number) => {
if (selectedPlanet.value) {
selectedPlanet.value.fleet[ship] = (selectedPlanet.value.fleet[ship] || 0) + count
+ updatePlayerPoints()
}
}
const setDefenseCount = (defense: DefenseType, count: number) => {
if (selectedPlanet.value) {
selectedPlanet.value.defense[defense] = (selectedPlanet.value.defense[defense] || 0) + count
+ updatePlayerPoints()
}
}
@@ -614,7 +624,7 @@
const maxAllResources = () => {
if (!selectedPlanet.value) return
- const maxAmount = 1000000000 // 10亿
+ const maxAmount = 1000000000000000000
selectedPlanet.value.resources.metal = maxAmount
selectedPlanet.value.resources.crystal = maxAmount
selectedPlanet.value.resources.deuterium = maxAmount
@@ -708,6 +718,9 @@
}
})
+ // 更新玩家积分(因为建筑/科技/舰队/防御可能已改变)
+ updatePlayerPoints()
+
toast.success(
t('gmView.completeQueuesSuccess', {
buildingCount,
diff --git a/src/views/MessagesView.vue b/src/views/MessagesView.vue
index 0332997..b759e6b 100644
--- a/src/views/MessagesView.vue
+++ b/src/views/MessagesView.vue
@@ -4,7 +4,7 @@
-
+
{{ tab.label }}
@@ -555,7 +555,7 @@
import BattleReportDialog from '@/components/BattleReportDialog.vue'
import SpyReportDialog from '@/components/SpyReportDialog.vue'
import { formatDate } from '@/utils/format'
- import { X, Sword, Eye, AlertTriangle, Package, Recycle, Gift, Ban, Check, Users, Skull, Globe } from 'lucide-vue-next'
+ import { X, Sword, Eye, AlertTriangle, Package, Recycle, Gift, Ban, Check, Users, Skull, Globe, Compass } from 'lucide-vue-next'
import type {
BattleResult,
SpyReport,
@@ -837,6 +837,7 @@
[MissionType.Transport]: t('fleetView.transport'),
[MissionType.Colonize]: t('fleetView.colonize'),
[MissionType.Deploy]: t('fleetView.deploy'),
+ [MissionType.Expedition]: t('fleetView.expedition'),
[MissionType.Recycle]: t('fleetView.recycle'),
[MissionType.Destroy]: t('fleetView.destroy'),
[MissionType.MissileAttack]: t('galaxyView.missileAttack')
@@ -963,6 +964,8 @@
return Recycle
case MissionType.Colonize:
return Globe
+ case MissionType.Expedition:
+ return Compass
case MissionType.Destroy:
return Skull
default:
diff --git a/src/views/ResearchView.vue b/src/views/ResearchView.vue
index ccc5e58..36c0942 100644
--- a/src/views/ResearchView.vue
+++ b/src/views/ResearchView.vue
@@ -65,9 +65,18 @@
{{ alertDialogTitle }}
-
+
{{ alertDialogMessage }}
+
+
+
+
+
+ {{ req.name }}: Lv {{ req.requiredLevel }} ({{ t('common.current') }}: Lv {{ req.currentLevel }})
+
+
+
{{ t('common.confirm') }}
@@ -99,6 +108,7 @@
AlertDialogTitle
} from '@/components/ui/alert-dialog'
import CardUnlockOverlay from '@/components/CardUnlockOverlay.vue'
+ import { Check, X } from 'lucide-vue-next'
import { formatNumber, getResourceCostColor } from '@/utils/format'
import * as publicLogic from '@/logic/publicLogic'
import * as researchLogic from '@/logic/researchLogic'
@@ -115,6 +125,8 @@
const alertDialogOpen = ref(false)
const alertDialogTitle = ref('')
const alertDialogMessage = ref('')
+ const alertDialogRequirements = ref>([])
+ const alertDialogShowRequirements = ref(false)
// 资源类型配置(用于成本显示)
const costResourceTypes = [
@@ -185,8 +197,10 @@
return t('researchView.research') // "研究"
}
- // 获取前置条件列表文本
- const getRequirementsList = (techType: TechnologyType): string => {
+ // 获取前置条件列表
+ const getRequirementsList = (
+ techType: TechnologyType
+ ): Array<{ name: string; requiredLevel: number; currentLevel: number; met: boolean }> => {
const config = TECHNOLOGIES.value[techType]
const currentLevel = getTechLevel(techType)
const targetLevel = currentLevel + 1
@@ -194,28 +208,59 @@
// 获取目标等级的所有前置条件(包括等级门槛)
const requirements = publicLogic.getLevelRequirements(config, targetLevel)
- if (!requirements || !planet.value) return ''
+ if (!requirements || !planet.value) return []
- const lines: string[] = []
+ const items: Array<{ name: string; requiredLevel: number; currentLevel: number; met: boolean }> = []
for (const [key, requiredLevel] of Object.entries(requirements)) {
// 检查是否为建筑类型
if (Object.values(BuildingType).includes(key as BuildingType)) {
const bt = key as BuildingType
const currentLevel = planet.value.buildings[bt] || 0
const name = BUILDINGS.value[bt]?.name || bt
- const status = currentLevel >= requiredLevel ? '✓' : '✗'
- lines.push(`${status} ${name}: Lv ${requiredLevel} (${t('common.current')}: Lv ${currentLevel})`)
+ items.push({ name, requiredLevel, currentLevel, met: currentLevel >= requiredLevel })
}
// 检查是否为科技类型
else if (Object.values(TechnologyType).includes(key as TechnologyType)) {
const tt = key as TechnologyType
const currentLevel = gameStore.player.technologies[tt] || 0
const name = TECHNOLOGIES.value[tt]?.name || tt
- const status = currentLevel >= requiredLevel ? '✓' : '✗'
- lines.push(`${status} ${name}: Lv ${requiredLevel} (${t('common.current')}: Lv ${currentLevel})`)
+ items.push({ name, requiredLevel, currentLevel, met: currentLevel >= requiredLevel })
}
}
- return lines.join('\n')
+ return items
+ }
+
+ // 获取前置条件显示(简化版,用于卡片内显示)
+ const getRequirementsDisplay = (techType: TechnologyType): Array<{ name: string; level: number; met: boolean }> => {
+ if (!planet.value) return []
+
+ const config = TECHNOLOGIES.value[techType]
+ const currentLevel = getTechLevel(techType)
+ const targetLevel = currentLevel + 1
+
+ // 获取目标等级的所有前置条件(包括等级门槛)
+ const requirements = publicLogic.getLevelRequirements(config, targetLevel)
+
+ if (!requirements || Object.keys(requirements).length === 0) return []
+
+ const items: Array<{ name: string; level: number; met: boolean }> = []
+ for (const [key, requiredLevel] of Object.entries(requirements)) {
+ // 检查是否为建筑类型
+ if (Object.values(BuildingType).includes(key as BuildingType)) {
+ const bt = key as BuildingType
+ const currentLevel = planet.value.buildings[bt] || 0
+ const name = BUILDINGS.value[bt]?.name || bt
+ items.push({ name, level: requiredLevel, met: currentLevel >= requiredLevel })
+ }
+ // 检查是否为科技类型
+ else if (Object.values(TechnologyType).includes(key as TechnologyType)) {
+ const tt = key as TechnologyType
+ const currentLevel = gameStore.player.technologies[tt] || 0
+ const name = TECHNOLOGIES.value[tt]?.name || tt
+ items.push({ name, level: requiredLevel, met: currentLevel >= requiredLevel })
+ }
+ }
+ return items
}
// 研究科技
@@ -223,7 +268,9 @@
// 检查前置条件
if (!checkUpgradeRequirements(techType)) {
alertDialogTitle.value = t('common.requirementsNotMet')
- alertDialogMessage.value = getRequirementsList(techType)
+ alertDialogRequirements.value = getRequirementsList(techType)
+ alertDialogShowRequirements.value = true
+ alertDialogMessage.value = ''
alertDialogOpen.value = true
return
}
@@ -232,6 +279,7 @@
if (!success) {
alertDialogTitle.value = t('researchView.researchFailed')
alertDialogMessage.value = t('researchView.researchFailedMessage')
+ alertDialogShowRequirements.value = false
alertDialogOpen.value = true
}
}
@@ -253,6 +301,12 @@
return false
}
+ // 检查队列中是否已存在该科技的研究任务
+ const existingQueueItem = player.value.researchQueue.find(item => item.type === 'technology' && item.itemType === techType)
+ if (existingQueueItem) {
+ return false
+ }
+
// 检查研究队列是否已满
const maxQueue = publicLogic.getMaxResearchQueue(gameStore.player.technologies)
if (player.value.researchQueue.length >= maxQueue) {