feat: 新增NPC与外交逻辑,优化UI组件结构

重构并精简了部分UI组件,移除冗余弹窗与详情组件,新增NPC相关逻辑(npcBehaviorLogic、npcGrowthLogic、npcStore等)及外交逻辑(diplomaticLogic、DiplomacyView)。完善分页、标签、复选框等通用UI组件。优化战报弹窗,调整README下载链接为相对路径,修复部分国际化内容。
This commit is contained in:
谦君
2025-12-15 08:23:45 +08:00
parent 44580909a3
commit 9b9fda0400
164 changed files with 18628 additions and 2775 deletions

View File

@@ -0,0 +1,733 @@
<template>
<div class="space-y-4">
<!-- 建筑/科技等级范围表格 -->
<div v-if="type === 'building' || type === 'technology'" class="border rounded-lg overflow-hidden">
<Table>
<TableHeader>
<TableRow>
<TableHead class="w-20 text-center">{{ t(`${typeKey}.levelRange`) }}</TableHead>
<TableHead class="text-center">{{ t('resources.metal') }}</TableHead>
<TableHead class="text-center">{{ t('resources.crystal') }}</TableHead>
<TableHead class="text-center">{{ t('resources.deuterium') }}</TableHead>
<TableHead v-if="showDarkMatterColumn" class="text-center">{{ t('resources.darkMatter') }}</TableHead>
<TableHead class="text-center">{{ type === 'building' ? t('buildings.buildTime') : t('research.researchTime') }}</TableHead>
<!-- 建筑相关列 -->
<TableHead v-if="type === 'building' && showProductionColumn" class="text-center">{{ t('buildings.production') }}</TableHead>
<TableHead v-if="type === 'building' && showConsumptionColumn" class="text-center">{{ t('buildings.consumption') }}</TableHead>
<TableHead v-if="type === 'building' && showCapacityColumn" class="text-center">{{ t('buildings.storageCapacity') }}</TableHead>
<TableHead v-if="type === 'building' && showFleetStorageColumn" class="text-center">{{ t('buildings.fleetStorage') }}</TableHead>
<TableHead v-if="type === 'building' && showBuildQueueColumn" class="text-center">{{ t('buildings.buildQueueBonus') }}</TableHead>
<TableHead v-if="type === 'building' && showSpaceColumn" class="text-center">{{ t('buildings.spaceBonus') }}</TableHead>
<TableHead v-if="type === 'building' && showMissileColumn" class="text-center">{{ t('buildings.missileCapacity') }}</TableHead>
<TableHead v-if="type === 'building' && showBuildSpeedColumn" class="text-center">{{ t('buildings.buildSpeedBonus') }}</TableHead>
<TableHead v-if="type === 'building' && showResearchSpeedColumn" class="text-center">{{ t('buildings.researchSpeedBonus') }}</TableHead>
<!-- 科技相关列 -->
<TableHead v-if="type === 'technology' && showAttackBonusColumn" class="text-center">{{ t('research.attackBonus') }}</TableHead>
<TableHead v-if="type === 'technology' && showShieldBonusColumn" class="text-center">{{ t('research.shieldBonus') }}</TableHead>
<TableHead v-if="type === 'technology' && showArmorBonusColumn" class="text-center">{{ t('research.armorBonus') }}</TableHead>
<TableHead v-if="type === 'technology' && showSpyLevelColumn" class="text-center">{{ t('research.spyLevel') }}</TableHead>
<TableHead v-if="type === 'technology' && showFleetStorageColumn" class="text-center">{{ t('buildings.fleetStorage') }}</TableHead>
<TableHead v-if="type === 'technology' && showResearchQueueColumn" class="text-center">{{ t('research.researchQueueBonus') }}</TableHead>
<TableHead v-if="type === 'technology' && showColonySlotsColumn" class="text-center">{{ t('research.colonySlots') }}</TableHead>
<TableHead v-if="type === 'technology' && showSpaceColumn" class="text-center">{{ t('buildings.spaceBonus') }}</TableHead>
<TableHead v-if="type === 'technology' && showSpeedBonusColumn" class="text-center">{{ t('research.speedBonus') }}</TableHead>
<TableHead v-if="type === 'technology' && showResearchSpeedColumn" class="text-center">{{ t('buildings.researchSpeedBonus') }}</TableHead>
<TableHead class="text-center">{{ t('player.points') }}</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow v-for="level in levelRange" :key="level" :class="{ 'bg-muted/50': level === safeCurrentLevel }">
<TableCell class="text-center font-medium">
<Badge v-if="level === safeCurrentLevel" variant="default">{{ level }}</Badge>
<span v-else>{{ level }}</span>
</TableCell>
<TableCell class="text-center text-sm">
<NumberWithTooltip :value="getLevelData(level).cost.metal" />
</TableCell>
<TableCell class="text-center text-sm">
<NumberWithTooltip :value="getLevelData(level).cost.crystal" />
</TableCell>
<TableCell class="text-center text-sm">
<NumberWithTooltip :value="getLevelData(level).cost.deuterium" />
</TableCell>
<TableCell v-if="showDarkMatterColumn" class="text-center text-sm">
<NumberWithTooltip :value="getLevelData(level).cost.darkMatter" />
</TableCell>
<TableCell class="text-center text-sm">{{ formatTime(getLevelData(level).time) }}</TableCell>
<!-- 建筑相关数据 -->
<TableCell v-if="type === 'building' && showProductionColumn" class="text-center text-sm">
<span v-if="getLevelData(level).production > 0" class="text-green-600 dark:text-green-400">
+
<NumberWithTooltip :value="getLevelData(level).production" />
/{{ t('resources.perHour') }}
</span>
<span v-else>-</span>
</TableCell>
<TableCell v-if="type === 'building' && showConsumptionColumn" class="text-center text-sm">
<span v-if="getLevelData(level).consumption > 0" class="text-red-600 dark:text-red-400">
-
<NumberWithTooltip :value="getLevelData(level).consumption" />
</span>
<span v-else>-</span>
</TableCell>
<TableCell v-if="type === 'building' && showCapacityColumn" class="text-center text-sm">
<span v-if="getLevelData(level).capacity > 0" class="text-blue-600 dark:text-blue-400">
<NumberWithTooltip :value="getLevelData(level).capacity" />
</span>
<span v-else>-</span>
</TableCell>
<TableCell v-if="type === 'building' && showFleetStorageColumn" class="text-center text-sm">
<span v-if="getLevelData(level).fleetStorage > 0" class="text-blue-600 dark:text-blue-400">
+<NumberWithTooltip :value="getLevelData(level).fleetStorage" />
</span>
<span v-else>-</span>
</TableCell>
<TableCell v-if="type === 'building' && showBuildQueueColumn" class="text-center text-sm">
<span class="text-purple-600 dark:text-purple-400">+1</span>
</TableCell>
<TableCell v-if="type === 'building' && showSpaceColumn" class="text-center text-sm">
<span v-if="getLevelData(level).spaceBonus > 0" class="text-green-600 dark:text-green-400">
+<NumberWithTooltip :value="getLevelData(level).spaceBonus" />
</span>
<span v-else>-</span>
</TableCell>
<TableCell v-if="type === 'building' && showMissileColumn" class="text-center text-sm">
<span class="text-orange-600 dark:text-orange-400">+10</span>
</TableCell>
<TableCell v-if="type === 'building' && showBuildSpeedColumn" class="text-center text-sm">
<span v-if="itemType === 'roboticsFactory'" class="text-cyan-600 dark:text-cyan-400">+{{ getLevelData(level).buildSpeedBonus * 100 }}%</span>
<span v-else-if="itemType === 'naniteFactory'" class="text-cyan-600 dark:text-cyan-400">+{{ getLevelData(level).buildSpeedBonus * 100 }}%</span>
</TableCell>
<TableCell v-if="type === 'building' && showResearchSpeedColumn" class="text-center text-sm">
<span class="text-indigo-600 dark:text-indigo-400">+{{ (getLevelData(level).researchSpeedBonus - 1) * 100 }}%</span>
</TableCell>
<!-- 科技相关数据 -->
<TableCell v-if="type === 'technology' && showAttackBonusColumn" class="text-center text-sm">
<span class="text-red-600 dark:text-red-400">+{{ level * 10 }}%</span>
</TableCell>
<TableCell v-if="type === 'technology' && showShieldBonusColumn" class="text-center text-sm">
<span class="text-blue-600 dark:text-blue-400">+{{ level * 10 }}%</span>
</TableCell>
<TableCell v-if="type === 'technology' && showArmorBonusColumn" class="text-center text-sm">
<span class="text-gray-600 dark:text-gray-400">+{{ level * 10 }}%</span>
</TableCell>
<TableCell v-if="type === 'technology' && showSpyLevelColumn" class="text-center text-sm">
<span class="text-purple-600 dark:text-purple-400">+{{ level }}</span>
</TableCell>
<TableCell v-if="type === 'technology' && showFleetStorageColumn" class="text-center text-sm">
<span class="text-blue-600 dark:text-blue-400">+<NumberWithTooltip :value="level * 500" /></span>
</TableCell>
<TableCell v-if="type === 'technology' && showResearchQueueColumn" class="text-center text-sm">
<span class="text-purple-600 dark:text-purple-400">+1</span>
</TableCell>
<TableCell v-if="type === 'technology' && showColonySlotsColumn" class="text-center text-sm">
<span class="text-green-600 dark:text-green-400">+1</span>
</TableCell>
<TableCell v-if="type === 'technology' && showSpaceColumn" class="text-center text-sm">
<span class="text-green-600 dark:text-green-400">+5 {{ t('research.forAllPlanets') }}</span>
</TableCell>
<TableCell v-if="type === 'technology' && showSpeedBonusColumn" class="text-center text-sm">
<span class="text-yellow-600 dark:text-yellow-400">+{{ level * 10 }}%</span>
</TableCell>
<TableCell v-if="type === 'technology' && showResearchSpeedColumn" class="text-center text-sm">
<span class="text-indigo-600 dark:text-indigo-400">+{{ getLevelData(level).researchSpeedBonus * 100 }}%</span>
</TableCell>
<TableCell class="text-center text-sm">
<span class="text-primary font-medium">
+
<NumberWithTooltip :value="getLevelData(level).points" />
</span>
</TableCell>
</TableRow>
</TableBody>
</Table>
</div>
<!-- 建筑/科技累积统计 -->
<div v-if="type === 'building' || type === 'technology'" class="grid grid-cols-2 gap-4">
<Card>
<CardHeader class="pb-3">
<CardTitle class="text-sm">{{ t(`${typeKey}.totalCost`) }}</CardTitle>
</CardHeader>
<CardContent class="space-y-2">
<div class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">{{ t('resources.metal') }}:</span>
<span class="font-medium"><NumberWithTooltip :value="totalStats.metal" /></span>
</div>
<div class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">{{ t('resources.crystal') }}:</span>
<span class="font-medium"><NumberWithTooltip :value="totalStats.crystal" /></span>
</div>
<div class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">{{ t('resources.deuterium') }}:</span>
<span class="font-medium"><NumberWithTooltip :value="totalStats.deuterium" /></span>
</div>
</CardContent>
</Card>
<Card>
<CardHeader class="pb-3">
<CardTitle class="text-sm">{{ t(`${typeKey}.totalPoints`) }}</CardTitle>
</CardHeader>
<CardContent>
<div class="text-3xl font-bold text-primary">
<NumberWithTooltip :value="totalStats.points" />
</div>
<p class="text-xs text-muted-foreground mt-1">
{{ t(`${typeKey}.levelRange`) }}: {{ Math.max(0, safeCurrentLevel - 10) }} - {{ safeCurrentLevel + 10 }}
</p>
</CardContent>
</Card>
</div>
<!-- 舰船/防御基础属性 -->
<div v-if="type === 'ship' || type === 'defense'" class="grid grid-cols-2 md:grid-cols-3 gap-4">
<Card>
<CardHeader class="pb-3">
<CardTitle class="text-sm flex items-center gap-2">
<Sword class="h-4 w-4" />
{{ t(`${typeKey}.attack`) }}
</CardTitle>
</CardHeader>
<CardContent>
<div class="text-2xl font-bold">
<NumberWithTooltip :value="combatUnitConfig?.attack || 0" />
</div>
</CardContent>
</Card>
<Card>
<CardHeader class="pb-3">
<CardTitle class="text-sm flex items-center gap-2">
<Shield class="h-4 w-4" />
{{ t(`${typeKey}.shield`) }}
</CardTitle>
</CardHeader>
<CardContent>
<div class="text-2xl font-bold">
<NumberWithTooltip :value="combatUnitConfig?.shield || 0" />
</div>
</CardContent>
</Card>
<Card>
<CardHeader class="pb-3">
<CardTitle class="text-sm flex items-center gap-2">
<ShieldCheck class="h-4 w-4" />
{{ t(`${typeKey}.armor`) }}
</CardTitle>
</CardHeader>
<CardContent>
<div class="text-2xl font-bold">
<NumberWithTooltip :value="combatUnitConfig?.armor || 0" />
</div>
</CardContent>
</Card>
<!-- 仅舰船显示 -->
<Card v-if="type === 'ship'">
<CardHeader class="pb-3">
<CardTitle class="text-sm flex items-center gap-2">
<Zap class="h-4 w-4" />
{{ t('shipyard.speed') }}
</CardTitle>
</CardHeader>
<CardContent>
<div class="text-2xl font-bold">
<NumberWithTooltip :value="shipConfig?.speed || 0" />
</div>
</CardContent>
</Card>
<Card v-if="type === 'ship'">
<CardHeader class="pb-3">
<CardTitle class="text-sm flex items-center gap-2">
<Package class="h-4 w-4" />
{{ t('shipyard.cargoCapacity') }}
</CardTitle>
</CardHeader>
<CardContent>
<div class="text-2xl font-bold">
<NumberWithTooltip :value="shipConfig?.cargoCapacity || 0" />
</div>
</CardContent>
</Card>
<Card v-if="type === 'ship'">
<CardHeader class="pb-3">
<CardTitle class="text-sm flex items-center gap-2">
<Fuel class="h-4 w-4" />
{{ t('shipyard.fuelConsumption') }}
</CardTitle>
</CardHeader>
<CardContent>
<div class="text-2xl font-bold">
<NumberWithTooltip :value="shipConfig?.fuelConsumption || 0" />
</div>
</CardContent>
</Card>
</div>
<!-- 舰船/防御建造成本和时间 -->
<div v-if="type === 'ship' || type === 'defense'" class="grid grid-cols-1 md:grid-cols-2 gap-4">
<Card>
<CardHeader>
<CardTitle class="text-sm">{{ t(`${typeKey}.buildCost`) }}</CardTitle>
</CardHeader>
<CardContent class="space-y-2">
<div v-for="resourceType in costResourceTypes" :key="resourceType.key" v-show="unitCost[resourceType.key] > 0" class="flex items-center justify-between text-sm">
<span class="text-muted-foreground">{{ t(`resources.${resourceType.key}`) }}:</span>
<span class="font-medium"><NumberWithTooltip :value="unitCost[resourceType.key]" /></span>
</div>
<div class="flex items-center justify-between text-sm pt-2 border-t">
<span class="text-muted-foreground">{{ t('player.points') }}:</span>
<span class="font-bold text-primary"><NumberWithTooltip :value="pointsPerUnit" /></span>
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle class="text-sm">{{ t(`${typeKey}.buildTime`) }}</CardTitle>
</CardHeader>
<CardContent>
<div class="text-3xl font-bold">{{ formatTime(unitBuildTime) }}</div>
<p class="text-xs text-muted-foreground mt-2">{{ t(`${typeKey}.perUnit`) }}</p>
</CardContent>
</Card>
</div>
<!-- 舰船/防御批量建造计算器 -->
<Card v-if="type === 'ship' || type === 'defense'">
<CardHeader>
<CardTitle class="text-sm">{{ t(`${typeKey}.batchCalculator`) }}</CardTitle>
</CardHeader>
<CardContent class="space-y-4">
<div class="flex items-center gap-4">
<Label class="w-20">{{ t(`${typeKey}.quantity`) }}:</Label>
<Input v-model.number="quantity" type="number" min="1" class="flex-1" />
</div>
<div class="grid grid-cols-2 gap-4 pt-4 border-t">
<div class="space-y-2">
<p class="text-sm text-muted-foreground">{{ t(`${typeKey}.totalCost`) }}:</p>
<div class="space-y-1 text-sm">
<div v-for="resourceType in costResourceTypes" :key="resourceType.key" class="flex justify-between">
<span>{{ t(`resources.${resourceType.key}`) }}:</span>
<span class="font-medium"><NumberWithTooltip :value="batchCost[resourceType.key]" /></span>
</div>
</div>
</div>
<div class="space-y-2">
<p class="text-sm text-muted-foreground">{{ t(`${typeKey}.totalTime`) }}:</p>
<div class="text-xl font-bold">{{ formatTime(unitBuildTime * quantity) }}</div>
<p class="text-xs text-muted-foreground">
{{ t('player.points') }}: +
<NumberWithTooltip :value="batchPoints" />
</p>
</div>
</div>
</CardContent>
</Card>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useI18n } from '@/composables/useI18n'
import { useGameStore } from '@/stores/gameStore'
import type { BuildingType, TechnologyType, ShipType, DefenseType } from '@/types/game'
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import NumberWithTooltip from '@/components/NumberWithTooltip.vue'
import { Sword, Shield, ShieldCheck, Zap, Package, Fuel } from 'lucide-vue-next'
import * as buildingLogic from '@/logic/buildingLogic'
import * as researchLogic from '@/logic/researchLogic'
import * as pointsLogic from '@/logic/pointsLogic'
import * as officerLogic from '@/logic/officerLogic'
import * as shipLogic from '@/logic/shipLogic'
import { SHIPS, DEFENSES } from '@/config/gameConfig'
import { formatTime } from '@/utils/format'
const { t } = useI18n()
const gameStore = useGameStore()
const props = defineProps<{
type: 'building' | 'technology' | 'ship' | 'defense'
itemType: BuildingType | TechnologyType | ShipType | DefenseType
currentLevel?: number
}>()
const quantity = ref(1)
// 资源类型配置(用于成本显示)
const costResourceTypes = [{ key: 'metal' as const }, { key: 'crystal' as const }, { key: 'deuterium' as const }]
// 获取当前星球
const currentPlanet = computed(() => gameStore.currentPlanet)
// 计算当前加成
const activeBonuses = computed(() => {
return officerLogic.calculateActiveBonuses(gameStore.player.officers, gameStore.gameTime)
})
// 获取工厂等级(用于建造时间计算)
const roboticsFactoryLevel = computed(() => {
if (!currentPlanet.value) return 0
return currentPlanet.value.buildings['roboticsFactory'] || 0
})
const naniteFactoryLevel = computed(() => {
if (!currentPlanet.value) return 0
return currentPlanet.value.buildings['naniteFactory'] || 0
})
// 获取研究所等级(用于研究时间计算)
const researchLabLevel = computed(() => {
if (!currentPlanet.value) return 0
return currentPlanet.value.buildings['researchLab'] || 0
})
// 翻译键(转换为复数形式)
const typeKey = computed(() => {
const typeMap = {
building: 'buildings',
technology: 'research',
ship: 'shipyard',
defense: 'defense'
} as const
return typeMap[props.type]
})
// 控制建筑列显示
const showDarkMatterColumn = computed(() => {
if (props.type === 'building') {
const buildingType = props.itemType as BuildingType
return buildingType === 'darkMatterCollector'
} else if (props.type === 'technology') {
const techType = props.itemType as TechnologyType
return techType === 'gravitonTechnology'
}
return false
})
const showProductionColumn = computed(() => {
if (props.type !== 'building') return false
const buildingType = props.itemType as BuildingType
return ['metalMine', 'crystalMine', 'deuteriumSynthesizer', 'solarPlant', 'fusionReactor', 'darkMatterCollector'].includes(buildingType)
})
const showConsumptionColumn = computed(() => {
if (props.type !== 'building') return false
const buildingType = props.itemType as BuildingType
return ['metalMine', 'crystalMine', 'deuteriumSynthesizer'].includes(buildingType)
})
const showCapacityColumn = computed(() => {
if (props.type !== 'building') return false
const buildingType = props.itemType as BuildingType
return ['metalStorage', 'crystalStorage', 'deuteriumTank', 'darkMatterCollector', 'darkMatterTank'].includes(buildingType)
})
const showFleetStorageColumn = computed(() => {
if (props.type === 'building') {
const buildingType = props.itemType as BuildingType
return buildingType === 'shipyard'
} else if (props.type === 'technology') {
const techType = props.itemType as TechnologyType
return techType === 'computerTechnology'
}
return false
})
const showBuildQueueColumn = computed(() => {
if (props.type !== 'building') return false
const buildingType = props.itemType as BuildingType
return buildingType === 'naniteFactory'
})
const showSpaceColumn = computed(() => {
if (props.type === 'building') {
const buildingType = props.itemType as BuildingType
return ['terraformer', 'lunarBase'].includes(buildingType)
} else if (props.type === 'technology') {
const techType = props.itemType as TechnologyType
return techType === 'terraformingTechnology'
}
return false
})
const showMissileColumn = computed(() => {
if (props.type !== 'building') return false
const buildingType = props.itemType as BuildingType
return buildingType === 'missileSilo'
})
const showBuildSpeedColumn = computed(() => {
if (props.type !== 'building') return false
const buildingType = props.itemType as BuildingType
return ['roboticsFactory', 'naniteFactory'].includes(buildingType)
})
const showResearchSpeedColumn = computed(() => {
if (props.type === 'building') {
const buildingType = props.itemType as BuildingType
return buildingType === 'researchLab'
} else if (props.type === 'technology') {
const techType = props.itemType as TechnologyType
return techType === 'energyTechnology'
}
return false
})
// 控制科技列显示
const showAttackBonusColumn = computed(() => {
if (props.type !== 'technology') return false
const techType = props.itemType as TechnologyType
return techType === 'weaponsTechnology'
})
const showShieldBonusColumn = computed(() => {
if (props.type !== 'technology') return false
const techType = props.itemType as TechnologyType
return techType === 'shieldingTechnology'
})
const showArmorBonusColumn = computed(() => {
if (props.type !== 'technology') return false
const techType = props.itemType as TechnologyType
return techType === 'armourTechnology'
})
const showSpyLevelColumn = computed(() => {
if (props.type !== 'technology') return false
const techType = props.itemType as TechnologyType
return techType === 'espionageTechnology'
})
const showResearchQueueColumn = computed(() => {
if (props.type !== 'technology') return false
const techType = props.itemType as TechnologyType
return techType === 'computerTechnology'
})
const showColonySlotsColumn = computed(() => {
if (props.type !== 'technology') return false
const techType = props.itemType as TechnologyType
return techType === 'astrophysics'
})
const showSpeedBonusColumn = computed(() => {
if (props.type !== 'technology') return false
const techType = props.itemType as TechnologyType
return ['combustionDrive', 'impulseDrive', 'hyperspaceDrive'].includes(techType)
})
// 安全的当前等级防止undefined
const safeCurrentLevel = computed(() => props.currentLevel ?? 0)
// 类型安全:战斗单位配置(舰船/防御)
const combatUnitConfig = computed(() => {
if (props.type === 'ship') return SHIPS[props.itemType as ShipType]
if (props.type === 'defense') return DEFENSES[props.itemType as DefenseType]
return null
})
// 类型安全:舰船配置
const shipConfig = computed(() => {
if (props.type === 'ship') return SHIPS[props.itemType as ShipType]
return null
})
// 类型安全单位成本处理cost vs baseCost差异
const unitCost = computed(() => {
if (props.type === 'ship') return SHIPS[props.itemType as ShipType].cost
if (props.type === 'defense') return DEFENSES[props.itemType as DefenseType].cost
return { metal: 0, crystal: 0, deuterium: 0 }
})
// 类型安全单位建造时间处理buildTime vs baseTime差异应用加成
const unitBuildTime = computed(() => {
if (props.type === 'ship') {
return shipLogic.calculateShipBuildTime(
props.itemType as ShipType,
1, // 单个单位
activeBonuses.value.buildingSpeedBonus,
roboticsFactoryLevel.value,
naniteFactoryLevel.value
)
}
if (props.type === 'defense') {
return shipLogic.calculateDefenseBuildTime(
props.itemType as DefenseType,
1, // 单个单位
activeBonuses.value.buildingSpeedBonus,
roboticsFactoryLevel.value,
naniteFactoryLevel.value
)
}
return 0
})
// 建筑/科技:等级范围
const levelRange = computed(() => {
if (props.type !== 'building' && props.type !== 'technology') return []
const current = props.currentLevel || 0
const levels = []
for (let i = current; i <= current + 10; i++) {
levels.push(i)
}
return levels
})
// 建筑/科技:获取某个等级的数据
const getLevelData = (level: number) => {
if (level === 0) {
return {
cost: { metal: 0, crystal: 0, deuterium: 0, darkMatter: 0 },
time: 0,
production: 0,
consumption: 0,
points: 0,
capacity: 0,
fleetStorage: 0,
spaceBonus: 0,
buildSpeedBonus: 0,
researchSpeedBonus: 0
}
}
if (props.type === 'building') {
const buildingType = props.itemType as BuildingType
const cost = buildingLogic.calculateBuildingCost(buildingType, level)
// 使用实际的工厂等级和加成计算建造时间
const time = buildingLogic.calculateBuildingTime(
buildingType,
level,
activeBonuses.value.buildingSpeedBonus,
roboticsFactoryLevel.value,
naniteFactoryLevel.value
)
let production = 0
let consumption = 0
let capacity = 0
let fleetStorage = 0
let spaceBonus = 0
let buildSpeedBonus = 0
let researchSpeedBonus = 0
// 应用资源产量加成
const resourceBonus = 1 + (activeBonuses.value.resourceProductionBonus || 0) / 100
const energyBonus = 1 + (activeBonuses.value.energyProductionBonus || 0) / 100
const storageBonus = 1 + (activeBonuses.value.storageCapacityBonus || 0) / 100
const baseCapacity = 10000
if (buildingType === 'metalMine') {
production = Math.floor(1500 * level * Math.pow(1.5, level) * resourceBonus)
consumption = Math.floor(10 * level * Math.pow(1.1, level))
} else if (buildingType === 'crystalMine') {
production = Math.floor(1000 * level * Math.pow(1.5, level) * resourceBonus)
consumption = Math.floor(10 * level * Math.pow(1.1, level))
} else if (buildingType === 'deuteriumSynthesizer') {
production = Math.floor(500 * level * Math.pow(1.5, level) * resourceBonus)
consumption = Math.floor(10 * level * Math.pow(1.1, level))
} else if (buildingType === 'solarPlant') {
production = Math.floor(50 * level * Math.pow(1.1, level) * energyBonus)
} else if (buildingType === 'metalStorage') {
capacity = Math.floor(baseCapacity * Math.pow(2, level) * storageBonus)
} else if (buildingType === 'crystalStorage') {
capacity = Math.floor(baseCapacity * Math.pow(2, level) * storageBonus)
} else if (buildingType === 'deuteriumTank') {
capacity = Math.floor(baseCapacity * Math.pow(2, level) * storageBonus)
} else if (buildingType === 'darkMatterCollector') {
capacity = 1000 + level * 100
production = Math.floor(25 * level * Math.pow(1.5, level))
} else if (buildingType === 'darkMatterTank') {
const darkMatterBaseCapacity = 1000
capacity = Math.floor(darkMatterBaseCapacity * Math.pow(2, level) * storageBonus)
} else if (buildingType === 'fusionReactor') {
production = Math.floor(150 * level * Math.pow(1.15, level))
} else if (buildingType === 'shipyard') {
fleetStorage = 1000 * level
} else if (buildingType === 'terraformer') {
spaceBonus = 5
} else if (buildingType === 'lunarBase') {
spaceBonus = 5
} else if (buildingType === 'roboticsFactory') {
buildSpeedBonus = level
} else if (buildingType === 'naniteFactory') {
buildSpeedBonus = level * 2
} else if (buildingType === 'researchLab') {
researchSpeedBonus = level
}
const points = pointsLogic.calculateBuildingPoints(buildingType, level - 1, level)
return { cost, time, production, consumption, points, capacity, fleetStorage, spaceBonus, buildSpeedBonus, researchSpeedBonus }
} else {
const techType = props.itemType as TechnologyType
const cost = researchLogic.calculateTechnologyCost(techType, level)
// 使用实际的研究所等级和加成计算研究时间
const time = researchLogic.calculateTechnologyTime(
techType,
level - 1,
activeBonuses.value.researchSpeedBonus,
researchLabLevel.value
)
let researchSpeedBonus = 0
if (techType === 'energyTechnology') {
researchSpeedBonus = level
}
const points = pointsLogic.calculateTechnologyPoints(techType, level - 1, level)
return { cost, time, production: 0, consumption: 0, points, capacity: 0, fleetStorage: 0, spaceBonus: 0, buildSpeedBonus: 0, researchSpeedBonus }
}
}
// 建筑/科技:累积统计
const totalStats = computed(() => {
if (props.type !== 'building' && props.type !== 'technology') {
return { metal: 0, crystal: 0, deuterium: 0, points: 0 }
}
let metal = 0,
crystal = 0,
deuterium = 0,
points = 0
for (const level of levelRange.value) {
if (level === 0) continue
const data = getLevelData(level)
metal += data.cost.metal
crystal += data.cost.crystal
deuterium += data.cost.deuterium
points += data.points
}
return { metal, crystal, deuterium, points }
})
// 舰船/防御:单位积分
const pointsPerUnit = computed(() => {
if (props.type === 'ship') return pointsLogic.calculateShipPoints(props.itemType as ShipType, 1)
if (props.type === 'defense') return pointsLogic.calculateDefensePoints(props.itemType as DefenseType, 1)
return 0
})
// 舰船/防御:批量成本
const batchCost = computed(() => ({
metal: unitCost.value.metal * quantity.value,
crystal: unitCost.value.crystal * quantity.value,
deuterium: unitCost.value.deuterium * quantity.value
}))
// 舰船/防御:批量积分
const batchPoints = computed(() => {
if (props.type === 'ship') return pointsLogic.calculateShipPoints(props.itemType as ShipType, quantity.value)
if (props.type === 'defense') return pointsLogic.calculateDefensePoints(props.itemType as DefenseType, quantity.value)
return 0
})
</script>