From 9e7560cc4b722e602fff4de2e35e15e8379413fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=A6=E5=90=9B?= <73606411+setube@users.noreply.github.com> Date: Tue, 6 Jan 2026 03:00:02 +0800 Subject: [PATCH] =?UTF-8?q?1.6.0=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- capacitor.config.ts | 18 +- main.go | 75 ++++++- package.json | 9 +- pnpm-lock.yaml | 41 ++++ src/App.vue | 87 ++++++-- src/assets/main.css | 6 +- src/components/campaign/QuestMap.vue | 2 +- src/components/campaign/QuestNode.vue | 2 +- src/components/common/ItemDetailView.vue | 23 ++- .../dialogs/BattleAnimationPlayer.vue | 176 ++++++++-------- src/components/ui/progress/Progress.vue | 2 +- src/composables/useGameConfig.ts | 9 +- src/composables/useQueueAnimation.ts | 2 +- src/config/gameConfig.ts | 149 +++++++++++++- src/locales/de.ts | 156 +++++++++++---- src/locales/en.ts | 89 +++++++-- src/locales/es-LA.ts | 66 ++++-- src/locales/ja.ts | 80 ++++++-- src/locales/ko.ts | 78 ++++++-- src/locales/ru.ts | 76 +++++-- src/locales/zh-CN.ts | 121 ++++++++--- src/locales/zh-TW.ts | 66 ++++-- src/logic/battleLogic.ts | 5 +- src/logic/buildingLogic.ts | 45 ++++- src/logic/fleetLogic.ts | 188 ++++++++++++++++-- src/logic/gameLogic.ts | 18 +- src/logic/npcBehaviorLogic.ts | 116 +++++++++-- src/logic/oreDepositLogic.ts | 56 ++++-- src/logic/planetLogic.ts | 60 ++++++ src/logic/publicLogic.ts | 17 +- src/logic/researchLogic.ts | 92 ++++++++- src/logic/researchValidation.ts | 30 ++- src/logic/resourceLogic.ts | 146 ++++++++++++-- src/logic/shipLogic.ts | 46 +++++ src/logic/shipValidation.ts | 63 ++++++ src/stores/gameStore.ts | 1 + src/style.css | 6 +- src/types/game.ts | 17 +- src/utils/battleSimulator.ts | 35 +++- src/views/BattleSimulatorView.vue | 136 ++++++++++++- src/views/FleetView.vue | 74 ++++++- src/views/GalaxyView.vue | 4 +- src/views/HomeView.vue | 4 +- src/views/OverviewView.vue | 106 +++++++++- src/views/ResearchView.vue | 29 ++- src/views/SettingsView.vue | 25 ++- src/views/ShipyardView.vue | 113 +++++++++++ src/workers/battle.worker.ts | 20 +- vite.config.ts | 29 +-- 调整基础矿脉恢复速度.ini | 28 +++ 50 files changed, 2374 insertions(+), 468 deletions(-) create mode 100644 调整基础矿脉恢复速度.ini diff --git a/capacitor.config.ts b/capacitor.config.ts index 0390b89..682c90e 100644 --- a/capacitor.config.ts +++ b/capacitor.config.ts @@ -4,25 +4,15 @@ const config: CapacitorConfig = { appId: 'games.wenzi.ogame', appName: 'OGame Vue Ts', webDir: 'docs', - server: { - androidScheme: 'https', - cacheControl: 'max-age=31536000' - }, + server: { androidScheme: 'https', cacheControl: 'max-age=31536000' }, android: { - buildOptions: { - keystorePath: undefined, - keystoreAlias: undefined - }, + buildOptions: { keystorePath: undefined, keystoreAlias: undefined }, webContentsDebuggingEnabled: false, allowMixedContent: false, hardwareAcceleration: true }, - plugins: { - // 禁用键盘自动调整视口 - Keyboard: { - resize: 'none' - } - } + // 禁用键盘自动调整视口 + plugins: { Keyboard: { resize: 'none' } } } export default config diff --git a/main.go b/main.go index ce68552..64be79e 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import ( + "bufio" "embed" "flag" "fmt" @@ -10,6 +11,7 @@ import ( "os" "os/exec" "runtime" + "strconv" "strings" "time" ) @@ -20,10 +22,16 @@ var content embed.FS func main() { // --- 1. 命令行参数配置 --- - // 定义 -port 参数,默认为 0(自动分配) - portPtr := flag.Int("port", 0, "指定运行端口 (例如: 8080),不指定则自动分配可用端口") + // 定义 -port 参数,默认为 -1(表示未指定,需要交互选择) + portPtr := flag.Int("port", -1, "指定运行端口 (例如: 8080),不指定则显示交互菜单") flag.Parse() + // 如果没有通过命令行指定端口,显示交互式菜单 + port := *portPtr + if port == -1 { + port = showPortMenu() + } + // --- 2. 静态资源处理 --- // 获取 docs 子目录的文件系统句柄 distFS, err := fs.Sub(content, "docs") @@ -60,10 +68,10 @@ func main() { }) // --- 3. 端口监听逻辑 --- - addr := fmt.Sprintf("0.0.0.0:%d", *portPtr) + addr := fmt.Sprintf("0.0.0.0:%d", port) listener, err := net.Listen("tcp", addr) if err != nil { - fmt.Printf("错误: 端口 %d 已被占用或监听失败: %v\n", *portPtr, err) + fmt.Printf("错误: 端口 %d 已被占用或监听失败: %v\n", port, err) // 停留 5 秒让用户看到错误信息 time.Sleep(5 * time.Second) os.Exit(1) @@ -79,8 +87,8 @@ func main() { fmt.Printf("启动时间: %s\n", time.Now().Format("2006-01-02 15:04:05")) fmt.Printf("本地访问: %s\n", localUrl) fmt.Printf("局域网访问: %s\n", lanUrl) - if *portPtr != 0 { - fmt.Printf("运行模式: 固定端口 (%d)\n", *portPtr) + if port != 0 { + fmt.Printf("运行模式: 固定端口 (%d)\n", port) } else { fmt.Printf("运行模式: 自动分配端口\n") } @@ -131,4 +139,59 @@ func openBrowser(url string) { } _ = exec.Command(cmd, args...).Start() +} + +// 显示端口选择菜单 +func showPortMenu() int { + reader := bufio.NewReader(os.Stdin) + + fmt.Println("=======================================") + fmt.Println(" OGame Vue Ts 服务器启动") + fmt.Println("=======================================") + fmt.Println() + fmt.Println("请选择端口模式:") + fmt.Println(" [1] 随机端口 (自动分配可用端口)") + fmt.Println(" [2] 自定义端口 (指定固定端口)") + fmt.Println() + fmt.Print("请输入选项 (1/2): ") + + for { + input, _ := reader.ReadString('\n') + input = strings.TrimSpace(input) + + switch input { + case "1", "": + fmt.Println("\n已选择: 随机端口模式") + return 0 + case "2": + return inputCustomPort(reader) + default: + fmt.Print("无效输入,请输入 1 或 2: ") + } + } +} + +// 输入自定义端口 +func inputCustomPort(reader *bufio.Reader) int { + fmt.Print("请输入端口号 (1-65535,推荐: 8080): ") + + for { + input, _ := reader.ReadString('\n') + input = strings.TrimSpace(input) + + // 如果直接回车,使用默认端口 8080 + if input == "" { + fmt.Println("\n已选择: 固定端口 8080") + return 8080 + } + + port, err := strconv.Atoi(input) + if err != nil || port < 1 || port > 65535 { + fmt.Print("无效端口号,请输入 1-65535 之间的数字: ") + continue + } + + fmt.Printf("\n已选择: 固定端口 %d\n", port) + return port + } } \ No newline at end of file diff --git a/package.json b/package.json index d9a6b69..9d3a867 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ "email": "1962257451@qq.com" }, "private": true, - "version": "1.5.6", - "buildDate": "2025/12/27 03:58:44", + "version": "1.6.0", + "buildDate": "2026/1/6 02:54:44", "main": "dist-electron/main.js", "type": "module", "scripts": { @@ -34,6 +34,7 @@ "crypto-js": "^4.2.0", "file-saver": "^2.0.5", "finalhandler": "^2.1.1", + "lightningcss": "^1.30.2", "lucide-vue-next": "^0.556.0", "marked": "^17.0.1", "motion-v": "^1.7.4", @@ -44,10 +45,10 @@ "tailwindcss": "^4.1.17", "vue": "^3.5.24", "vue-router": "4", - "vue-sonner": "^2.0.9", - "lightningcss": "^1.30.2" + "vue-sonner": "^2.0.9" }, "devDependencies": { + "@csstools/postcss-cascade-layers": "^5.0.2", "@types/crypto-js": "^4.2.2", "@types/file-saver": "^2.0.7", "@types/node": "^24.10.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f09fd33..7282853 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -81,6 +81,9 @@ importers: specifier: ^2.0.9 version: 2.0.9 devDependencies: + '@csstools/postcss-cascade-layers': + specifier: ^5.0.2 + version: 5.0.2(postcss@8.5.6) '@types/crypto-js': specifier: ^4.2.2 version: 4.2.2 @@ -674,6 +677,18 @@ packages: '@capacitor/synapse@1.0.4': resolution: {integrity: sha512-/C1FUo8/OkKuAT4nCIu/34ny9siNHr9qtFezu4kxm6GY1wNFxrCFWjfYx5C1tUhVGz3fxBABegupkpjXvjCHrw==} + '@csstools/postcss-cascade-layers@5.0.2': + resolution: {integrity: sha512-nWBE08nhO8uWl6kSAeCx4im7QfVko3zLrtgWZY4/bP87zrSPpSyN/3W3TDqz1jJuH+kbKOHXg5rJnK+ZVYcFFg==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/selector-specificity@5.0.0': + resolution: {integrity: sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==} + engines: {node: '>=18'} + peerDependencies: + postcss-selector-parser: ^7.0.0 + '@develar/schema-utils@2.6.5': resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==} engines: {node: '>= 8.9.0'} @@ -1915,6 +1930,11 @@ packages: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -3104,6 +3124,10 @@ packages: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + engines: {node: '>=4'} + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -4646,6 +4670,16 @@ snapshots: '@capacitor/synapse@1.0.4': {} + '@csstools/postcss-cascade-layers@5.0.2(postcss@8.5.6)': + dependencies: + '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + '@csstools/selector-specificity@5.0.0(postcss-selector-parser@7.1.1)': + dependencies: + postcss-selector-parser: 7.1.1 + '@develar/schema-utils@2.6.5': dependencies: ajv: 6.12.6 @@ -5955,6 +5989,8 @@ snapshots: crypto-random-string@2.0.0: {} + cssesc@3.0.0: {} + csstype@3.2.3: {} data-view-buffer@1.0.2: @@ -7243,6 +7279,11 @@ snapshots: possible-typed-array-names@1.1.0: {} + postcss-selector-parser@7.1.1: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + postcss@8.5.6: dependencies: nanoid: 3.3.11 diff --git a/src/App.vue b/src/App.vue index 8e6a607..323ed28 100644 --- a/src/App.vue +++ b/src/App.vue @@ -45,7 +45,7 @@ - +
{{ t('planet.switchPlanet') }} @@ -378,7 +378,7 @@ -
+
@@ -518,7 +518,7 @@ import HintToast from '@/components/notifications/HintToast.vue' import BackToTop from '@/components/common/BackToTop.vue' import Sonner from '@/components/ui/sonner/Sonner.vue' - import { MissionType, BuildingType, TechnologyType, DiplomaticEventType } 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' @@ -838,8 +838,14 @@ // 计算离线收益(直接同步计算,应用游戏速度) const bonuses = officerLogic.calculateActiveBonuses(gameStore.player.officers, now) + const miningTechLevel = gameStore.player.technologies[TechnologyType.MiningTechnology] || 0 + const techBonuses = { + mineralResearchLevel: gameStore.player.technologies[TechnologyType.MineralResearch] || 0, + crystalResearchLevel: gameStore.player.technologies[TechnologyType.CrystalResearch] || 0, + fuelResearchLevel: gameStore.player.technologies[TechnologyType.FuelResearch] || 0 + } gameStore.player.planets.forEach(planet => { - resourceLogic.updatePlanetResources(planet, now, bonuses, gameStore.gameSpeed) + resourceLogic.updatePlanetResources(planet, now, bonuses, gameStore.gameSpeed, miningTechLevel, techBonuses) }) // 只在没有NPC星球时才生成(首次加载已有玩家数据时) @@ -1065,6 +1071,19 @@ 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 } + } } } @@ -1262,8 +1281,41 @@ } } } else if (mission.missionType === MissionType.Destroy) { - // 处理行星毁灭任务 - const destroyResult = fleetLogic.processDestroyArrival(mission, targetPlanet, gameStore.player) + // 处理行星毁灭任务(需要先战斗,再计算毁灭概率) + 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) { @@ -1303,12 +1355,14 @@ ? { destroyedPlanetName: targetPlanet?.name || - `[${mission.targetPosition.galaxy}:${mission.targetPosition.system}:${mission.targetPosition.position}]` + `[${mission.targetPosition.galaxy}:${mission.targetPosition.system}:${mission.targetPosition.position}]`, + hadBattle: !!destroyResult.battleResult } : { failReason: destroyResult.failReason, destructionChance: destroyResult.destructionChance, - deathstarsLost: destroyResult.deathstarsLost + deathstarsLost: destroyResult.deathstarsLost, + hadBattle: !!destroyResult.battleResult }, read: false }) @@ -1387,7 +1441,7 @@ delete universeStore.debrisFields[destroyedDebrisId] } } else if (mission.missionType === MissionType.Expedition) { - // 处理远征任务 + // 处理探险任务 const expeditionResult = fleetLogic.processExpeditionArrival(mission) // 确保返回时间正确设置(兼容旧版本任务数据) @@ -1399,12 +1453,12 @@ 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 = [] } @@ -1676,10 +1730,16 @@ // 应用损失到目标星球 missileLogic.applyMissileAttackResult(targetPlanet, impactResult.defenseLosses) - // 如果目标是NPC的星球,扣除外交好感度 + // 如果目标是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 // 导弹攻击的好感度惩罚是普通攻击的一半 @@ -2220,6 +2280,7 @@ const switchToMoon = () => { if (moon.value) { gameStore.currentPlanetId = moon.value.id + router.push('/') } } @@ -2227,12 +2288,14 @@ const switchToParentPlanet = () => { if (planet.value?.parentPlanetId) { gameStore.currentPlanetId = planet.value.parentPlanetId + router.push('/') } } // 切换到指定星球 const switchToPlanet = (planetId: string) => { gameStore.currentPlanetId = planetId + router.push('/') } // 切换侧边栏 diff --git a/src/assets/main.css b/src/assets/main.css index 48c14f6..d9c4528 100644 --- a/src/assets/main.css +++ b/src/assets/main.css @@ -72,15 +72,15 @@ html.light { /* 队列添加动画 - 脉冲效果 */ @keyframes queue-pulse-animation { 0% { - transform: scale(1); + transform: scale3d(1, 1, 1); box-shadow: 0 0 0 0 rgba(34, 197, 94, 0.7); } 50% { - transform: scale(1.1); + transform: scale3d(1.1, 1.1, 1); box-shadow: 0 0 0 8px rgba(34, 197, 94, 0); } 100% { - transform: scale(1); + transform: scale3d(1, 1, 1); box-shadow: 0 0 0 0 rgba(34, 197, 94, 0); } } diff --git a/src/components/campaign/QuestMap.vue b/src/components/campaign/QuestMap.vue index 0de0d1d..05a5ab2 100644 --- a/src/components/campaign/QuestMap.vue +++ b/src/components/campaign/QuestMap.vue @@ -9,7 +9,7 @@
{ if (!currentPlanet.value) return 0 + const intergalacticResearchNetworkLevel = gameStore.player.technologies[TechnologyType.IntergalacticResearchNetwork] || 0 + + // 如果有星际研究网络,计算有效实验室等级 + if (intergalacticResearchNetworkLevel > 0) { + return researchLogic.calculateEffectiveLabLevel( + gameStore.player.planets, + currentPlanet.value.id, + intergalacticResearchNetworkLevel + ) + } + return currentPlanet.value.buildings['researchLab'] || 0 }) @@ -502,6 +513,12 @@ return gameStore.player.technologies['energyTechnology'] || 0 }) + // 获取大学等级(用于研究时间计算) + const universityLevel = computed(() => { + if (!currentPlanet.value) return 0 + return currentPlanet.value.buildings['university'] || 0 + }) + // 翻译键(转换为复数形式) const typeKey = computed(() => { const typeMap = { @@ -931,7 +948,9 @@ level - 1, activeBonuses.value.researchSpeedBonus, researchLabLevel.value, - energyTechLevel.value + energyTechLevel.value, + 1, + universityLevel.value ) let researchSpeedBonus = 0 diff --git a/src/components/dialogs/BattleAnimationPlayer.vue b/src/components/dialogs/BattleAnimationPlayer.vue index 026e3a3..4337cfa 100644 --- a/src/components/dialogs/BattleAnimationPlayer.vue +++ b/src/components/dialogs/BattleAnimationPlayer.vue @@ -178,6 +178,16 @@ type: 'attacker-loss' | 'defender-loss' | 'info' } const battleLogs = ref([]) + const MAX_LOGS = 100 // 限制日志数量,防止100回合战斗导致性能问题 + + // 添加日志的辅助函数,自动限制数量 + const addBattleLog = (log: BattleLog) => { + battleLogs.value.push(log) + // 如果超过最大数量,删除最旧的日志 + if (battleLogs.value.length > MAX_LOGS) { + battleLogs.value = battleLogs.value.slice(-MAX_LOGS) + } + } // 计算属性 const totalRounds = computed(() => props.report.roundDetails?.length || props.report.rounds || 1) @@ -367,97 +377,101 @@ if (currentRoundIndex.value >= totalRounds.value) return isPlayingRound = true - const speed = parseFloat(speedMultiplier.value) - const roundIndex = currentRoundIndex.value - const roundData = props.report.roundDetails?.[roundIndex] + try { + const speed = parseFloat(speedMultiplier.value) || 1 + const roundIndex = currentRoundIndex.value + const roundData = props.report.roundDetails?.[roundIndex] - // 攻击动画阶段 - attackAnimationPhase.value = 'attack' + // 攻击动画阶段 + attackAnimationPhase.value = 'attack' - // 添加日志 - battleLogs.value.push({ - round: roundIndex + 1, - message: t('messagesView.roundStarted').replace('{round}', String(roundIndex + 1)), - type: 'info' - }) + // 添加日志 + addBattleLog({ + round: roundIndex + 1, + message: t('messagesView.roundStarted').replace('{round}', String(roundIndex + 1)), + type: 'info' + }) - // 等待攻击动画 - await sleep(400 / speed) + // 等待攻击动画 + await sleep(400 / speed) - // 伤害阶段 - attackAnimationPhase.value = 'damage' + // 伤害阶段 + attackAnimationPhase.value = 'damage' - // 计算当前回合的损失数字 - if (roundData) { - const attackerLoss = Object.values(roundData.attackerLosses).reduce((sum, count) => sum + count, 0) - const defenderLoss = - Object.values(roundData.defenderLosses.fleet || {}).reduce((sum, count) => sum + count, 0) + - Object.values(roundData.defenderLosses.defense || {}).reduce((sum, count) => sum + count, 0) - displayedLosses.value = { attacker: attackerLoss, defender: defenderLoss } - } else { - displayedLosses.value = { attacker: 0, defender: 0 } + // 计算当前回合的损失数字 + if (roundData) { + const attackerLoss = Object.values(roundData.attackerLosses || {}).reduce((sum, count) => sum + count, 0) + const defenderLoss = + Object.values(roundData.defenderLosses?.fleet || {}).reduce((sum, count) => sum + count, 0) + + Object.values(roundData.defenderLosses?.defense || {}).reduce((sum, count) => sum + count, 0) + displayedLosses.value = { attacker: attackerLoss, defender: defenderLoss } + } else { + displayedLosses.value = { attacker: 0, defender: 0 } + } + showDamageNumbers.value = true + + if (roundData) { + // 记录攻击方损失 + for (const [shipType, count] of Object.entries(roundData.attackerLosses || {})) { + if (count > 0) { + explodingShips.value.push({ side: 'attacker', type: shipType }) + addBattleLog({ + round: roundIndex + 1, + message: t('messagesView.shipDestroyed') + .replace('{count}', String(count)) + .replace('{ship}', SHIPS.value[shipType as ShipType]?.name || shipType), + type: 'attacker-loss' + }) + } + } + + // 记录防守方损失 + for (const [shipType, count] of Object.entries(roundData.defenderLosses?.fleet || {})) { + if (count > 0) { + explodingShips.value.push({ side: 'defender', type: shipType }) + addBattleLog({ + round: roundIndex + 1, + message: t('messagesView.shipDestroyed') + .replace('{count}', String(count)) + .replace('{ship}', SHIPS.value[shipType as ShipType]?.name || shipType), + type: 'defender-loss' + }) + } + } + + for (const [defType, count] of Object.entries(roundData.defenderLosses?.defense || {})) { + if (count > 0) { + explodingShips.value.push({ side: 'defender', type: defType }) + addBattleLog({ + round: roundIndex + 1, + message: t('messagesView.defenseDestroyed') + .replace('{count}', String(count)) + .replace('{defense}', DEFENSES.value[defType as DefenseType]?.name || defType), + type: 'defender-loss' + }) + } + } + } + + // 等待伤害显示 + await sleep(600 / speed) + + // 清理状态 + attackAnimationPhase.value = 'idle' + showDamageNumbers.value = false + explodingShips.value = [] + + currentRoundIndex.value++ + } finally { + // 确保锁始终被释放,即使发生错误 + isPlayingRound = false } - showDamageNumbers.value = true - - if (roundData) { - // 记录攻击方损失 - for (const [shipType, count] of Object.entries(roundData.attackerLosses)) { - if (count > 0) { - explodingShips.value.push({ side: 'attacker', type: shipType }) - battleLogs.value.push({ - round: roundIndex + 1, - message: t('messagesView.shipDestroyed') - .replace('{count}', String(count)) - .replace('{ship}', SHIPS.value[shipType as ShipType]?.name || shipType), - type: 'attacker-loss' - }) - } - } - - // 记录防守方损失 - for (const [shipType, count] of Object.entries(roundData.defenderLosses.fleet || {})) { - if (count > 0) { - explodingShips.value.push({ side: 'defender', type: shipType }) - battleLogs.value.push({ - round: roundIndex + 1, - message: t('messagesView.shipDestroyed') - .replace('{count}', String(count)) - .replace('{ship}', SHIPS.value[shipType as ShipType]?.name || shipType), - type: 'defender-loss' - }) - } - } - - for (const [defType, count] of Object.entries(roundData.defenderLosses.defense || {})) { - if (count > 0) { - explodingShips.value.push({ side: 'defender', type: defType }) - battleLogs.value.push({ - round: roundIndex + 1, - message: t('messagesView.defenseDestroyed') - .replace('{count}', String(count)) - .replace('{defense}', DEFENSES.value[defType as DefenseType]?.name || defType), - type: 'defender-loss' - }) - } - } - } - - // 等待伤害显示 - await sleep(600 / speed) - - // 清理状态 - attackAnimationPhase.value = 'idle' - showDamageNumbers.value = false - explodingShips.value = [] - - currentRoundIndex.value++ - isPlayingRound = false } - const nextRound = () => { + const nextRound = async () => { if (currentRoundIndex.value < totalRounds.value) { pause() - playRound() + await playRound() } } diff --git a/src/components/ui/progress/Progress.vue b/src/components/ui/progress/Progress.vue index 8e43493..efee3c9 100644 --- a/src/components/ui/progress/Progress.vue +++ b/src/components/ui/progress/Progress.vue @@ -7,7 +7,7 @@ diff --git a/src/composables/useGameConfig.ts b/src/composables/useGameConfig.ts index e6fcb6c..f558a9e 100644 --- a/src/composables/useGameConfig.ts +++ b/src/composables/useGameConfig.ts @@ -43,7 +43,8 @@ export const useGameConfig = () => { [BuildingType.JumpGate]: 'jumpGate', [BuildingType.PlanetDestroyerFactory]: 'planetDestroyerFactory', [BuildingType.GeoResearchStation]: 'geoResearchStation', - [BuildingType.DeepDrillingFacility]: 'deepDrillingFacility' + [BuildingType.DeepDrillingFacility]: 'deepDrillingFacility', + [BuildingType.University]: 'university' } // 舰船类型枚举值到翻译键的映射 @@ -100,7 +101,11 @@ export const useGameConfig = () => { [TechnologyType.DarkMatterTechnology]: 'darkMatterTechnology', [TechnologyType.TerraformingTechnology]: 'terraformingTechnology', [TechnologyType.PlanetDestructionTech]: 'planetDestructionTech', - [TechnologyType.MiningTechnology]: 'miningTechnology' + [TechnologyType.MiningTechnology]: 'miningTechnology', + [TechnologyType.IntergalacticResearchNetwork]: 'intergalacticResearchNetwork', + [TechnologyType.MineralResearch]: 'mineralResearch', + [TechnologyType.CrystalResearch]: 'crystalResearch', + [TechnologyType.FuelResearch]: 'fuelResearch' } // 军官类型枚举值到翻译键的映射 diff --git a/src/composables/useQueueAnimation.ts b/src/composables/useQueueAnimation.ts index fd812b9..7b067f8 100644 --- a/src/composables/useQueueAnimation.ts +++ b/src/composables/useQueueAnimation.ts @@ -110,7 +110,7 @@ export const triggerQueueAnimation = (event: MouseEvent, type: 'building' | 'tec el.style.left = `${x}px` el.style.top = `${y}px` - el.style.transform = `translate(-50%, -50%) scale(${scale})` + el.style.transform = `translate3d(-50%, -50%, 0) scale3d(${scale}, ${scale}, 1)` el.style.opacity = `${opacity}` if (progress < 1) { diff --git a/src/config/gameConfig.ts b/src/config/gameConfig.ts index 6226cbd..d488ac5 100644 --- a/src/config/gameConfig.ts +++ b/src/config/gameConfig.ts @@ -284,7 +284,7 @@ export const BUILDINGS: Record = { id: BuildingType.LunarBase, name: '月球基地', description: '增加月球可用空间', - baseCost: { metal: 20000, crystal: 40000, deuterium: 20000, darkMatter: 0, energy: 0 }, + baseCost: { metal: 8000, crystal: 8000, deuterium: 4000, darkMatter: 0, energy: 0 }, baseTime: 45, // 减少建造时间:60→45秒 costMultiplier: 2, spaceUsage: 0, // 月球基地本身不占用空间,反而增加空间 @@ -357,7 +357,7 @@ export const BUILDINGS: Record = { [BuildingType.GeoResearchStation]: { id: BuildingType.GeoResearchStation, name: '地质研究站', - description: '研究地质结构,提高矿脉自然恢复速度。每级增加50%恢复速率', + description: '研究地质结构,提高矿脉自然恢复速度。每级增加10%恢复速率', baseCost: { metal: 50000, crystal: 30000, deuterium: 20000, darkMatter: 0, energy: 0 }, baseTime: 60, costMultiplier: 1.8, @@ -416,6 +416,34 @@ export const BUILDINGS: Record = { [TechnologyType.PlasmaTechnology]: 5 } } + }, + // 2moons新增建筑 + [BuildingType.University]: { + id: BuildingType.University, + name: '大学', + description: '培养科研人员,加快研究速度。每级减少研究时间8%(与星际研究网络叠加)', + baseCost: { metal: 200000, crystal: 100000, deuterium: 50000, darkMatter: 0, energy: 0 }, + baseTime: 120, + costMultiplier: 2, + spaceUsage: 8, + planetOnly: true, + maxLevel: 10, // 最多10级(最高约57%研究时间减少) + requirements: { + [BuildingType.ResearchLab]: 8, + [BuildingType.RoboticsFactory]: 6 + }, + levelRequirements: { + 5: { + [BuildingType.ResearchLab]: 10, + [BuildingType.RoboticsFactory]: 8, + [TechnologyType.EnergyTechnology]: 8 + }, + 8: { + [BuildingType.ResearchLab]: 12, + [BuildingType.NaniteFactory]: 2, + [TechnologyType.ComputerTechnology]: 8 + } + } } } @@ -726,6 +754,111 @@ export const TECHNOLOGIES: Record = { [TechnologyType.PlasmaTechnology]: 3 } } + }, + // 2moons新增科技 + [TechnologyType.IntergalacticResearchNetwork]: { + id: TechnologyType.IntergalacticResearchNetwork, + name: '星际研究网络', + description: '连接多个星球的研究实验室,共享研究资源。每级可连接1个额外的研究实验室(取等级最高的N个实验室)', + baseCost: { metal: 240000, crystal: 400000, deuterium: 160000, darkMatter: 0, energy: 0 }, + baseTime: 180, + costMultiplier: 2, + maxLevel: 10, + requirements: { + [BuildingType.ResearchLab]: 10, + [TechnologyType.ComputerTechnology]: 8, + [TechnologyType.HyperspaceTechnology]: 8 + }, + levelRequirements: { + 5: { + [BuildingType.ResearchLab]: 12, + [TechnologyType.ComputerTechnology]: 10, + [TechnologyType.HyperspaceTechnology]: 10 + }, + 8: { + [BuildingType.ResearchLab]: 14, + [TechnologyType.ComputerTechnology]: 12, + [BuildingType.NaniteFactory]: 5 + } + } + }, + [TechnologyType.MineralResearch]: { + id: TechnologyType.MineralResearch, + name: '矿物研究', + description: '研究更高效的金属提取技术,提升金属矿产量。每级增加金属产量2%', + baseCost: { metal: 60000, crystal: 30000, deuterium: 0, darkMatter: 0, energy: 0 }, + baseTime: 60, + costMultiplier: 1.75, + maxLevel: 20, + requirements: { + [BuildingType.ResearchLab]: 5, + [BuildingType.MetalMine]: 10, + [TechnologyType.EnergyTechnology]: 3 + }, + levelRequirements: { + 10: { + [BuildingType.ResearchLab]: 8, + [BuildingType.MetalMine]: 20, + [TechnologyType.EnergyTechnology]: 8 + }, + 15: { + [BuildingType.ResearchLab]: 12, + [BuildingType.NaniteFactory]: 2, + [TechnologyType.PlasmaTechnology]: 5 + } + } + }, + [TechnologyType.CrystalResearch]: { + id: TechnologyType.CrystalResearch, + name: '晶体研究', + description: '研究更高效的晶体提炼技术,提升晶体矿产量。每级增加晶体产量2%', + baseCost: { metal: 40000, crystal: 60000, deuterium: 0, darkMatter: 0, energy: 0 }, + baseTime: 60, + costMultiplier: 1.75, + maxLevel: 20, + requirements: { + [BuildingType.ResearchLab]: 5, + [BuildingType.CrystalMine]: 10, + [TechnologyType.EnergyTechnology]: 3 + }, + levelRequirements: { + 10: { + [BuildingType.ResearchLab]: 8, + [BuildingType.CrystalMine]: 20, + [TechnologyType.EnergyTechnology]: 8 + }, + 15: { + [BuildingType.ResearchLab]: 12, + [BuildingType.NaniteFactory]: 2, + [TechnologyType.PlasmaTechnology]: 5 + } + } + }, + [TechnologyType.FuelResearch]: { + id: TechnologyType.FuelResearch, + name: '燃料研究', + description: '研究更高效的重氢合成技术,提升重氢产量。每级增加重氢产量2%', + baseCost: { metal: 0, crystal: 50000, deuterium: 50000, darkMatter: 0, energy: 0 }, + baseTime: 60, + costMultiplier: 1.75, + maxLevel: 20, + requirements: { + [BuildingType.ResearchLab]: 5, + [BuildingType.DeuteriumSynthesizer]: 10, + [TechnologyType.EnergyTechnology]: 3 + }, + levelRequirements: { + 10: { + [BuildingType.ResearchLab]: 8, + [BuildingType.DeuteriumSynthesizer]: 20, + [TechnologyType.EnergyTechnology]: 8 + }, + 15: { + [BuildingType.ResearchLab]: 12, + [BuildingType.NaniteFactory]: 2, + [TechnologyType.PlasmaTechnology]: 5 + } + } } } @@ -1007,7 +1140,7 @@ export const SHIPS: Record = { id: ShipType.Deathstar, name: '死星', description: '终极武器,能够摧毁整个行星', - cost: { metal: 5000000, crystal: 4000000, deuterium: 1000000, darkMatter: 20000, energy: 0 }, + cost: { metal: 50000000, crystal: 40000000, deuterium: 10000000, darkMatter: 20000, energy: 0 }, buildTime: 600, cargoCapacity: 1000000, attack: 200000, @@ -1467,9 +1600,9 @@ export const DIPLOMATIC_CONFIG = { // 贸易检查间隔(秒) CHECK_INTERVAL: 1800, // 30分钟 // 贸易概率 - PROBABILITY: 0.1, + PROBABILITY: 0.05, // 玩家最多同时保留的贸易提议数量 - MAX_PENDING_OFFERS: 30, + MAX_PENDING_OFFERS: 5, // 汇率配置:NPC出售资源的汇率 EXCHANGE_RATES: { // 金属:晶体:重氢 基准比例 3:2:1 @@ -1658,9 +1791,9 @@ export const ORE_DEPOSIT_CONFIG = { // 矿脉恢复配置 REGENERATION: { ENABLED: true, - // 每小时恢复初始储量的百分比(0.1% = 每小时恢复0.1%,约42天完全恢复) - RATE_PER_HOUR: 0.001, - // 最大恢复到初始储量的百分比(100%表示可以完全恢复) + // 每小时恢复初始储量的百分比(1% = 每小时恢复1%,约4.2天完全恢复) + RATE_PER_HOUR: 0.01, + // 最大恢复到初始储量的百分比(100表示可以完全恢复)% MAX_PERCENTAGE: 1.0 } } diff --git a/src/locales/de.ts b/src/locales/de.ts index cc53f9e..66cb61e 100644 --- a/src/locales/de.ts +++ b/src/locales/de.ts @@ -153,6 +153,7 @@ export default { planetDestroyerFactory: 'Planetenzerstörer-Fabrik', geoResearchStation: 'Geologische Forschungsstation', deepDrillingFacility: 'Tiefbohranlage', + university: 'Universität', buildTime: 'Bauzeit', build: 'Bauen', production: 'Produktion', @@ -204,8 +205,9 @@ export default { jumpGate: 'Überträgt Flotten sofort zu anderen Monden', planetDestroyerFactory: 'Konstruiert ultimative Waffen zur Zerstörung von Planeten', geoResearchStation: - 'Erforscht geologische Strukturen und erhöht die natürliche Erzvorkommen-Regenerationsrate. +50% Regeneration pro Stufe', - deepDrillingFacility: '' + 'Erforscht geologische Strukturen und erhöht die natürliche Erzvorkommen-Regenerationsrate. +10% Regeneration pro Stufe', + deepDrillingFacility: '', + university: 'Bildet Forscher aus, um die Forschungsgeschwindigkeit zu beschleunigen. -8% Forschungszeit pro Stufe' }, ships: { lightFighter: 'Leichter Jäger', @@ -287,7 +289,11 @@ export default { researchQueueBonus: 'Forschungswarteschlange', colonySlots: 'Kolonieplätze', forAllPlanets: '(Global)', - speedBonus: 'Geschwindigkeitsbonus' + speedBonus: 'Geschwindigkeitsbonus', + // Ressourcenproduktionsbonus-Anzeige + mineralResearch: 'Mineralforschung', + crystalResearch: 'Kristallforschung', + fuelResearch: 'Brennstoffforschung' }, technologies: { energyTechnology: 'Energietechnik', @@ -308,7 +314,11 @@ export default { darkMatterTechnology: 'Dunkle-Materie-Technologie', terraformingTechnology: 'Terraforming-Technologie', planetDestructionTech: 'Planetenzerstörungstechnologie', - miningTechnology: '' + miningTechnology: '', + intergalacticResearchNetwork: 'Intergalaktisches Forschungsnetzwerk', + mineralResearch: 'Mineralforschung', + crystalResearch: 'Kristallforschung', + fuelResearch: 'Treibstoffforschung' }, technologyDescriptions: { energyTechnology: 'Verbessert Energieeffizienz', @@ -330,7 +340,11 @@ export default { darkMatterTechnology: 'Forschung zu Eigenschaften und Anwendungen von Dunkler Materie', terraformingTechnology: 'Forschung zur Planeten-Terraforming-Technologie, erhöht verfügbaren Platz aller Planeten um 30 pro Stufe', planetDestructionTech: 'Schreckliche Technologie zur Zerstörung ganzer Planeten', - miningTechnology: '' + miningTechnology: '', + intergalacticResearchNetwork: 'Verbindet mehrere Forschungslabore über Planeten hinweg. Jede Stufe verbindet 1 zusätzliches Labor', + mineralResearch: 'Erforscht effizientere Metallextraktionstechniken. +2% Metallproduktion pro Stufe', + crystalResearch: 'Erforscht effizientere Kristallveredelungstechniken. +2% Kristallproduktion pro Stufe', + fuelResearch: 'Erforscht effizientere Deuterium-Synthesetechniken. +2% Deuteriumproduktion pro Stufe' }, officers: { commander: 'Kommandant', @@ -932,7 +946,10 @@ export default { hideRoundDetails: 'Rundendetails ausblenden', round: 'Runde {round}', attackerRemainingPower: 'Verbleibende Angreiferkraft', - defenderRemainingPower: 'Verbleibende Verteidigerkraft' + defenderRemainingPower: 'Verbleibende Verteidigerkraft', + importFromSpyReport: 'Aus Spionagebericht importieren', + selectSpyReport: 'Spionagebericht auswählen', + noSpyReports: 'Keine Spionageberichte verfügbar' }, settings: { dataManagement: 'Datenverwaltung', @@ -943,6 +960,7 @@ export default { exporting: 'Exportieren...', exportSuccess: 'Export erfolgreich', exportSuccessWithPath: 'Export erfolgreich, Datei gespeichert unter: {path}', + storagePermissionDenied: 'Speicherberechtigung verweigert, Datei kann nicht exportiert werden', exportFailed: 'Export fehlgeschlagen, bitte erneut versuchen', importData: 'Daten importieren', importDataDesc: 'Spielfortschritt aus JSON-Datei wiederherstellen', @@ -962,6 +980,8 @@ export default { gameSettingsDesc: 'Spielparameter und Einstellungen anpassen', gamePause: 'Spielpause', gamePauseDesc: 'Spielzeit und Ressourcenproduktion pausieren oder fortsetzen', + battleMode: 'Bis zum Ende kämpfen', + battleModeDesc: 'Wenn aktiviert, dauern Kämpfe bis zu 100 Runden bis ein Sieger feststeht. Wenn deaktiviert, wird der klassische 6-Runden-Modus verwendet', pause: 'Pausieren', resume: 'Fortsetzen', gamePaused: 'Spiel pausiert', @@ -1400,19 +1420,23 @@ export default { skip: 'Anleitung überspringen', welcome: { title: 'Willkommen bei OGame', - content: 'Willkommen, Kommandant! Diese Anleitung führt Sie durch die Grundlagen des Imperiumsaufbaus. Klicken Sie auf "Weiter", um Ihre Reise zu beginnen.' + content: + 'Willkommen, Kommandant! Diese Anleitung führt Sie durch die Grundlagen des Imperiumsaufbaus. Klicken Sie auf "Weiter", um Ihre Reise zu beginnen.' }, resources: { title: 'Ressourcenübersicht', - content: 'Dies sind Ihre Ressourcen: Metall, Kristall und Deuterium. Sie sind für den Bau von Gebäuden und die Erforschung von Technologien unerlässlich. Energie ist ebenfalls wichtig, um Ihre Infrastruktur zu betreiben.' + content: + 'Dies sind Ihre Ressourcen: Metall, Kristall und Deuterium. Sie sind für den Bau von Gebäuden und die Erforschung von Technologien unerlässlich. Energie ist ebenfalls wichtig, um Ihre Infrastruktur zu betreiben.' }, planet: { title: 'Ihr Planet', - content: 'Dies ist Ihr Heimatplanet. Hier sehen Sie den Planetennamen, die Koordinaten und können zwischen Planeten wechseln, wenn Sie Ihr Imperium erweitern.' + content: + 'Dies ist Ihr Heimatplanet. Hier sehen Sie den Planetennamen, die Koordinaten und können zwischen Planeten wechseln, wenn Sie Ihr Imperium erweitern.' }, navigation: { title: 'Navigationsmenü', - content: 'Verwenden Sie dieses Menü, um zwischen verschiedenen Bereichen zu navigieren: Gebäude, Forschung, Flotte, Galaxie usw. Jeder Bereich bietet einzigartige Spielfunktionen.' + content: + 'Verwenden Sie dieses Menü, um zwischen verschiedenen Bereichen zu navigieren: Gebäude, Forschung, Flotte, Galaxie usw. Jeder Bereich bietet einzigartige Spielfunktionen.' }, gotoBuildings: { title: 'Zu Gebäuden gehen', @@ -1420,39 +1444,48 @@ export default { }, buildSolarPlant: { title: 'Solarkraftwerk bauen', - content: 'Bauen Sie zuerst ein Solarkraftwerk! Es versorgt Ihren Planeten mit Energie. Ohne Energie können andere Ressourcengebäude nicht funktionieren. Dies ist der wichtigste erste Schritt.' + content: + 'Bauen Sie zuerst ein Solarkraftwerk! Es versorgt Ihren Planeten mit Energie. Ohne Energie können andere Ressourcengebäude nicht funktionieren. Dies ist der wichtigste erste Schritt.' }, waitBuild: { title: 'Bauauftrag', - content: 'Ihr Gebäude befindet sich jetzt im Bauauftrag. Klicken Sie auf das Warteschlangensymbol oben rechts, um alle laufenden Bau- und Forschungsaufgaben anzuzeigen. Gebäude brauchen Zeit zur Fertigstellung, aber Sie können während des Wartens weitermachen.' + content: + 'Ihr Gebäude befindet sich jetzt im Bauauftrag. Klicken Sie auf das Warteschlangensymbol oben rechts, um alle laufenden Bau- und Forschungsaufgaben anzuzeigen. Gebäude brauchen Zeit zur Fertigstellung, aber Sie können während des Wartens weitermachen.' }, buildMetalMine: { title: 'Metallmine bauen', - content: 'Jetzt, da Sie Energie haben, bauen Sie eine Metallmine. Die Metallmine ist Ihre Hauptmetallquelle, und Metall wird für fast jedes Gebäude und Schiff benötigt.' + content: + 'Jetzt, da Sie Energie haben, bauen Sie eine Metallmine. Die Metallmine ist Ihre Hauptmetallquelle, und Metall wird für fast jedes Gebäude und Schiff benötigt.' }, buildCrystalMine: { title: 'Kristallmine bauen', - content: 'Kristall ist seltener, aber für fortgeschrittene Technologien entscheidend. Bauen Sie eine Kristallmine, um diese wertvolle Ressource zu sammeln.' + content: + 'Kristall ist seltener, aber für fortgeschrittene Technologien entscheidend. Bauen Sie eine Kristallmine, um diese wertvolle Ressource zu sammeln.' }, buildDeuterium: { title: 'Deuteriumsynthesizer bauen', - content: 'Deuterium ist für Schiffstreibstoff und fortgeschrittene Forschung unerlässlich. Bauen Sie einen Deuteriumsynthesizer, um diese wichtige Ressource zu produzieren.' + content: + 'Deuterium ist für Schiffstreibstoff und fortgeschrittene Forschung unerlässlich. Bauen Sie einen Deuteriumsynthesizer, um diese wichtige Ressource zu produzieren.' }, upgradeMines: { title: 'Ressourcenminen upgraden', - content: 'Als Nächstes müssen Sie die drei Ressourcenminen (Metall, Kristall, Deuterium) auf Level 2 upgraden, um die Anforderungen für den Bau der Roboterfabrik zu erfüllen. Upgraden Sie sie weiter, wenn Sie genügend Ressourcen haben.' + content: + 'Als Nächstes müssen Sie die drei Ressourcenminen (Metall, Kristall, Deuterium) auf Level 2 upgraden, um die Anforderungen für den Bau der Roboterfabrik zu erfüllen. Upgraden Sie sie weiter, wenn Sie genügend Ressourcen haben.' }, buildRobotics: { title: 'Roboterfabrik bauen', - content: 'Die Roboterfabrik kann die Baugeschwindigkeit erheblich erhöhen. Sie benötigt Metallmine, Kristallmine und Deuteriumsynthesizer jeweils auf Level 2. Bauen Sie sie, um die Baueffizienz zu steigern!' + content: + 'Die Roboterfabrik kann die Baugeschwindigkeit erheblich erhöhen. Sie benötigt Metallmine, Kristallmine und Deuteriumsynthesizer jeweils auf Level 2. Bauen Sie sie, um die Baueffizienz zu steigern!' }, upgradeMinesForLab: { title: 'Ressourcenminen weiter upgraden', - content: 'Jetzt müssen Sie die drei Ressourcenminen auf Level 3 upgraden, um die Bauanforderungen des Forschungslabors zu erfüllen. Entwickeln Sie Ihre Ressourcenproduktion weiter.' + content: + 'Jetzt müssen Sie die drei Ressourcenminen auf Level 3 upgraden, um die Bauanforderungen des Forschungslabors zu erfüllen. Entwickeln Sie Ihre Ressourcenproduktion weiter.' }, buildResearchLab: { title: 'Forschungslabor bauen', - content: 'Das Forschungslabor ist die Grundlage für technologischen Fortschritt. Es benötigt alle drei Ressourcenminen auf Level 3. Bauen Sie es, um Technologieforschung freizuschalten!' + content: + 'Das Forschungslabor ist die Grundlage für technologischen Fortschritt. Es benötigt alle drei Ressourcenminen auf Level 3. Bauen Sie es, um Technologieforschung freizuschalten!' }, gotoResearch: { title: 'Zur Forschung gehen', @@ -1460,11 +1493,13 @@ export default { }, researchEnergy: { title: 'Energietechnik erforschen', - content: 'Die Energietechnik kann Ihre Energieproduktion verbessern und fortgeschrittene Gebäude freischalten. Dies ist eine der grundlegendsten und wichtigsten Technologien.' + content: + 'Die Energietechnik kann Ihre Energieproduktion verbessern und fortgeschrittene Gebäude freischalten. Dies ist eine der grundlegendsten und wichtigsten Technologien.' }, shipyardIntro: { title: 'Flotte & Werft', - content: 'Schiffe ermöglichen es Ihnen, die Galaxie zu erkunden, Ressourcen zu transportieren und Ihr Imperium zu verteidigen. Um Schiffe zu bauen, benötigen Sie eine Raumschiffwerft (benötigt Roboterfabrik Level 2).' + content: + 'Schiffe ermöglichen es Ihnen, die Galaxie zu erkunden, Ressourcen zu transportieren und Ihr Imperium zu verteidigen. Um Schiffe zu bauen, benötigen Sie eine Raumschiffwerft (benötigt Roboterfabrik Level 2).' }, gotoBuildingsForShipyard: { title: 'Zurück zur Gebäudeseite', @@ -1472,32 +1507,39 @@ export default { }, buildShipyard: { title: 'Raumschiffwerft bauen', - content: 'Die Raumschiffwerft ermöglicht es Ihnen, Schiffe und Verteidigungssysteme zu bauen. Dies ist für Flottenoperationen unerlässlich.' + content: + 'Die Raumschiffwerft ermöglicht es Ihnen, Schiffe und Verteidigungssysteme zu bauen. Dies ist für Flottenoperationen unerlässlich.' }, fleetIntro: { title: 'Flottenoperationen', - content: 'Sobald Sie Schiffe haben, können Sie sie auf Missionen schicken: Ressourcen transportieren, Planeten kolonisieren, Feinde angreifen oder Trümmerfelder erkunden.' + content: + 'Sobald Sie Schiffe haben, können Sie sie auf Missionen schicken: Ressourcen transportieren, Planeten kolonisieren, Feinde angreifen oder Trümmerfelder erkunden.' }, galaxyIntro: { title: 'Galaxie erkunden', - content: 'Die Galaxieansicht zeigt andere Planeten, Trümmerfelder und Expansionsmöglichkeiten. Verwenden Sie sie, um Ziele auszukundschaften und Ihre Strategie zu planen.' + content: + 'Die Galaxieansicht zeigt andere Planeten, Trümmerfelder und Expansionsmöglichkeiten. Verwenden Sie sie, um Ziele auszukundschaften und Ihre Strategie zu planen.' }, complete: { title: 'Anleitung abgeschlossen!', - content: 'Glückwunsch, Kommandant! Sie kennen jetzt die Grundlagen. Bauen Sie Ihr Imperium weiter auf, erforschen Sie Technologien und erkunden Sie die Galaxie. Denken Sie daran: Zuerst Energie entwickeln, dann Ressourcen, dann Fabriken und Forschung! Viel Glück!' + content: + 'Glückwunsch, Kommandant! Sie kennen jetzt die Grundlagen. Bauen Sie Ihr Imperium weiter auf, erforschen Sie Technologien und erkunden Sie die Galaxie. Denken Sie daran: Zuerst Energie entwickeln, dann Ressourcen, dann Fabriken und Forschung! Viel Glück!' }, mobile: { welcome: { title: 'Willkommen bei OGame (Mobil)', - content: 'Willkommen, Kommandant! Dies ist eine vereinfachte Anleitung für Touchscreens. Wir werden schnell die Kernfunktionen durchgehen, damit Sie mit dem Aufbau Ihres Imperiums beginnen können.' + content: + 'Willkommen, Kommandant! Dies ist eine vereinfachte Anleitung für Touchscreens. Wir werden schnell die Kernfunktionen durchgehen, damit Sie mit dem Aufbau Ihres Imperiums beginnen können.' }, resources: { title: 'Obere Ressourcenleiste', - content: 'Oben werden Ihre Ressourcen angezeigt: Metall, Kristall und Deuterium. Tippen Sie, um detaillierte Produktionsinformationen anzuzeigen.' + content: + 'Oben werden Ihre Ressourcen angezeigt: Metall, Kristall und Deuterium. Tippen Sie, um detaillierte Produktionsinformationen anzuzeigen.' }, menu: { title: 'Navigationsmenü öffnen', - content: 'Tippen Sie auf dieses Menüsymbol, um die Navigationsleiste zu öffnen. Sie können auf alle Funktionen zugreifen: Gebäude, Forschung, Flotte usw.' + content: + 'Tippen Sie auf dieses Menüsymbol, um die Navigationsleiste zu öffnen. Sie können auf alle Funktionen zugreifen: Gebäude, Forschung, Flotte usw.' }, gotoBuildings: { title: 'Zur Gebäudeseite gehen', @@ -1505,19 +1547,23 @@ export default { }, buildSolarPlant: { title: 'Solarkraftwerk bauen', - content: 'Bauen Sie zuerst ein Solarkraftwerk! Scrollen Sie nach unten, um es zu finden, und tippen Sie auf die Karte zum Bauen. Energie ist die Grundlage für alles.' + content: + 'Bauen Sie zuerst ein Solarkraftwerk! Scrollen Sie nach unten, um es zu finden, und tippen Sie auf die Karte zum Bauen. Energie ist die Grundlage für alles.' }, waitBuild: { title: 'Bauauftrag', - content: 'Tippen Sie auf das Warteschlangensymbol oben rechts, um den Baufortschritt anzuzeigen. Sie können weiter andere Seiten durchsuchen - der Bau läuft im Hintergrund.' + content: + 'Tippen Sie auf das Warteschlangensymbol oben rechts, um den Baufortschritt anzuzeigen. Sie können weiter andere Seiten durchsuchen - der Bau läuft im Hintergrund.' }, buildMetalMine: { title: 'Metallmine bauen', - content: 'Nachdem Sie Energie haben, bauen Sie eine Metallmine. Scrollen Sie nach unten, um die Metallmine zu finden, und tippen Sie zum Bauen.' + content: + 'Nachdem Sie Energie haben, bauen Sie eine Metallmine. Scrollen Sie nach unten, um die Metallmine zu finden, und tippen Sie zum Bauen.' }, complete: { title: 'Schnellanleitung abgeschlossen!', - content: 'Sehr gut! Sie haben die Grundlagen gemeistert. Bauen Sie weiter die Kristallmine und den Deuteriumsynthesizer und erkunden Sie andere Funktionen. Denken Sie daran: Zuerst Energie, dann Ressourcen!' + content: + 'Sehr gut! Sie haben die Grundlagen gemeistert. Bauen Sie weiter die Kristallmine und den Deuteriumsynthesizer und erkunden Sie andere Funktionen. Denken Sie daran: Zuerst Energie, dann Ressourcen!' } } }, @@ -1586,7 +1632,8 @@ export default { }, campaign: { title: 'Kampagnenmodus', - message: 'Erkunden Sie die Galaxie-Story-Kampagne! Schließen Sie Missionen ab, um Ressourcenbelohnungen zu erhalten und neue Herausforderungen freizuschalten. Jeder Knoten hat einzigartige Ziele und Feinde.' + message: + 'Erkunden Sie die Galaxie-Story-Kampagne! Schließen Sie Missionen ab, um Ressourcenbelohnungen zu erhalten und neue Herausforderungen freizuschalten. Jeder Knoten hat einzigartige Ziele und Feinde.' }, achievements: { title: 'Erfolgssystem', @@ -1964,13 +2011,19 @@ export default { questNotActive: 'Quest nicht aktiv', questNotCompleted: 'Quest nicht abgeschlossen', rewardsAlreadyClaimed: 'Belohnungen bereits erhalten', - prerequisiteNotMet: 'Voraussetzungs-Quest nicht abgeschlossen' + prerequisiteNotMet: 'Voraussetzungs-Quest nicht abgeschlossen', + questLocked: 'Quest ist gesperrt', + notInitialized: 'Kampagne nicht initialisiert', + questAlreadyCompleted: 'Quest bereits abgeschlossen' }, speakers: { ancientVoice: 'Antike Stimme', neighborNPC: 'Nachbar-Fraktion', mysteriousSignal: 'Mysteriöses Signal', - enemyCommander: 'Feindlicher Kommandant' + enemyCommander: 'Feindlicher Kommandant', + shadowVoice: 'Schattenstimme', + allyNPC: 'Verbündete Fraktion', + ancientGuardian: 'Antiker Wächter' }, objectiveDescriptions: { buildMetalMine: 'Baue Metallmine auf Stufe 2', @@ -2060,13 +2113,19 @@ export default { '2_3': { prologue_1: 'Deine Expedition entdeckte anomale Signale. Diese Signale scheinen von einer antiken Zivilisation zu stammen... Untersuche ihre Quelle.', + prologue_2: + 'Diese Signale... Sie tragen Echos einer längst verlorenen Zivilisation. Ihre Geheimnisse warten darauf, entdeckt zu werden...', epilogue_1: 'Diese Symbole... Sie sind Ruinen einer antiken Zivilisation! Untersuche weiter, um ihre Geheimnisse zu enthüllen.' }, '2_4': { - prologue_1: 'Du hast den Standort antiker Ruinen gefunden. Sende deine Flotte zur Erkundung und sieh, was du entdecken kannst.' + prologue_1: 'Du hast den Standort antiker Ruinen gefunden. Sende deine Flotte zur Erkundung und sieh, was du entdecken kannst.', + prologue_2: 'Die Ruinen bergen viele Geheimnisse... Wähle deinen Weg weise...', + choice_1: 'Vorsichtig erkunden - Sicherheit priorisieren', + choice_2: 'Aggressiv erkunden - Entdeckung priorisieren' }, '2_5': { - prologue_1: 'Datenarchive wurden in den Ruinen gefunden. Studiere diese Daten, vielleicht kannst du neue Technologie freischalten.' + prologue_1: 'Datenarchive wurden in den Ruinen gefunden. Studiere diese Daten, vielleicht kannst du neue Technologie freischalten.', + epilogue_1: 'Die antiken Daten wurden entschlüsselt! Neue technologische Erkenntnisse wurden gewonnen.' }, '3_1': { prologue_1: 'Beim Erkunden vergiss nicht die Diplomatie. Gute Beziehungen zu umliegenden Fraktionen zu pflegen nützt dir.' }, '3_2': { @@ -2075,14 +2134,19 @@ export default { }, '3_3': { prologue_1: - 'Geheimdienstberichte deuten darauf hin, dass feindliche Kräfte dich aus den Schatten beobachten. Bleibe wachsam und erkunde ihre Bewegungen.' + 'Geheimdienstberichte deuten darauf hin, dass feindliche Kräfte dich aus den Schatten beobachten. Bleibe wachsam und erkunde ihre Bewegungen.', + prologue_2: 'Dunkle Mächte regen sich in der Leere... Sie haben deine wachsende Macht bemerkt...' }, '3_4': { prologue_1: 'Schließe eine formelle Allianz mit freundlichen Fraktionen, um euch gegenseitig gegen Bedrohungen zu unterstützen.' }, - '3_5': { prologue_1: 'Bedrohungen nähern sich. Baue Verteidigungsanlagen und bereite dich auf mögliche Konflikte vor.' }, + '3_5': { + prologue_1: 'Bedrohungen nähern sich. Baue Verteidigungsanlagen und bereite dich auf mögliche Konflikte vor.', + epilogue_1: 'Deine Verteidigung ist bereit. Der Sturm naht, aber du bist vorbereitet.' + }, '4_1': { prologue_1: 'Der Feind hat einen Angriff gestartet! Verteidige deinen Planeten!', + prologue_2: 'Die Schattenflotte nähert sich... Deine Stunde der Prüfung ist gekommen...', epilogue_1: 'Du hast die erste Welle des Feindes erfolgreich abgewehrt. Aber das ist erst der Anfang...' }, '4_2': { @@ -2092,20 +2156,28 @@ export default { '4_4': { prologue_1: 'Viele Trümmer bleiben auf dem Schlachtfeld. Recycel diese Ressourcen, um dich auf die nächste Schlacht vorzubereiten.' }, - '4_5': { prologue_1: 'Die letzte Schlacht naht. Baue eine mächtige Flotte und bereite dich auf die ultimative Herausforderung vor.' }, + '4_5': { + prologue_1: 'Die letzte Schlacht naht. Baue eine mächtige Flotte und bereite dich auf die ultimative Herausforderung vor.', + epilogue_1: 'Deine Flotte ist versammelt. Der entscheidende Moment naht...' + }, '5_1': { prologue_1: 'Alle Hinweise deuten auf den tiefsten Teil der Ruinen. Die Kerngeheimnisse der antiken Zivilisation liegen dort.', prologue_2: 'Du bist endlich angekommen... Die Wahrheit wird bald enthüllt...' }, - '5_2': { prologue_1: 'In den Tiefen der Ruinen entdecktest du verlorene antike Technologie. Erforsche und schalte ihre Macht frei.' }, + '5_2': { + prologue_1: 'In den Tiefen der Ruinen entdecktest du verlorene antike Technologie. Erforsche und schalte ihre Macht frei.', + prologue_2: 'Diese Technologie... Sie ist älter als alle bekannten Zivilisationen. Gehe vorsichtig damit um...' + }, '5_3': { prologue_1: 'Ein mysteriöser Feind ist aufgetaucht. Dies ist die letzte Herausforderung. Besiege ihn!', + prologue_2: 'Ich bin der Wächter dieser Geheimnisse. Beweise deinen Wert oder werde vernichtet!', epilogue_1: 'Du hast es geschafft! Der antike Wächter wurde besiegt. Die Geheimnisse der Galaxie stehen dir nun offen.' }, '5_4': { prologue_1: 'Frieden ist endlich eingekehrt. In dieser neuen Ära gründe neue Kolonien und erweitere dein Imperium.' }, '5_5': { prologue_1: 'Deine Legende hat gerade erst begonnen. Erkunde weiter und erobere mehr Sternensysteme!', - epilogue_1: 'Die Galaxie ist weit und grenzenlos, mit zahllosen Geheimnissen, die auf dich warten...' + epilogue_1: 'Die Galaxie ist weit und grenzenlos, mit zahllosen Geheimnissen, die auf dich warten...', + epilogue_2: 'Deine Reise geht weiter... Neue Abenteuer warten jenseits der Sterne...' } } } diff --git a/src/locales/en.ts b/src/locales/en.ts index 62648e4..fddf992 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -46,6 +46,8 @@ export default { cannotAttackOwnPlanet: 'Cannot attack your own planet', fleetMissionsFull: 'Fleet mission slots full', insufficientFleet: 'Insufficient fleet', + insufficientShips: 'Insufficient ships', + invalidQuantity: 'Invalid quantity', insufficientFuel: 'Insufficient fuel', planetOnly: 'This building can only be built on planets', moonOnly: 'This building can only be built on moons', @@ -55,7 +57,12 @@ export default { researchQueueFull: 'Research queue full', moonExists: 'Moon already exists', insufficientDebris: 'Insufficient debris field', - launchFailed: 'Launch failed' + launchFailed: 'Launch failed', + planetNotFound: 'Planet not found', + cannotAbandonHomePlanet: 'Cannot abandon home planet', + hasBuildQueue: 'Please wait for build queue to complete', + hasFleetOnPlanet: 'Please transfer or scrap all fleet first', + hasDefenseOnPlanet: 'Please demolish all defense first' }, nav: { overview: 'Overview', @@ -123,7 +130,12 @@ export default { renamePlanet: 'Rename Planet', renamePlanetTitle: 'Rename Planet', planetNamePlaceholder: 'Enter new planet name', - rename: 'Rename' + rename: 'Rename', + abandonColony: 'Abandon Colony', + confirmAbandon: 'Confirm Abandon Colony', + abandonWarning: 'Are you sure you want to abandon "{name}"?\n\nThis action cannot be undone!\nAll buildings, resources and the moon (if any) will be lost.', + confirmAbandonButton: 'Abandon', + abandonFailed: 'Abandon Failed' }, player: { points: 'Total Points' @@ -152,6 +164,7 @@ export default { planetDestroyerFactory: 'Planet Destroyer Factory', geoResearchStation: 'Geological Research Station', deepDrillingFacility: 'Deep Drilling Facility', + university: 'University', buildTime: 'Build Time', production: 'Production', consumption: 'Consumption', @@ -199,8 +212,9 @@ export default { sensorPhalanx: 'Detects fleet activities in surrounding systems', jumpGate: 'Instantly transfers fleets to other moons', planetDestroyerFactory: 'Constructs ultimate weapons capable of destroying planets', - geoResearchStation: 'Researches geological structures and increases ore deposit regeneration rate. +50% regeneration per level', - deepDrillingFacility: 'Drills deep into the crust to access deeper ore veins. +20% ore deposit capacity per level' + geoResearchStation: 'Researches geological structures and increases ore deposit regeneration rate. +10% regeneration per level', + deepDrillingFacility: 'Drills deep into the crust to access deeper ore veins. +20% ore deposit capacity per level', + university: 'Trains researchers to accelerate research speed. -8% research time per level (stacks with Intergalactic Research Network)' }, ships: { lightFighter: 'Light Fighter', @@ -275,7 +289,11 @@ export default { researchQueueBonus: 'Research Queue', colonySlots: 'Colony Slots', forAllPlanets: '(Global)', - speedBonus: 'Speed Bonus' + speedBonus: 'Speed Bonus', + // 资源产量加成显示 + mineralResearch: 'Mineral Research', + crystalResearch: 'Crystal Research', + fuelResearch: 'Fuel Research' }, technologies: { energyTechnology: 'Energy Technology', @@ -296,7 +314,11 @@ export default { darkMatterTechnology: 'Dark Matter Technology', terraformingTechnology: 'Terraforming Technology', planetDestructionTech: 'Planet Destruction Technology', - miningTechnology: 'Mining Technology' + miningTechnology: 'Mining Technology', + intergalacticResearchNetwork: 'Intergalactic Research Network', + mineralResearch: 'Mineral Research', + crystalResearch: 'Crystal Research', + fuelResearch: 'Fuel Research' }, technologyDescriptions: { energyTechnology: 'Improves energy efficiency', @@ -318,7 +340,11 @@ export default { darkMatterTechnology: 'Research into dark matter properties and applications', terraformingTechnology: 'Research planet terraforming technology, adds 30 available space to all planets per level', planetDestructionTech: 'Terrifying technology for destroying entire planets', - miningTechnology: 'Improves mining methods and equipment, increases ore deposit capacity on all planets. +15% capacity per level' + miningTechnology: 'Improves mining methods and equipment, increases ore deposit capacity on all planets. +15% capacity per level', + intergalacticResearchNetwork: 'Links multiple research labs across planets. Each level connects 1 additional lab (highest level labs are used)', + mineralResearch: 'Research more efficient metal extraction techniques. +2% metal production per level', + crystalResearch: 'Research more efficient crystal refinement techniques. +2% crystal production per level', + fuelResearch: 'Research more efficient deuterium synthesis techniques. +2% deuterium production per level' }, officers: { commander: 'Commander', @@ -440,7 +466,12 @@ export default { inputError: 'Input Error', inputErrorMessage: 'Please enter build quantity!', buildFailed: 'Build Failed', - buildFailedMessage: 'Please check if you have enough resources or if prerequisites are met.' + buildFailedMessage: 'Please check if you have enough resources or if prerequisites are met.', + scrapQuantity: 'Scrap Quantity', + scrapRefund: 'Scrap Refund (50%)', + scrap: 'Scrap', + scrapFailed: 'Scrap Failed', + scrapFailedMessage: 'Please check if you have enough ships.' }, defense: { attack: 'Attack', @@ -917,6 +948,9 @@ export default { round: 'Round {round}', attackerRemainingPower: 'Attacker remaining power', defenderRemainingPower: 'Defender remaining power', + importFromSpyReport: 'Import from Spy Report', + selectSpyReport: 'Select Spy Report', + noSpyReports: 'No spy reports available', // Battle animation playAnimation: 'Play Animation', showDetails: 'Show Details', @@ -944,6 +978,7 @@ export default { exporting: 'Exporting...', exportSuccess: 'Export successful', exportSuccessWithPath: 'Export successful, file saved to: {path}', + storagePermissionDenied: 'Storage permission denied, cannot export file', exportFailed: 'Export failed, please try again', importData: 'Import Data', importDataDesc: 'Restore game progress from JSON file', @@ -961,6 +996,8 @@ export default { gameSettingsDesc: 'Adjust game parameters and preferences', gamePause: 'Game Pause', gamePauseDesc: 'Pause or resume game time and resource production', + battleMode: 'Fight to Finish Mode', + battleModeDesc: 'When enabled, battles last up to 100 rounds until a winner is decided. When disabled, uses classic 6-round mode', pause: 'Pause', resume: 'Resume', gamePaused: 'Game paused', @@ -1950,13 +1987,19 @@ export default { questNotActive: 'Quest not active', questNotCompleted: 'Quest not completed', rewardsAlreadyClaimed: 'Rewards already claimed', - prerequisiteNotMet: 'Prerequisite quest not completed' + prerequisiteNotMet: 'Prerequisite quest not completed', + questLocked: 'Quest is locked', + notInitialized: 'Campaign not initialized', + questAlreadyCompleted: 'Quest already completed' }, speakers: { ancientVoice: 'Ancient Voice', neighborNPC: 'Neighbor Faction', mysteriousSignal: 'Mysterious Signal', - enemyCommander: 'Enemy Commander' + enemyCommander: 'Enemy Commander', + shadowVoice: 'Shadow Voice', + allyNPC: 'Allied Faction', + ancientGuardian: 'Ancient Guardian' }, objectiveDescriptions: { buildMetalMine: 'Build Metal Mine to level 2', @@ -2044,13 +2087,18 @@ export default { '2_3': { prologue_1: 'Your expedition discovered anomalous signals. These signals seem to come from an ancient civilization... Investigate their source.', + prologue_2: 'These signals... they carry echoes of a long-lost civilization. Their secrets await discovery...', epilogue_1: 'These symbols... They are ruins of an ancient civilization! Continue investigating to uncover their secrets.' }, '2_4': { - prologue_1: 'You have found the location of ancient ruins. Send your fleet to explore and see what you can discover.' + prologue_1: 'You have found the location of ancient ruins. Send your fleet to explore and see what you can discover.', + prologue_2: 'The ruins hold many secrets... Choose your path wisely...', + choice_1: 'Explore cautiously - prioritize safety', + choice_2: 'Explore aggressively - prioritize discovery' }, '2_5': { - prologue_1: 'Data archives were found in the ruins. Study this data, perhaps you can unlock new technology.' + prologue_1: 'Data archives were found in the ruins. Study this data, perhaps you can unlock new technology.', + epilogue_1: 'The ancient data has been decrypted! New technological insights have been gained.' }, '3_1': { prologue_1: 'While exploring, do not forget about diplomacy. Maintaining good relations with surrounding factions benefits you.' @@ -2059,16 +2107,19 @@ export default { prologue_1: 'Some factions have shown friendliness. Continue deepening relations, perhaps you can gain more support.' }, '3_3': { - prologue_1: 'Intelligence indicates hostile forces are watching you from the shadows. Stay vigilant and scout their movements.' + prologue_1: 'Intelligence indicates hostile forces are watching you from the shadows. Stay vigilant and scout their movements.', + prologue_2: 'Dark forces stir in the void... They have noticed your growing power...' }, '3_4': { prologue_1: 'Establish a formal alliance with friendly factions to support each other against threats.' }, '3_5': { - prologue_1: 'Threats are approaching. Build defense facilities and prepare for possible conflict.' + prologue_1: 'Threats are approaching. Build defense facilities and prepare for possible conflict.', + epilogue_1: 'Your defenses are ready. The storm is coming, but you are prepared.' }, '4_1': { prologue_1: 'The enemy has launched an attack! Defend your planet!', + prologue_2: 'The shadow fleet approaches... Your moment of trial has come...', epilogue_1: "You successfully repelled the enemy's first wave. But this is just the beginning..." }, '4_2': { @@ -2081,17 +2132,20 @@ export default { prologue_1: 'Much debris remains on the battlefield. Recycle these resources to prepare for the next battle.' }, '4_5': { - prologue_1: 'The final battle approaches. Build a powerful fleet and prepare for the ultimate challenge.' + prologue_1: 'The final battle approaches. Build a powerful fleet and prepare for the ultimate challenge.', + epilogue_1: 'Your fleet is assembled. The decisive moment draws near...' }, '5_1': { prologue_1: 'All clues point to the deepest part of the ruins. The core secrets of the ancient civilization lie there.', prologue_2: 'You have finally arrived... The truth will soon be revealed...' }, '5_2': { - prologue_1: 'In the depths of the ruins, you discovered lost ancient technology. Research and unlock their power.' + prologue_1: 'In the depths of the ruins, you discovered lost ancient technology. Research and unlock their power.', + prologue_2: 'This technology... it predates all known civilizations. Handle it with care...' }, '5_3': { prologue_1: 'A mysterious enemy has appeared. This is the final challenge. Defeat it!', + prologue_2: 'I am the guardian of these secrets. Prove your worth, or be destroyed!', epilogue_1: 'You did it! The ancient guardian has been defeated. The secrets of the galaxy are now open to you.' }, '5_4': { @@ -2099,7 +2153,8 @@ export default { }, '5_5': { prologue_1: 'Your legend has just begun. Continue exploring and conquering more star systems!', - epilogue_1: 'The galaxy is vast and boundless, with countless secrets waiting for you to discover...' + epilogue_1: 'The galaxy is vast and boundless, with countless secrets waiting for you to discover...', + epilogue_2: 'Your journey continues... New adventures await beyond the stars...' } } }, diff --git a/src/locales/es-LA.ts b/src/locales/es-LA.ts index 6d802b1..c637603 100644 --- a/src/locales/es-LA.ts +++ b/src/locales/es-LA.ts @@ -152,6 +152,7 @@ export default { planetDestroyerFactory: 'Fábrica de Destructores de Planetas', geoResearchStation: 'Estación de Investigación Geológica', deepDrillingFacility: 'Instalación de Perforación Profunda', + university: 'Universidad', buildTime: 'Tiempo de Construcción', production: 'Producción', consumption: 'Consumo', @@ -200,9 +201,10 @@ export default { jumpGate: 'Transfiere flotas instantáneamente a otras lunas', planetDestroyerFactory: 'Construye armas definitivas capaces de destruir planetas', geoResearchStation: - 'Investiga estructuras geológicas y aumenta la tasa de regeneración de depósitos de mineral. +50% de regeneración por nivel', + 'Investiga estructuras geológicas y aumenta la tasa de regeneración de depósitos de mineral. +10% de regeneración por nivel', deepDrillingFacility: - 'Perfora profundamente en la corteza para acceder a vetas de mineral más profundas. +20% de capacidad de depósito de mineral por nivel' + 'Perfora profundamente en la corteza para acceder a vetas de mineral más profundas. +20% de capacidad de depósito de mineral por nivel', + university: 'Entrena investigadores para acelerar la velocidad de investigación. -8% de tiempo de investigación por nivel' }, ships: { lightFighter: 'Caza Ligero', @@ -278,7 +280,11 @@ export default { colonySlots: 'Espacios de Colonia', forAllPlanets: '(Global)', speedBonus: 'Bono de Velocidad', - researchSpeedBonus: 'Bono de Velocidad de Investigación' + researchSpeedBonus: 'Bono de Velocidad de Investigación', + // Visualización de bono de producción de recursos + mineralResearch: 'Investigación Mineral', + crystalResearch: 'Investigación de Cristal', + fuelResearch: 'Investigación de Combustible' }, technologies: { energyTechnology: 'Tecnología de Energía', @@ -299,7 +305,11 @@ export default { darkMatterTechnology: 'Tecnología de Materia Oscura', terraformingTechnology: 'Tecnología de Terraformación', planetDestructionTech: 'Tecnología de Destrucción Planetaria', - miningTechnology: 'Tecnología de Minería' + miningTechnology: 'Tecnología de Minería', + intergalacticResearchNetwork: 'Red de Investigación Intergaláctica', + mineralResearch: 'Investigación Mineral', + crystalResearch: 'Investigación de Cristal', + fuelResearch: 'Investigación de Combustible' }, technologyDescriptions: { energyTechnology: 'Mejora la eficiencia energética', @@ -323,7 +333,11 @@ export default { 'Investigación de tecnología de terraformación planetaria, añade 30 espacios disponibles a todos los planetas por nivel', planetDestructionTech: 'Tecnología aterradora para destruir planetas enteros', miningTechnology: - 'Mejora los métodos y equipos de minería, aumenta la capacidad de depósito de mineral en todos los planetas. +15% de capacidad por nivel' + 'Mejora los métodos y equipos de minería, aumenta la capacidad de depósito de mineral en todos los planetas. +15% de capacidad por nivel', + intergalacticResearchNetwork: 'Conecta múltiples laboratorios de investigación entre planetas. Cada nivel conecta 1 laboratorio adicional', + mineralResearch: 'Investiga técnicas más eficientes de extracción de metal. +2% de producción de metal por nivel', + crystalResearch: 'Investiga técnicas más eficientes de refinamiento de cristal. +2% de producción de cristal por nivel', + fuelResearch: 'Investiga técnicas más eficientes de síntesis de deuterio. +2% de producción de deuterio por nivel' }, officers: { commander: 'Comandante', @@ -925,6 +939,9 @@ export default { round: 'Ronda {round}', attackerRemainingPower: 'Poder restante del atacante', defenderRemainingPower: 'Poder restante del defensor', + importFromSpyReport: 'Importar desde informe de espionaje', + selectSpyReport: 'Seleccionar informe de espionaje', + noSpyReports: 'No hay informes de espionaje disponibles', // Battle animation playAnimation: 'Reproducir Animación', showDetails: 'Mostrar Detalles', @@ -952,6 +969,7 @@ export default { exporting: 'Exportando...', exportSuccess: 'Exportación exitosa', exportSuccessWithPath: 'Exportación exitosa, archivo guardado en: {path}', + storagePermissionDenied: 'Permiso de almacenamiento denegado, no se puede exportar el archivo', exportFailed: 'Exportación fallida, por favor intenta de nuevo', importData: 'Importar Datos', importDataDesc: 'Restaurar progreso del juego desde archivo JSON', @@ -969,6 +987,8 @@ export default { gameSettingsDesc: 'Ajustar parámetros y preferencias del juego', gamePause: 'Pausa del Juego', gamePauseDesc: 'Pausar o reanudar el tiempo del juego y la producción de recursos', + battleMode: 'Modo de combate hasta el final', + battleModeDesc: 'Cuando está activado, las batallas duran hasta 100 rondas hasta que se decide un ganador. Cuando está desactivado, se usa el modo clásico de 6 rondas', pause: 'Pausar', resume: 'Reanudar', gamePaused: 'Juego pausado', @@ -1954,13 +1974,19 @@ export default { questNotActive: 'Misión no activa', questNotCompleted: 'Misión no completada', rewardsAlreadyClaimed: 'Recompensas ya reclamadas', - prerequisiteNotMet: 'Misión prerequisito no completada' + prerequisiteNotMet: 'Misión prerequisito no completada', + questLocked: 'Misión bloqueada', + notInitialized: 'Campaña no inicializada', + questAlreadyCompleted: 'Misión ya completada' }, speakers: { ancientVoice: 'Voz Antigua', neighborNPC: 'Facción Vecina', mysteriousSignal: 'Señal Misteriosa', - enemyCommander: 'Comandante Enemigo' + enemyCommander: 'Comandante Enemigo', + shadowVoice: 'Voz de la Sombra', + allyNPC: 'Facción Aliada', + ancientGuardian: 'Guardián Antiguo' }, objectiveDescriptions: { buildMetalMine: 'Construir Mina de Metal al nivel 2', @@ -2050,13 +2076,18 @@ export default { '2_3': { prologue_1: 'Tu expedición descubrió señales anómalas. Estas señales parecen venir de una civilización antigua... Investiga su origen.', + prologue_2: 'Estas señales... llevan ecos de una civilización perdida hace tiempo. Sus secretos esperan ser descubiertos...', epilogue_1: 'Estos símbolos... ¡Son ruinas de una civilización antigua! Continúa investigando para descubrir sus secretos.' }, '2_4': { - prologue_1: 'Has encontrado la ubicación de ruinas antiguas. Envía tu flota a explorar y ver qué puedes descubrir.' + prologue_1: 'Has encontrado la ubicación de ruinas antiguas. Envía tu flota a explorar y ver qué puedes descubrir.', + prologue_2: 'Las ruinas guardan muchos secretos... Elige tu camino sabiamente...', + choice_1: 'Explorar con cautela - priorizar seguridad', + choice_2: 'Explorar agresivamente - priorizar descubrimiento' }, '2_5': { - prologue_1: 'Se encontraron archivos de datos en las ruinas. Estudia estos datos, quizás puedas desbloquear nueva tecnología.' + prologue_1: 'Se encontraron archivos de datos en las ruinas. Estudia estos datos, quizás puedas desbloquear nueva tecnología.', + epilogue_1: '¡Los datos antiguos han sido descifrados! Se han obtenido nuevos conocimientos tecnológicos.' }, '3_1': { prologue_1: 'Mientras exploras, no olvides la diplomacia. Mantener buenas relaciones con las facciones circundantes te beneficia.' @@ -2066,16 +2097,19 @@ export default { }, '3_3': { prologue_1: - 'La inteligencia indica que fuerzas hostiles te están vigilando desde las sombras. Mantente alerta y explora sus movimientos.' + 'La inteligencia indica que fuerzas hostiles te están vigilando desde las sombras. Mantente alerta y explora sus movimientos.', + prologue_2: 'Fuerzas oscuras se agitan en el vacío... Han notado tu poder creciente...' }, '3_4': { prologue_1: 'Establece una alianza formal con facciones amigables para apoyarse mutuamente contra las amenazas.' }, '3_5': { - prologue_1: 'Las amenazas se acercan. Construye instalaciones de defensa y prepárate para posibles conflictos.' + prologue_1: 'Las amenazas se acercan. Construye instalaciones de defensa y prepárate para posibles conflictos.', + epilogue_1: 'Tus defensas están listas. La tormenta se acerca, pero estás preparado.' }, '4_1': { prologue_1: '¡El enemigo ha lanzado un ataque! ¡Defiende tu planeta!', + prologue_2: 'La flota de las sombras se acerca... Ha llegado tu momento de prueba...', epilogue_1: 'Repeliste exitosamente la primera ola del enemigo. Pero esto es solo el comienzo...' }, '4_2': { @@ -2088,7 +2122,8 @@ export default { prologue_1: 'Muchos escombros permanecen en el campo de batalla. Recicla estos recursos para prepararte para la próxima batalla.' }, '4_5': { - prologue_1: 'La batalla final se acerca. Construye una flota poderosa y prepárate para el desafío definitivo.' + prologue_1: 'La batalla final se acerca. Construye una flota poderosa y prepárate para el desafío definitivo.', + epilogue_1: 'Tu flota está reunida. El momento decisivo se acerca...' }, '5_1': { prologue_1: @@ -2096,10 +2131,12 @@ export default { prologue_2: 'Finalmente has llegado... La verdad pronto será revelada...' }, '5_2': { - prologue_1: 'En las profundidades de las ruinas, descubriste tecnología antigua perdida. Investiga y desbloquea su poder.' + prologue_1: 'En las profundidades de las ruinas, descubriste tecnología antigua perdida. Investiga y desbloquea su poder.', + prologue_2: 'Esta tecnología... es más antigua que todas las civilizaciones conocidas. Manéjala con cuidado...' }, '5_3': { prologue_1: 'Ha aparecido un enemigo misterioso. Este es el desafío final. ¡Derrótalo!', + prologue_2: '¡Soy el guardián de estos secretos. Demuestra tu valor o serás destruido!', epilogue_1: '¡Lo lograste! El guardián antiguo ha sido derrotado. Los secretos de la galaxia ahora están abiertos para ti.' }, '5_4': { @@ -2107,7 +2144,8 @@ export default { }, '5_5': { prologue_1: 'Tu leyenda acaba de comenzar. ¡Continúa explorando y conquistando más sistemas estelares!', - epilogue_1: 'La galaxia es vasta e infinita, con innumerables secretos esperando que los descubras...' + epilogue_1: 'La galaxia es vasta e infinita, con innumerables secretos esperando que los descubras...', + epilogue_2: 'Tu viaje continúa... Nuevas aventuras esperan más allá de las estrellas...' } } }, diff --git a/src/locales/ja.ts b/src/locales/ja.ts index 54a68ed..37d33be 100644 --- a/src/locales/ja.ts +++ b/src/locales/ja.ts @@ -165,6 +165,7 @@ export default { planetDestroyerFactory: '惑星破壊工場', geoResearchStation: '地質研究所', deepDrillingFacility: '深部掘削施設', + university: '大学', buildTime: '建設時間', build: '建設', production: '生産量', @@ -215,8 +216,9 @@ export default { sensorPhalanx: '周辺星系の艦隊活動を探知', jumpGate: '他の月へ艦隊を瞬間移動', planetDestroyerFactory: '惑星を破壊できる究極兵器を建造', - geoResearchStation: '地質構造を研究し、鉱脈の自然回復速度を向上。レベル毎に回復速度50%増加', - deepDrillingFacility: '' + geoResearchStation: '地質構造を研究し、鉱脈の自然回復速度を向上。レベル毎に回復速度10%増加', + deepDrillingFacility: '', + university: '研究者を育成し、研究速度を加速。レベル毎に研究時間-8%' }, ships: { lightFighter: '軽戦闘機', @@ -299,7 +301,11 @@ export default { colonySlots: '植民地スロット', forAllPlanets: '(全惑星)', speedBonus: '速度ボーナス', - researchSpeedBonus: '研究速度ボーナス' + researchSpeedBonus: '研究速度ボーナス', + // 資源生産ボーナス表示 + mineralResearch: '鉱物研究', + crystalResearch: 'クリスタル研究', + fuelResearch: '燃料研究' }, technologies: { energyTechnology: 'エネルギー技術', @@ -320,7 +326,11 @@ export default { darkMatterTechnology: 'ダークマター技術', terraformingTechnology: 'テラフォーミング技術', planetDestructionTech: '惑星破壊技術', - miningTechnology: '' + miningTechnology: '', + intergalacticResearchNetwork: '銀河間研究ネットワーク', + mineralResearch: '鉱物研究', + crystalResearch: 'クリスタル研究', + fuelResearch: '燃料研究' }, technologyDescriptions: { energyTechnology: 'エネルギー利用効率を向上', @@ -342,7 +352,11 @@ export default { darkMatterTechnology: 'ダークマターの性質と応用を研究', terraformingTechnology: '惑星地形改造技術を研究、レベル毎に全惑星の利用可能スペース30増加', planetDestructionTech: '惑星全体を破壊する恐怖の技術を研究', - miningTechnology: '' + miningTechnology: '', + intergalacticResearchNetwork: '複数の惑星の研究所を連結。レベル毎に追加1研究所を接続', + mineralResearch: 'より効率的な金属抽出技術を研究。レベル毎に金属生産+2%', + crystalResearch: 'より効率的なクリスタル精製技術を研究。レベル毎にクリスタル生産+2%', + fuelResearch: 'より効率的な重水素合成技術を研究。レベル毎に重水素生産+2%' }, officers: { commander: '司令官', @@ -955,7 +969,10 @@ export default { hideRoundDetails: 'ラウンド詳細非表示', round: '第{round}ラウンド', attackerRemainingPower: '攻撃側残存火力', - defenderRemainingPower: '防御側残存火力' + defenderRemainingPower: '防御側残存火力', + importFromSpyReport: 'スパイレポートからインポート', + selectSpyReport: 'スパイレポートを選択', + noSpyReports: 'スパイレポートがありません' }, settings: { dataManagement: 'データ管理', @@ -966,6 +983,7 @@ export default { exporting: 'エクスポート中...', exportSuccess: 'エクスポート成功', exportSuccessWithPath: 'エクスポート成功、ファイルの保存先:{path}', + storagePermissionDenied: 'ストレージ権限が拒否されました。ファイルをエクスポートできません', exportFailed: 'エクスポートに失敗しました。もう一度お試しください', importData: 'データインポート', importDataDesc: 'JSONファイルからゲームの進行状況を復元', @@ -983,6 +1001,8 @@ export default { gameSettingsDesc: 'ゲームパラメータと設定を調整', gamePause: 'ゲーム一時停止', gamePauseDesc: 'ゲーム時間と資源生産を一時停止または再開', + battleMode: '最後まで戦うモード', + battleModeDesc: '有効にすると、勝者が決まるまで最大100ラウンドの戦闘が行われます。無効の場合は、クラシックな6ラウンドモードが使用されます', pause: '一時停止', resume: '再開', gamePaused: 'ゲームを一時停止しました', @@ -1996,13 +2016,19 @@ export default { questNotActive: 'クエストはアクティブではありません', questNotCompleted: 'クエスト未完了', rewardsAlreadyClaimed: '報酬は既に受け取り済み', - prerequisiteNotMet: '前提クエスト未完了' + prerequisiteNotMet: '前提クエスト未完了', + questLocked: 'クエストはロックされています', + notInitialized: 'キャンペーンが初期化されていません', + questAlreadyCompleted: 'クエストは既に完了しています' }, speakers: { ancientVoice: '古代の声', neighborNPC: '隣接勢力', mysteriousSignal: '謎の信号', - enemyCommander: '敵司令官' + enemyCommander: '敵司令官', + shadowVoice: '影の声', + allyNPC: '同盟勢力', + ancientGuardian: '古代の守護者' }, objectiveDescriptions: { buildMetalMine: '金属鉱山をレベル2に建設', @@ -2082,36 +2108,60 @@ export default { }, '2_3': { prologue_1: '遠征で異常な信号を発見しました。これらの信号は古代文明からのようです...発信源を調査してください。', + prologue_2: 'これらの信号...失われた文明の残響を運んでいる。その秘密が発見を待っている...', epilogue_1: 'これらの記号は...古代文明の遺跡だ!さらに調査して秘密を解き明かそう。' }, - '2_4': { prologue_1: '古代遺跡の場所を発見しました。艦隊を送り、何が見つかるか探索してください。' }, - '2_5': { prologue_1: '遺跡でデータアーカイブが見つかりました。このデータを研究すれば、新しい技術が解放できるかもしれません。' }, + '2_4': { + prologue_1: '古代遺跡の場所を発見しました。艦隊を送り、何が見つかるか探索してください。', + prologue_2: '遺跡には多くの秘密がある...賢く道を選べ...', + choice_1: '慎重に探索する - 安全を優先', + choice_2: '積極的に探索する - 発見を優先' + }, + '2_5': { + prologue_1: '遺跡でデータアーカイブが見つかりました。このデータを研究すれば、新しい技術が解放できるかもしれません。', + epilogue_1: '古代のデータが解読されました!新しい技術的洞察を得ました。' + }, '3_1': { prologue_1: '探索中も外交を忘れないでください。周囲の勢力と良好な関係を維持することは有益です。' }, '3_2': { prologue_1: 'いくつかの勢力が友好を示しています。関係を深め続ければ、より多くのサポートを得られるかもしれません。' }, - '3_3': { prologue_1: '情報によると敵対勢力が影からあなたを監視しています。警戒を怠らず、彼らの動きを偵察してください。' }, + '3_3': { + prologue_1: '情報によると敵対勢力が影からあなたを監視しています。警戒を怠らず、彼らの動きを偵察してください。', + prologue_2: '闇の力が虚空で蠢いている...彼らはあなたの成長する力に気づいた...' + }, '3_4': { prologue_1: '友好勢力と正式な同盟を結び、脅威に対してお互いをサポートしましょう。' }, - '3_5': { prologue_1: '脅威が迫っています。防衛施設を建設し、可能な紛争に備えてください。' }, + '3_5': { + prologue_1: '脅威が迫っています。防衛施設を建設し、可能な紛争に備えてください。', + epilogue_1: '防衛準備が整いました。嵐が来るが、あなたは準備ができている。' + }, '4_1': { prologue_1: '敵が攻撃を開始しました!惑星を守ってください!', + prologue_2: '影の艦隊が迫っている...あなたの試練の時が来た...', epilogue_1: '敵の第一波を撃退しました。しかしこれは始まりに過ぎません...' }, '4_2': { prologue_1: '敵は撤退しましたが、戻ってくるでしょう。彼らの惑星を偵察して戦力を把握してください。' }, '4_3': { prologue_1: '反撃の時です。敵の惑星を攻撃し、彼らの戦力を弱めてください。' }, '4_4': { prologue_1: '戦場に多くのデブリが残っています。これらの資源をリサイクルして次の戦闘に備えてください。' }, - '4_5': { prologue_1: '最終決戦が近づいています。強力な艦隊を建造し、究極の挑戦に備えてください。' }, + '4_5': { + prologue_1: '最終決戦が近づいています。強力な艦隊を建造し、究極の挑戦に備えてください。', + epilogue_1: '艦隊が集結しました。決戦の時が近づいている...' + }, '5_1': { prologue_1: 'すべての手がかりは遺跡の最深部を指しています。古代文明の核心的な秘密がそこにあります。', prologue_2: 'ついに到着した...真実がまもなく明かされる...' }, - '5_2': { prologue_1: '遺跡の深部で失われた古代技術を発見しました。研究してその力を解放してください。' }, + '5_2': { + prologue_1: '遺跡の深部で失われた古代技術を発見しました。研究してその力を解放してください。', + prologue_2: 'この技術は...既知のすべての文明より古い。慎重に扱え...' + }, '5_3': { prologue_1: '謎の敵が現れました。これが最後の挑戦です。撃破してください!', + prologue_2: '私はこれらの秘密の守護者だ。お前の価値を証明せよ、さもなくば滅びよ!', epilogue_1: 'やりました!古代の守護者は倒されました。銀河の秘密は今やあなたに開かれています。' }, '5_4': { prologue_1: 'ついに平和が訪れました。この新時代に新しい植民地を築き、帝国を拡大してください。' }, '5_5': { prologue_1: 'あなたの伝説は始まったばかりです。さらに探索を続け、より多くの星系を征服してください!', - epilogue_1: '銀河は広大で果てしなく、数え切れない秘密があなたを待っています...' + epilogue_1: '銀河は広大で果てしなく、数え切れない秘密があなたを待っています...', + epilogue_2: 'あなたの旅は続く...新たな冒険が星の彼方で待っている...' } } } diff --git a/src/locales/ko.ts b/src/locales/ko.ts index 0bbb3e8..64b930a 100644 --- a/src/locales/ko.ts +++ b/src/locales/ko.ts @@ -153,6 +153,7 @@ export default { planetDestroyerFactory: '행성 파괴 공장', geoResearchStation: '지질 연구소', deepDrillingFacility: '심층 시추 시설', + university: '대학', buildTime: '건설 시간', build: '건설', production: '생산량', @@ -199,8 +200,9 @@ export default { sensorPhalanx: '주변 행성계의 함대 활동 감지', jumpGate: '다른 위성으로 함대 순간 이동', planetDestroyerFactory: '행성을 파괴할 수 있는 궁극 병기 건조', - geoResearchStation: '지질 구조를 연구하여 광맥 자연 회복 속도를 높입니다. 레벨당 회복 속도 50% 증가', - deepDrillingFacility: '' + geoResearchStation: '지질 구조를 연구하여 광맥 자연 회복 속도를 높입니다. 레벨당 회복 속도 10% 증가', + deepDrillingFacility: '', + university: '연구원을 양성하여 연구 속도를 가속합니다. 레벨당 연구 시간 -8%' }, ships: { lightFighter: '경전투기', @@ -276,7 +278,11 @@ export default { colonySlots: '식민지 슬롯', forAllPlanets: '(전역)', speedBonus: '속도 보너스', - researchSpeedBonus: '연구 속도 보너스' + researchSpeedBonus: '연구 속도 보너스', + // 자원 생산 보너스 표시 + mineralResearch: '광물 연구', + crystalResearch: '크리스탈 연구', + fuelResearch: '연료 연구' }, technologies: { energyTechnology: '에너지 기술', @@ -297,7 +303,11 @@ export default { darkMatterTechnology: '암흑 물질 기술', terraformingTechnology: '지형 변환 기술', planetDestructionTech: '행성 파괴 기술', - miningTechnology: '' + miningTechnology: '', + intergalacticResearchNetwork: '은하간 연구 네트워크', + mineralResearch: '광물 연구', + crystalResearch: '크리스탈 연구', + fuelResearch: '연료 연구' }, technologyDescriptions: { energyTechnology: '에너지 이용 효율 향상', @@ -319,7 +329,11 @@ export default { darkMatterTechnology: '암흑 물질의 성질과 응용 연구', terraformingTechnology: '행성 지형 개조 기술 연구, 레벨당 모든 행성의 가용 공간 30 증가', planetDestructionTech: '행성 전체를 파괴하는 공포의 기술 연구', - miningTechnology: '' + miningTechnology: '', + intergalacticResearchNetwork: '여러 행성의 연구소를 연결합니다. 레벨당 1개 추가 연구소 연결', + mineralResearch: '더 효율적인 금속 추출 기술 연구. 레벨당 금속 생산 +2%', + crystalResearch: '더 효율적인 크리스탈 정제 기술 연구. 레벨당 크리스탈 생산 +2%', + fuelResearch: '더 효율적인 중수소 합성 기술 연구. 레벨당 중수소 생산 +2%' }, officers: { commander: '사령관', @@ -910,7 +924,10 @@ export default { hideRoundDetails: '라운드 상세 숨기기', round: '제 {round} 라운드', attackerRemainingPower: '공격자 잔여 화력', - defenderRemainingPower: '방어자 잔여 화력' + defenderRemainingPower: '방어자 잔여 화력', + importFromSpyReport: '정찰 보고서에서 가져오기', + selectSpyReport: '정찰 보고서 선택', + noSpyReports: '정찰 보고서가 없습니다' }, settings: { dataManagement: '데이터 관리', @@ -921,6 +938,7 @@ export default { exporting: '내보내는 중...', exportSuccess: '내보내기 성공', exportSuccessWithPath: '내보내기 성공, 파일 저장 위치: {path}', + storagePermissionDenied: '저장소 권한이 거부되어 파일을 내보낼 수 없습니다', exportFailed: '내보내기 실패, 다시 시도해주세요', importData: '데이터 가져오기', importDataDesc: 'JSON 파일에서 게임 진행 상황 복원', @@ -938,6 +956,8 @@ export default { gameSettingsDesc: '게임 매개변수 및 설정 조정', gamePause: '게임 일시정지', gamePauseDesc: '게임 시간 및 자원 생산 일시정지 또는 재개', + battleMode: '끝까지 싸우기 모드', + battleModeDesc: '활성화하면 승자가 결정될 때까지 최대 100라운드까지 전투가 진행됩니다. 비활성화하면 클래식 6라운드 모드가 사용됩니다', pause: '일시정지', resume: '재개', gamePaused: '게임이 일시정지되었습니다', @@ -1936,13 +1956,19 @@ export default { questNotActive: '퀘스트가 활성화되지 않았습니다', questNotCompleted: '퀘스트 미완료', rewardsAlreadyClaimed: '이미 보상을 받았습니다', - prerequisiteNotMet: '선행 퀘스트 미완료' + prerequisiteNotMet: '선행 퀘스트 미완료', + questLocked: '퀘스트가 잠겨 있습니다', + notInitialized: '캠페인이 초기화되지 않았습니다', + questAlreadyCompleted: '퀘스트가 이미 완료되었습니다' }, speakers: { ancientVoice: '고대의 목소리', neighborNPC: '인접 세력', mysteriousSignal: '신비한 신호', - enemyCommander: '적 사령관' + enemyCommander: '적 사령관', + shadowVoice: '그림자의 목소리', + allyNPC: '동맹 세력', + ancientGuardian: '고대의 수호자' }, objectiveDescriptions: { buildMetalMine: '금속 광산을 레벨 2로 건설', @@ -2023,38 +2049,60 @@ export default { }, '2_3': { prologue_1: '탐험에서 이상한 신호를 발견했습니다. 이 신호들은 고대 문명에서 온 것 같습니다... 출처를 조사하세요.', + prologue_2: '이 신호들... 잃어버린 문명의 메아리를 담고 있다. 그들의 비밀이 발견을 기다리고 있다...', epilogue_1: '이 기호들은... 고대 문명의 유적이다! 계속 조사하여 비밀을 밝히세요.' }, - '2_4': { prologue_1: '고대 유적의 위치를 발견했습니다. 함대를 보내 무엇을 발견할 수 있는지 탐험하세요.' }, - '2_5': { prologue_1: '유적에서 데이터 아카이브가 발견되었습니다. 이 데이터를 연구하면 새 기술을 해금할 수 있을지도 모릅니다.' }, + '2_4': { + prologue_1: '고대 유적의 위치를 발견했습니다. 함대를 보내 무엇을 발견할 수 있는지 탐험하세요.', + prologue_2: '유적에는 많은 비밀이 있다... 현명하게 길을 선택하라...', + choice_1: '신중하게 탐험 - 안전 우선', + choice_2: '적극적으로 탐험 - 발견 우선' + }, + '2_5': { + prologue_1: '유적에서 데이터 아카이브가 발견되었습니다. 이 데이터를 연구하면 새 기술을 해금할 수 있을지도 모릅니다.', + epilogue_1: '고대 데이터가 해독되었습니다! 새로운 기술적 통찰을 얻었습니다.' + }, '3_1': { prologue_1: '탐험 중에도 외교를 잊지 마세요. 주변 세력과 좋은 관계를 유지하는 것이 유익합니다.' }, '3_2': { prologue_1: '일부 세력이 우호를 보이고 있습니다. 관계를 계속 깊게 하면 더 많은 지원을 받을 수 있을지도 모릅니다.' }, '3_3': { - prologue_1: '정보에 따르면 적대 세력이 그림자에서 당신을 감시하고 있습니다. 경계를 늦추지 말고 그들의 움직임을 정찰하세요.' + prologue_1: '정보에 따르면 적대 세력이 그림자에서 당신을 감시하고 있습니다. 경계를 늦추지 말고 그들의 움직임을 정찰하세요.', + prologue_2: '어둠의 힘이 허공에서 움직이고 있다... 그들은 당신의 성장하는 힘을 알아챘다...' }, '3_4': { prologue_1: '우호 세력과 공식 동맹을 맺어 위협에 대해 서로를 지원하세요.' }, - '3_5': { prologue_1: '위협이 다가오고 있습니다. 방어 시설을 건설하고 가능한 충돌에 대비하세요.' }, + '3_5': { + prologue_1: '위협이 다가오고 있습니다. 방어 시설을 건설하고 가능한 충돌에 대비하세요.', + epilogue_1: '방어 준비가 완료되었습니다. 폭풍이 오지만, 당신은 준비가 되어 있습니다.' + }, '4_1': { prologue_1: '적이 공격을 시작했습니다! 행성을 방어하세요!', + prologue_2: '그림자 함대가 다가온다... 당신의 시련의 시간이 왔다...', epilogue_1: '적의 첫 번째 파도를 성공적으로 격퇴했습니다. 하지만 이것은 시작에 불과합니다...' }, '4_2': { prologue_1: '적이 후퇴했지만 돌아올 것입니다. 그들의 행성을 정찰하여 전력을 파악하세요.' }, '4_3': { prologue_1: '반격할 시간입니다. 적 행성을 공격하여 그들의 전력을 약화시키세요.' }, '4_4': { prologue_1: '전장에 많은 잔해가 남아 있습니다. 이 자원을 재활용하여 다음 전투에 대비하세요.' }, - '4_5': { prologue_1: '최종 전투가 다가오고 있습니다. 강력한 함대를 건조하고 궁극의 도전에 대비하세요.' }, + '4_5': { + prologue_1: '최종 전투가 다가오고 있습니다. 강력한 함대를 건조하고 궁극의 도전에 대비하세요.', + epilogue_1: '함대가 집결했습니다. 결전의 시간이 다가온다...' + }, '5_1': { prologue_1: '모든 단서가 유적의 가장 깊은 곳을 가리킵니다. 고대 문명의 핵심 비밀이 그곳에 있습니다.', prologue_2: '드디어 도착했다... 진실이 곧 밝혀질 것이다...' }, - '5_2': { prologue_1: '유적 깊은 곳에서 잃어버린 고대 기술을 발견했습니다. 연구하여 그 힘을 해방하세요.' }, + '5_2': { + prologue_1: '유적 깊은 곳에서 잃어버린 고대 기술을 발견했습니다. 연구하여 그 힘을 해방하세요.', + prologue_2: '이 기술은... 알려진 모든 문명보다 오래되었다. 신중하게 다루어라...' + }, '5_3': { prologue_1: '신비한 적이 나타났습니다. 이것이 마지막 도전입니다. 격파하세요!', + prologue_2: '나는 이 비밀들의 수호자다. 네 가치를 증명하라, 그렇지 않으면 멸망하라!', epilogue_1: '해냈습니다! 고대의 수호자가 쓰러졌습니다. 은하의 비밀이 이제 당신에게 열려 있습니다.' }, '5_4': { prologue_1: '마침내 평화가 찾아왔습니다. 이 새 시대에 새 식민지를 세우고 제국을 확장하세요.' }, '5_5': { prologue_1: '당신의 전설은 이제 막 시작되었습니다. 계속 탐험하고 더 많은 성계를 정복하세요!', - epilogue_1: '은하는 광대하고 끝이 없으며, 셀 수 없는 비밀이 당신을 기다리고 있습니다...' + epilogue_1: '은하는 광대하고 끝이 없으며, 셀 수 없는 비밀이 당신을 기다리고 있습니다...', + epilogue_2: '당신의 여정은 계속된다... 새로운 모험이 별 너머에서 기다리고 있다...' } } } diff --git a/src/locales/ru.ts b/src/locales/ru.ts index 3c2f2ea..9fd7a2a 100644 --- a/src/locales/ru.ts +++ b/src/locales/ru.ts @@ -154,6 +154,7 @@ export default { planetDestroyerFactory: 'Фабрика разрушителей планет', geoResearchStation: 'Геологическая станция', deepDrillingFacility: 'Глубинная буровая установка', + university: 'Университет', buildTime: 'Время строительства', build: 'Построить', production: 'Производство', @@ -205,8 +206,9 @@ export default { jumpGate: 'Мгновенно переносит флоты на другие луны', planetDestroyerFactory: 'Производит абсолютное оружие, способное уничтожать планеты', geoResearchStation: - 'Исследует геологическую структуру и повышает скорость восстановления рудных месторождений. +50% скорости восстановления за уровень', - deepDrillingFacility: '' + 'Исследует геологическую структуру и повышает скорость восстановления рудных месторождений. +10% скорости восстановления за уровень', + deepDrillingFacility: '', + university: 'Обучает исследователей для ускорения исследований. -8% времени исследования за уровень' }, ships: { lightFighter: 'Лёгкий истребитель', @@ -288,7 +290,11 @@ export default { researchQueueBonus: 'Очередь исследований', colonySlots: 'Слоты колоний', forAllPlanets: '(Глобально)', - speedBonus: 'Бонус скорости' + speedBonus: 'Бонус скорости', + // Отображение бонуса производства ресурсов + mineralResearch: 'Минеральные исследования', + crystalResearch: 'Кристаллические исследования', + fuelResearch: 'Топливные исследования' }, technologies: { energyTechnology: 'Энергетическая технология', @@ -309,7 +315,11 @@ export default { darkMatterTechnology: 'Технология тёмной материи', terraformingTechnology: 'Технология терраформирования', planetDestructionTech: 'Технология уничтожения планет', - miningTechnology: '' + miningTechnology: '', + intergalacticResearchNetwork: 'Межгалактическая исследовательская сеть', + mineralResearch: 'Исследование минералов', + crystalResearch: 'Исследование кристаллов', + fuelResearch: 'Исследование топлива' }, technologyDescriptions: { energyTechnology: 'Улучшает энергоэффективность', @@ -332,7 +342,11 @@ export default { terraformingTechnology: 'Исследование технологии терраформирования планет, увеличивает доступное пространство всех планет на 30 за уровень', planetDestructionTech: 'Исследование ужасающей технологии уничтожения целых планет', - miningTechnology: '' + miningTechnology: '', + intergalacticResearchNetwork: 'Связывает несколько исследовательских лабораторий на разных планетах. Каждый уровень подключает 1 дополнительную лабораторию', + mineralResearch: 'Исследование более эффективных методов добычи металла. +2% производства металла за уровень', + crystalResearch: 'Исследование более эффективных методов обработки кристаллов. +2% производства кристаллов за уровень', + fuelResearch: 'Исследование более эффективных методов синтеза дейтерия. +2% производства дейтерия за уровень' }, officers: { commander: 'Командир', @@ -933,7 +947,10 @@ export default { hideRoundDetails: 'Скрыть детали раундов', round: 'Раунд {round}', attackerRemainingPower: 'Оставшаяся мощь нападающего', - defenderRemainingPower: 'Оставшаяся мощь защитника' + defenderRemainingPower: 'Оставшаяся мощь защитника', + importFromSpyReport: 'Импорт из шпионского отчета', + selectSpyReport: 'Выбрать шпионский отчет', + noSpyReports: 'Нет шпионских отчетов' }, settings: { dataManagement: 'Управление данными', @@ -944,6 +961,7 @@ export default { exporting: 'Экспорт...', exportSuccess: 'Экспорт успешен', exportSuccessWithPath: 'Экспорт успешен, файл сохранен в: {path}', + storagePermissionDenied: 'Разрешение на хранение отклонено, невозможно экспортировать файл', exportFailed: 'Экспорт не удался, попробуйте еще раз', importData: 'Импорт данных', importDataDesc: 'Восстановить прогресс игры из JSON файла', @@ -961,6 +979,8 @@ export default { gameSettingsDesc: 'Настроить параметры и предпочтения игры', gamePause: 'Пауза игры', gamePauseDesc: 'Приостановить или возобновить игровое время и производство ресурсов', + battleMode: 'Режим боя до конца', + battleModeDesc: 'При включении бои длятся до 100 раундов до определения победителя. При выключении используется классический режим 6 раундов', pause: 'Пауза', resume: 'Возобновить', gamePaused: 'Игра приостановлена', @@ -1993,13 +2013,19 @@ export default { questNotActive: 'Квест не активен', questNotCompleted: 'Квест не завершён', rewardsAlreadyClaimed: 'Награды уже получены', - prerequisiteNotMet: 'Предварительный квест не завершён' + prerequisiteNotMet: 'Предварительный квест не завершён', + questLocked: 'Квест заблокирован', + notInitialized: 'Кампания не инициализирована', + questAlreadyCompleted: 'Квест уже завершён' }, speakers: { ancientVoice: 'Древний голос', neighborNPC: 'Соседняя фракция', mysteriousSignal: 'Загадочный сигнал', - enemyCommander: 'Вражеский командир' + enemyCommander: 'Вражеский командир', + shadowVoice: 'Голос тени', + allyNPC: 'Союзная фракция', + ancientGuardian: 'Древний страж' }, objectiveDescriptions: { buildMetalMine: 'Построить Металлургический завод до уровня 2', @@ -2089,12 +2115,19 @@ export default { '2_3': { prologue_1: 'Ваша экспедиция обнаружила аномальные сигналы. Эти сигналы, похоже, исходят от древней цивилизации... Исследуйте их источник.', + prologue_2: 'Эти сигналы... Они несут отголоски исчезнувшей цивилизации. Их тайны ждут открытия...', epilogue_1: 'Эти символы... Это руины древней цивилизации! Продолжайте исследование, чтобы раскрыть их тайны.' }, '2_4': { - prologue_1: 'Вы нашли местоположение древних руин. Отправьте свой флот на исследование и посмотрите, что вы можете обнаружить.' + prologue_1: 'Вы нашли местоположение древних руин. Отправьте свой флот на исследование и посмотрите, что вы можете обнаружить.', + prologue_2: 'В руинах скрыто много тайн... Выбирайте путь мудро...', + choice_1: 'Исследовать осторожно - приоритет безопасности', + choice_2: 'Исследовать агрессивно - приоритет открытий' + }, + '2_5': { + prologue_1: 'В руинах найдены архивы данных. Изучите эти данные, возможно, вы сможете разблокировать новую технологию.', + epilogue_1: 'Древние данные расшифрованы! Получены новые технологические знания.' }, - '2_5': { prologue_1: 'В руинах найдены архивы данных. Изучите эти данные, возможно, вы сможете разблокировать новую технологию.' }, '3_1': { prologue_1: 'Во время исследований не забывайте о дипломатии. Поддержание хороших отношений с окружающими фракциями выгодно.' }, @@ -2103,31 +2136,44 @@ export default { }, '3_3': { prologue_1: - 'Разведка показывает, что враждебные силы наблюдают за вами из тени. Оставайтесь бдительными и разведайте их перемещения.' + 'Разведка показывает, что враждебные силы наблюдают за вами из тени. Оставайтесь бдительными и разведайте их перемещения.', + prologue_2: 'Тёмные силы шевелятся в пустоте... Они заметили вашу растущую мощь...' }, '3_4': { prologue_1: 'Заключите официальный альянс с дружественными фракциями для взаимной поддержки против угроз.' }, - '3_5': { prologue_1: 'Угрозы приближаются. Постройте оборонительные сооружения и подготовьтесь к возможному конфликту.' }, + '3_5': { + prologue_1: 'Угрозы приближаются. Постройте оборонительные сооружения и подготовьтесь к возможному конфликту.', + epilogue_1: 'Ваша оборона готова. Буря надвигается, но вы подготовлены.' + }, '4_1': { prologue_1: 'Враг начал атаку! Защитите свою планету!', + prologue_2: 'Теневой флот приближается... Час твоего испытания настал...', epilogue_1: 'Вы успешно отбили первую волну врага. Но это только начало...' }, '4_2': { prologue_1: 'Враг отступил, но он вернётся. Разведайте их планеты, чтобы понять их силу.' }, '4_3': { prologue_1: 'Пора контратаковать. Атакуйте вражеские планеты и ослабьте их силы.' }, '4_4': { prologue_1: 'На поле боя осталось много обломков. Переработайте эти ресурсы для подготовки к следующей битве.' }, - '4_5': { prologue_1: 'Финальная битва приближается. Постройте мощный флот и приготовьтесь к конечному испытанию.' }, + '4_5': { + prologue_1: 'Финальная битва приближается. Постройте мощный флот и приготовьтесь к конечному испытанию.', + epilogue_1: 'Ваш флот собран. Решающий момент приближается...' + }, '5_1': { prologue_1: 'Все улики указывают на самую глубокую часть руин. Ключевые тайны древней цивилизации находятся там.', prologue_2: 'Ты наконец прибыл... Истина скоро откроется...' }, - '5_2': { prologue_1: 'В глубинах руин вы обнаружили утерянные древние технологии. Исследуйте и разблокируйте их мощь.' }, + '5_2': { + prologue_1: 'В глубинах руин вы обнаружили утерянные древние технологии. Исследуйте и разблокируйте их мощь.', + prologue_2: 'Эта технология... Она древнее всех известных цивилизаций. Обращайтесь с ней осторожно...' + }, '5_3': { prologue_1: 'Появился загадочный враг. Это финальное испытание. Победите его!', + prologue_2: 'Я — страж этих тайн. Докажи свою ценность или будешь уничтожен!', epilogue_1: 'Вы справились! Древний страж повержен. Тайны галактики теперь открыты для вас.' }, '5_4': { prologue_1: 'Мир наконец наступил. В эту новую эру основывайте новые колонии и расширяйте свою империю.' }, '5_5': { prologue_1: 'Ваша легенда только началась. Продолжайте исследовать и завоёвывать больше звёздных систем!', - epilogue_1: 'Галактика необъятна и бесконечна, бесчисленные тайны ждут вас...' + epilogue_1: 'Галактика необъятна и бесконечна, бесчисленные тайны ждут вас...', + epilogue_2: 'Ваше путешествие продолжается... Новые приключения ждут за звёздами...' } } } diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 926671b..7daf3c1 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -48,6 +48,8 @@ export default { launchFailed: '发射失败', fleetMissionsFull: '舰队任务槽位已满', insufficientFleet: '舰队数量不足', + insufficientShips: '舰船数量不足', + invalidQuantity: '无效数量', insufficientFuel: '燃料不足', planetOnly: '该建筑只能在行星上建造', moonOnly: '该建筑只能在月球上建造', @@ -56,7 +58,12 @@ export default { buildingLevelZero: '建筑等级为0,无法拆除', researchQueueFull: '研究队列已满', moonExists: '已存在月球', - insufficientDebris: '残骸场不足' + insufficientDebris: '残骸场不足', + planetNotFound: '找不到星球', + cannotAbandonHomePlanet: '不能放弃母星', + hasBuildQueue: '请等待建造队列完成', + hasFleetOnPlanet: '请先转移或拆除所有舰船', + hasDefenseOnPlanet: '请先拆除所有防御设施' }, nav: { overview: '总览', @@ -124,7 +131,12 @@ export default { renamePlanet: '重命名星球', renamePlanetTitle: '重命名星球', planetNamePlaceholder: '输入新的星球名称', - rename: '重命名' + rename: '重命名', + abandonColony: '放弃殖民地', + confirmAbandon: '确认放弃殖民地', + abandonWarning: '确定要放弃 "{name}" 吗?\n\n此操作无法撤销!\n所有建筑、资源和月球(如有)都将丢失。', + confirmAbandonButton: '放弃', + abandonFailed: '放弃失败' }, player: { points: '总积分' @@ -153,6 +165,7 @@ export default { planetDestroyerFactory: '行星毁灭者工厂', geoResearchStation: '地质研究站', deepDrillingFacility: '深层钻探设施', + university: '大学', buildTime: '建造时间', production: '产量', consumption: '消耗', @@ -200,8 +213,9 @@ export default { sensorPhalanx: '侦测周围星系的舰队活动', jumpGate: '瞬间传送舰队到其他月球', planetDestroyerFactory: '建造能够摧毁行星的终极武器', - geoResearchStation: '研究地质结构,提高矿脉自然恢复速度。每级增加50%恢复速率', - deepDrillingFacility: '深入地壳钻探,解锁更深层的矿脉储量。每级增加20%矿脉上限' + geoResearchStation: '研究地质结构,提高矿脉自然恢复速度。每级增加10%恢复速率', + deepDrillingFacility: '深入地壳钻探,解锁更深层的矿脉储量。每级增加20%矿脉上限', + university: '培养科研人员,加快研究速度。每级减少研究时间8%(与星际研究网络叠加)' }, ships: { lightFighter: '轻型战斗机', @@ -276,7 +290,11 @@ export default { researchQueueBonus: '研究队列', colonySlots: '殖民地槽位', forAllPlanets: '(全局)', - speedBonus: '速度加成' + speedBonus: '速度加成', + // 资源产量加成显示 + mineralResearch: '矿物研究', + crystalResearch: '晶体研究', + fuelResearch: '燃料研究' }, technologies: { energyTechnology: '能源技术', @@ -297,7 +315,11 @@ export default { darkMatterTechnology: '暗物质技术', terraformingTechnology: '地形改造技术', planetDestructionTech: '行星毁灭技术', - miningTechnology: '采矿技术' + miningTechnology: '采矿技术', + intergalacticResearchNetwork: '星际研究网络', + mineralResearch: '矿物研究', + crystalResearch: '晶体研究', + fuelResearch: '燃料研究' }, technologyDescriptions: { energyTechnology: '提高能源利用效率', @@ -319,7 +341,11 @@ export default { darkMatterTechnology: '研究暗物质的性质和应用', terraformingTechnology: '研究行星地形改造技术,每级为所有行星增加30个可用空间', planetDestructionTech: '研究如何摧毁整个行星的恐怖技术', - miningTechnology: '改进采矿方法和设备,提升所有星球矿脉储量上限。每级增加15%矿脉上限' + miningTechnology: '改进采矿方法和设备,提升所有星球矿脉储量上限。每级增加15%矿脉上限', + intergalacticResearchNetwork: '连接多个星球的研究实验室,共享研究资源。每级可连接1个额外的研究实验室(取等级最高的N个实验室)', + mineralResearch: '研究更高效的金属提取技术,提升金属矿产量。每级增加金属产量2%', + crystalResearch: '研究更高效的晶体提炼技术,提升晶体矿产量。每级增加晶体产量2%', + fuelResearch: '研究更高效的重氢合成技术,提升重氢产量。每级增加重氢产量2%' }, officers: { commander: '指挥官', @@ -437,7 +463,12 @@ export default { inputError: '输入错误', inputErrorMessage: '请输入建造数量!', buildFailed: '建造失败', - buildFailedMessage: '请检查资源是否足够或前置条件是否满足。' + buildFailedMessage: '请检查资源是否足够或前置条件是否满足。', + scrapQuantity: '拆除数量', + scrapRefund: '拆除返还 (50%)', + scrap: '拆除', + scrapFailed: '拆除失败', + scrapFailedMessage: '请检查舰船数量是否足够。' }, defense: { attack: '攻击力', @@ -859,14 +890,14 @@ export default { missileAttackFailed: '导弹攻击失败,目标星球不存在', missileAttackIntercepted: '所有导弹被拦截', hits: '枚命中', - expeditionResources: '远征队发现了资源!', - expeditionDarkMatter: '远征队发现了暗物质!', - expeditionFleet: '远征队发现了废弃的舰船!', - expeditionPiratesAttack: '远征队遭遇海盗袭击,损失了部分舰船', - expeditionPiratesEscaped: '远征队遭遇海盗,但成功逃脱', - expeditionAliensAttack: '远征队遭遇外星人袭击,损失了部分舰船', - expeditionAliensEscaped: '远征队遭遇外星人,但成功逃脱', - expeditionNothing: '远征队什么也没有发现' + expeditionResources: '探险队发现了资源!', + expeditionDarkMatter: '探险队发现了暗物质!', + expeditionFleet: '探险队发现了废弃的舰船!', + expeditionPiratesAttack: '探险队遭遇海盗袭击,损失了部分舰船', + expeditionPiratesEscaped: '探险队遭遇海盗,但成功逃脱', + expeditionAliensAttack: '探险队遭遇外星人袭击,损失了部分舰船', + expeditionAliensEscaped: '探险队遭遇外星人,但成功逃脱', + expeditionNothing: '探险队什么也没有发现' }, simulatorView: { title: '战斗模拟器', @@ -903,7 +934,10 @@ export default { hideRoundDetails: '隐藏回合详情', round: '第 {round} 回合', attackerRemainingPower: '攻击方剩余火力', - defenderRemainingPower: '防守方剩余火力' + defenderRemainingPower: '防守方剩余火力', + importFromSpyReport: '从侦查报告导入', + selectSpyReport: '选择侦查报告', + noSpyReports: '没有侦查报告' }, settings: { dataManagement: '数据管理', @@ -914,6 +948,7 @@ export default { exporting: '导出中...', exportSuccess: '导出成功', exportSuccessWithPath: '导出成功,文件已保存到:{path}', + storagePermissionDenied: '存储权限被拒绝,无法导出文件', exportFailed: '导出失败,请重试', importData: '导入数据', importDataDesc: '从JSON文件恢复游戏进度', @@ -931,6 +966,8 @@ export default { gameSettingsDesc: '调整游戏参数和偏好设置', gamePause: '游戏暂停', gamePauseDesc: '暂停或恢复游戏时间和资源生产', + battleMode: '战斗到底模式', + battleModeDesc: '启用后战斗最多进行100回合直到分出胜负,关闭则使用经典6回合模式', pause: '暂停', resume: '恢复', gamePaused: '游戏已暂停', @@ -1738,8 +1775,8 @@ export default { colonizer: '成功殖民星球次数', spy: '执行侦查任务次数', deployer: '执行部署任务次数', - explorer: '远征总次数', - luckyExplorer: '远征成功次数', + explorer: '探险总次数', + luckyExplorer: '探险成功次数', recycler: '回收任务次数', scavenger: '回收资源总量', destroyer: '摧毁星球次数', @@ -1867,7 +1904,7 @@ export default { }, '2_2': { title: '深空探险', - description: '派遣舰队进行远征探险' + description: '派遣舰队进行探险探险' }, '2_3': { title: '神秘信号', @@ -1963,13 +2000,19 @@ export default { questNotActive: '任务未激活', questNotCompleted: '任务未完成', rewardsAlreadyClaimed: '奖励已领取', - prerequisiteNotMet: '前置任务未完成' + prerequisiteNotMet: '前置任务未完成', + questLocked: '任务已锁定', + notInitialized: '战役未初始化', + questAlreadyCompleted: '任务已完成' }, speakers: { ancientVoice: '古代之声', neighborNPC: '邻近势力', mysteriousSignal: '神秘信号', - enemyCommander: '敌方指挥官' + enemyCommander: '敌方指挥官', + shadowVoice: '暗影之声', + allyNPC: '盟友势力', + ancientGuardian: '远古守护者' }, objectiveDescriptions: { buildMetalMine: '建造金属矿到2级', @@ -1989,10 +2032,10 @@ export default { buildColonyShip: '建造殖民船', colonizeNewPlanet: '殖民新星球', colonizeMultiple: '殖民5个星球', - completeExpedition: '完成3次远征任务', - expeditionDeepSpace: '完成2次深空远征', + completeExpedition: '完成3次探险任务', + expeditionDeepSpace: '完成2次深空探险', expeditionUncharted: '探索1次未知区域', - expeditionDangerous: '完成3次危险星云远征', + expeditionDangerous: '完成3次危险星云探险', discoverRuins: '发现古代遗迹', researchComputer: '研究电脑技术到4级', researchImpulse: '研究脉冲驱动到3级', @@ -2048,18 +2091,23 @@ export default { prologue_2: '宇宙是无限的...更多的星球意味着更多的可能性...' }, '2_2': { - prologue_1: '殖民成功!但宇宙深处还有更多秘密等待发现。派遣舰队进行远征探险吧。', + prologue_1: '殖民成功!但宇宙深处还有更多秘密等待发现。派遣舰队进行探险探险吧。', prologue_2: '远方传来微弱的信号...那里有什么在等待着你...' }, '2_3': { prologue_1: '你的探险队发现了异常信号。这些信号似乎来自一个古老的文明...调查它们的来源。', + prologue_2: '这些信号...承载着一个早已消逝的文明的回响。它们的秘密等待被发现...', epilogue_1: '这些符号...是古代文明的遗迹!继续调查,揭开它们的秘密。' }, '2_4': { - prologue_1: '你发现了古代遗迹的位置。派遣舰队前去探索,看看能发现什么。' + prologue_1: '你发现了古代遗迹的位置。派遣舰队前去探索,看看能发现什么。', + prologue_2: '遗迹中隐藏着许多秘密...明智地选择你的道路...', + choice_1: '谨慎探索 - 优先安全', + choice_2: '激进探索 - 优先发现' }, '2_5': { - prologue_1: '遗迹中发现了大量数据档案。研究这些数据,也许能解锁新的科技。' + prologue_1: '遗迹中发现了大量数据档案。研究这些数据,也许能解锁新的科技。', + epilogue_1: '古代数据已被解密!获得了新的科技洞见。' }, '3_1': { prologue_1: '在探索的同时,也不要忘记外交。与周围的势力保持良好关系对你有益。' @@ -2068,16 +2116,19 @@ export default { prologue_1: '有些势力对你表示了友好。继续加深关系,也许能获得更多支持。' }, '3_3': { - prologue_1: '情报显示,有敌对势力正在暗中观察你。保持警惕,侦查他们的动向。' + prologue_1: '情报显示,有敌对势力正在暗中观察你。保持警惕,侦查他们的动向。', + prologue_2: '黑暗势力在虚空中蠢蠢欲动...他们已经注意到你日益增长的力量...' }, '3_4': { prologue_1: '与友好势力建立正式同盟,在面对威胁时互相支持。' }, '3_5': { - prologue_1: '威胁正在逼近。建设防御设施,准备迎接可能的冲突。' + prologue_1: '威胁正在逼近。建设防御设施,准备迎接可能的冲突。', + epilogue_1: '你的防线已经准备就绪。风暴即将来临,但你已经做好了准备。' }, '4_1': { prologue_1: '敌人发动了进攻!保卫你的星球!', + prologue_2: '暗影舰队正在逼近...你的考验时刻已经到来...', epilogue_1: '你成功击退了敌人的第一波进攻。但这只是开始...' }, '4_2': { @@ -2090,17 +2141,20 @@ export default { prologue_1: '战场上留下了大量残骸。回收这些资源,为下一场战斗做准备。' }, '4_5': { - prologue_1: '最终决战即将来临。建造强大的舰队,准备迎接最后的挑战。' + prologue_1: '最终决战即将来临。建造强大的舰队,准备迎接最后的挑战。', + epilogue_1: '你的舰队已经集结完毕。决定性的时刻即将到来...' }, '5_1': { prologue_1: '所有线索都指向遗迹的最深处。那里隐藏着古代文明最核心的秘密。', prologue_2: '你终于来到了这里...真相即将揭晓...' }, '5_2': { - prologue_1: '在遗迹深处,你发现了失落的古代科技。研究并解锁它们的力量。' + prologue_1: '在遗迹深处,你发现了失落的古代科技。研究并解锁它们的力量。', + prologue_2: '这项科技...比所有已知文明都要古老。小心处理...' }, '5_3': { prologue_1: '一个神秘的敌人出现了。这是最后的挑战,击败它!', + prologue_2: '我是这些秘密的守护者。证明你的价值,否则将被毁灭!', epilogue_1: '你做到了!古代的守护者已被击败。银河系的秘密向你敞开。' }, '5_4': { @@ -2108,7 +2162,8 @@ export default { }, '5_5': { prologue_1: '你的传奇才刚刚开始。继续探索,征服更多的星系!', - epilogue_1: '银河系广阔无垠,还有无数秘密等待你去发现...' + epilogue_1: '银河系广阔无垠,还有无数秘密等待你去发现...', + epilogue_2: '你的旅程仍在继续...新的冒险在群星之外等待着你...' } } }, diff --git a/src/locales/zh-TW.ts b/src/locales/zh-TW.ts index e493462..5518fd3 100644 --- a/src/locales/zh-TW.ts +++ b/src/locales/zh-TW.ts @@ -155,6 +155,7 @@ export default { planetDestroyerFactory: '行星毀滅者工廠', geoResearchStation: '地質研究站', deepDrillingFacility: '深層鑽探設施', + university: '大學', buildTime: '建造時間', build: '建造', production: '產量', @@ -206,7 +207,8 @@ export default { jumpGate: '瞬間傳送艦隊到其他月球', planetDestroyerFactory: '建造能夠摧毀行星的終極武器', geoResearchStation: '研究地質結構,提高礦脈自然恢復速度。每級增加50%恢復速率', - deepDrillingFacility: '' + deepDrillingFacility: '', + university: '培養科研人員,加快研究速度。每級減少研究時間8%' }, ships: { lightFighter: '輕型戰鬥機', @@ -281,7 +283,11 @@ export default { researchQueueBonus: '研究隊列', colonySlots: '殖民地槽位', forAllPlanets: '(全局)', - speedBonus: '速度加成' + speedBonus: '速度加成', + // 資源產量加成顯示 + mineralResearch: '礦物研究', + crystalResearch: '晶體研究', + fuelResearch: '燃料研究' }, technologies: { energyTechnology: '能源技術', @@ -302,7 +308,11 @@ export default { darkMatterTechnology: '暗物質技術', terraformingTechnology: '地形改造技術', planetDestructionTech: '行星毀滅技術', - miningTechnology: '' + miningTechnology: '', + intergalacticResearchNetwork: '星際研究網絡', + mineralResearch: '礦物研究', + crystalResearch: '晶體研究', + fuelResearch: '燃料研究' }, technologyDescriptions: { energyTechnology: '提高能源利用效率', @@ -324,7 +334,11 @@ export default { darkMatterTechnology: '研究暗物質的性質和應用', terraformingTechnology: '研究行星地形改造技術,每級為所有行星增加30個可用空間', planetDestructionTech: '研究如何摧毀整個行星的恐怖技術', - miningTechnology: '' + miningTechnology: '', + intergalacticResearchNetwork: '連接多個星球的研究實驗室,共享研究資源。每級可連接1個額外的研究實驗室', + mineralResearch: '研究更高效的金屬提取技術,提升金屬礦產量。每級增加金屬產量2%', + crystalResearch: '研究更高效的晶體提煉技術,提升晶體礦產量。每級增加晶體產量2%', + fuelResearch: '研究更高效的重氫合成技術,提升重氫產量。每級增加重氫產量2%' }, officers: { commander: '指揮官', @@ -924,7 +938,10 @@ export default { hideRoundDetails: '隱藏回合詳情', round: '第 {round} 回合', attackerRemainingPower: '攻擊方剩餘火力', - defenderRemainingPower: '防守方剩餘火力' + defenderRemainingPower: '防守方剩餘火力', + importFromSpyReport: '從偵查報告匯入', + selectSpyReport: '選擇偵查報告', + noSpyReports: '沒有偵查報告' }, settings: { dataManagement: '資料管理', @@ -935,6 +952,7 @@ export default { exporting: '匯出中...', exportSuccess: '匯出成功', exportSuccessWithPath: '匯出成功,檔案已儲存到:{path}', + storagePermissionDenied: '儲存權限被拒絕,無法匯出檔案', exportFailed: '匯出失敗,請重試', importData: '匯入資料', importDataDesc: '從JSON檔案恢復遊戲進度', @@ -952,6 +970,8 @@ export default { gameSettingsDesc: '調整遊戲參數和偏好設定', gamePause: '遊戲暫停', gamePauseDesc: '暫停或恢復遊戲時間和資源生產', + battleMode: '戰鬥到底模式', + battleModeDesc: '啟用後戰鬥最多進行100回合直到分出勝負,關閉則使用經典6回合模式', pause: '暫停', resume: '恢復', gamePaused: '遊戲已暫停', @@ -2159,13 +2179,19 @@ export default { questNotActive: '任務未激活', questNotCompleted: '任務未完成', rewardsAlreadyClaimed: '獎勵已領取', - prerequisiteNotMet: '前置任務未完成' + prerequisiteNotMet: '前置任務未完成', + questLocked: '任務已鎖定', + notInitialized: '戰役未初始化', + questAlreadyCompleted: '任務已完成' }, speakers: { ancientVoice: '古代之聲', neighborNPC: '鄰近勢力', mysteriousSignal: '神秘信號', - enemyCommander: '敵方指揮官' + enemyCommander: '敵方指揮官', + shadowVoice: '暗影之聲', + allyNPC: '盟友勢力', + ancientGuardian: '遠古守護者' }, objectiveDescriptions: { buildMetalMine: '建造金屬礦到2級', @@ -2249,13 +2275,18 @@ export default { }, '2_3': { prologue_1: '你的探險隊發現了異常信號。這些信號似乎來自一個古老的文明...調查它們的來源。', + prologue_2: '這些信號...承載著失落文明的回響。它們的秘密等待被發現...', epilogue_1: '這些符號...是古代文明的遺跡!繼續調查,揭開它們的秘密。' }, '2_4': { - prologue_1: '你發現了古代遺跡的位置。派遣艦隊前去探索,看看能發現什麼。' + prologue_1: '你發現了古代遺跡的位置。派遣艦隊前去探索,看看能發現什麼。', + prologue_2: '遺跡中藏有許多秘密...明智地選擇你的道路...', + choice_1: '謹慎探索 - 優先安全', + choice_2: '積極探索 - 優先發現' }, '2_5': { - prologue_1: '遺跡中發現了大量數據檔案。研究這些數據,也許能解鎖新的科技。' + prologue_1: '遺跡中發現了大量數據檔案。研究這些數據,也許能解鎖新的科技。', + epilogue_1: '古代數據已被解密!獲得了新的技術見解。' }, '3_1': { prologue_1: '在探索的同時,也不要忘記外交。與周圍的勢力保持良好關係對你有益。' @@ -2264,16 +2295,19 @@ export default { prologue_1: '有些勢力對你表示了友好。繼續加深關係,也許能獲得更多支持。' }, '3_3': { - prologue_1: '情報顯示,有敵對勢力正在暗中觀察你。保持警惕,偵查他們的動向。' + prologue_1: '情報顯示,有敵對勢力正在暗中觀察你。保持警惕,偵查他們的動向。', + prologue_2: '黑暗勢力在虛空中蠢蠢欲動...他們已經注意到你日益增長的力量...' }, '3_4': { prologue_1: '與友好勢力建立正式同盟,在面對威脅時互相支持。' }, '3_5': { - prologue_1: '威脅正在逼近。建設防禦設施,準備迎接可能的衝突。' + prologue_1: '威脅正在逼近。建設防禦設施,準備迎接可能的衝突。', + epilogue_1: '你的防禦已經就緒。風暴即將來臨,但你已準備好了。' }, '4_1': { prologue_1: '敵人發動了進攻!保衛你的星球!', + prologue_2: '暗影艦隊正在逼近...你的考驗時刻已經到來...', epilogue_1: '你成功擊退了敵人的第一波進攻。但這只是開始...' }, '4_2': { @@ -2286,17 +2320,20 @@ export default { prologue_1: '戰場上留下了大量殘骸。回收這些資源,為下一場戰鬥做準備。' }, '4_5': { - prologue_1: '最終決戰即將來臨。建造強大的艦隊,準備迎接最後的挑戰。' + prologue_1: '最終決戰即將來臨。建造強大的艦隊,準備迎接最後的挑戰。', + epilogue_1: '你的艦隊已經集結完畢。決戰時刻即將來臨...' }, '5_1': { prologue_1: '所有線索都指向遺跡的最深處。那裡隱藏著古代文明最核心的秘密。', prologue_2: '你終於來到了這裡...真相即將揭曉...' }, '5_2': { - prologue_1: '在遺跡深處,你發現了失落的古代科技。研究並解鎖它們的力量。' + prologue_1: '在遺跡深處,你發現了失落的古代科技。研究並解鎖它們的力量。', + prologue_2: '這項科技...比所有已知文明都要古老。小心處理它...' }, '5_3': { prologue_1: '一個神秘的敵人出現了。這是最後的挑戰,擊敗它!', + prologue_2: '我是這些秘密的守護者。證明你的價值,否則將被毀滅!', epilogue_1: '你做到了!古代的守護者已被擊敗。銀河系的秘密向你敞開。' }, '5_4': { @@ -2304,7 +2341,8 @@ export default { }, '5_5': { prologue_1: '你的傳奇才剛剛開始。繼續探索,征服更多的星系!', - epilogue_1: '銀河系廣闘無垠,還有無數秘密等待你去發現...' + epilogue_1: '銀河系廣闘無垠,還有無數秘密等待你去發現...', + epilogue_2: '你的旅程還在繼續...新的冒險在星海彼岸等待著你...' } } } diff --git a/src/logic/battleLogic.ts b/src/logic/battleLogic.ts index 5c927f9..00159af 100644 --- a/src/logic/battleLogic.ts +++ b/src/logic/battleLogic.ts @@ -15,7 +15,8 @@ export const simulateBattle = async ( _attackerOfficers: Record, _defenderOfficers: Record, attackerTechnologies: Record, - defenderTechnologies: Record + defenderTechnologies: Record, + battleToFinish: boolean = false // 战斗到底模式 ): Promise => { // 从科技系统读取实际科技等级 const attackerWeaponTech = attackerTechnologies['weaponsTechnology'] || 0 @@ -41,7 +42,7 @@ export const simulateBattle = async ( shieldTech: defenderShieldTech, armorTech: defenderArmorTech }, - maxRounds: 6 // 最多6回合 + maxRounds: battleToFinish ? 100 : 6 // 战斗到底模式最多100回合,经典模式6回合 }) // 计算掠夺(仅攻击方胜利时) diff --git a/src/logic/buildingLogic.ts b/src/logic/buildingLogic.ts index 7c4fa48..3e547ab 100644 --- a/src/logic/buildingLogic.ts +++ b/src/logic/buildingLogic.ts @@ -23,30 +23,44 @@ export const calculateBuildingCost = (buildingType: BuildingType, targetLevel: n /** * 计算建筑升级时间 + * 使用 2moons 公式(调整版): + * 1. 成本系数 = Σ (资源^0.3 / 0.003) + * 2. 时间(秒) = 成本系数 / ((1 + 机器人工厂) × 2^纳米工厂 × 游戏速度) * @param buildingType 建筑类型 * @param targetLevel 目标等级 * @param buildingSpeedBonus 指挥官等提供的速度加成百分比 * @param roboticsFactoryLevel 机器人工厂等级 * @param naniteFactoryLevel 纳米工厂等级 + * @param gameSpeed 游戏速度(默认1) */ export const calculateBuildingTime = ( buildingType: BuildingType, targetLevel: number, buildingSpeedBonus: number = 0, roboticsFactoryLevel: number = 0, - naniteFactoryLevel: number = 0 + naniteFactoryLevel: number = 0, + gameSpeed: number = 1 ): number => { - const config = BUILDINGS[buildingType] - const multiplier = Math.pow(config.costMultiplier, targetLevel - 1) - const baseTime = config.baseTime * multiplier + // 计算该等级的成本 + const cost = calculateBuildingCost(buildingType, targetLevel) - // 机器人工厂和纳米工厂的加速:建造时间 / (1 + 机器人工厂等级 + 纳米工厂等级 × 2) - const factorySpeedDivisor = 1 + roboticsFactoryLevel + naniteFactoryLevel * 2 + // 2moons 公式:成本系数 = Σ (资源^0.3 / 0.003) + let elementCost = 0 + if (cost.metal > 0) elementCost += Math.pow(cost.metal, 0.3) / 0.003 + if (cost.crystal > 0) elementCost += Math.pow(cost.crystal, 0.3) / 0.003 + if (cost.deuterium > 0) elementCost += Math.pow(cost.deuterium, 0.3) / 0.003 + + // 机器人工厂和纳米工厂的加速 + const factoryBonus = (1 + roboticsFactoryLevel) * Math.pow(2, naniteFactoryLevel) + + // 简化公式:时间(秒) = 成本系数 / (工厂加成 × 游戏速度) + const timeInSeconds = elementCost / (factoryBonus * gameSpeed) // 指挥官等的百分比加成 const speedMultiplier = 1 - buildingSpeedBonus / 100 - return Math.floor((baseTime / factorySpeedDivisor) * speedMultiplier) + // 确保最小时间为5秒 + return Math.max(5, Math.floor(timeInSeconds * speedMultiplier)) } /** @@ -78,7 +92,16 @@ export const checkBuildingRequirements = ( for (const [key, level] of Object.entries(requirements)) { const requiredLevel = level as number if (Object.values(BuildingType).includes(key as BuildingType)) { - if ((planet.buildings[key as BuildingType] || 0) < requiredLevel) { + const requiredBuildingType = key as BuildingType + const requiredBuildingConfig = BUILDINGS[requiredBuildingType] + + // 如果当前是月球,且所需建筑是星球专属建筑(planetOnly),则跳过此前置条件 + // 这允许在月球上建造机器人工厂等建筑,即使它们的前置条件是无法在月球建造的矿场 + if (planet.isMoon && requiredBuildingConfig?.planetOnly) { + continue + } + + if ((planet.buildings[requiredBuildingType] || 0) < requiredLevel) { return false } } else if (Object.values(TechnologyType).includes(key as TechnologyType)) { @@ -168,6 +191,12 @@ export const completeBuildQueue = ( const buildingType = item.itemType as BuildingType const currentLevel = planet.buildings[buildingType] || 0 planet.buildings[buildingType] = Math.max(0, currentLevel - 1) + } else if (item.type === 'scrap_ship') { + // 舰船拆除完成,减少舰船数量(舰船已在开始拆除时扣除) + // 资源返还也在开始拆除时完成,这里不需要额外操作 + if (onCompleted) { + onCompleted('ship', item.itemType, undefined, item.quantity) + } } return false } diff --git a/src/logic/fleetLogic.ts b/src/logic/fleetLogic.ts index 1867a0b..9d67b3e 100644 --- a/src/logic/fleetLogic.ts +++ b/src/logic/fleetLogic.ts @@ -2,6 +2,7 @@ import type { FleetMission, Planet, Resources, Fleet, BattleResult, SpyReport, P import type { Locale } from '@/locales' import { ShipType, DefenseType, MissionType, BuildingType, OfficerType, TechnologyType, ExpeditionZone } from '@/types/game' import { FLEET_STORAGE_CONFIG, EXPEDITION_ZONES } from '@/config/gameConfig' +import { useGameStore } from '@/stores/gameStore' import * as battleLogic from './battleLogic' import * as moonLogic from './moonLogic' import * as moonValidation from './moonValidation' @@ -156,6 +157,7 @@ export const processAttackArrival = async ( } // 执行战斗(使用 Worker 进行异步计算) + const gameStore = useGameStore() const battleResult = await battleLogic.simulateBattle( mission.fleet, targetPlanet.fleet, @@ -164,7 +166,8 @@ export const processAttackArrival = async ( attacker.officers, defender?.officers || ({} as Record), attacker.technologies, - defender?.technologies || ({} as Record) + defender?.technologies || ({} as Record), + gameStore.battleToFinish ) // 更新战斗报告ID @@ -250,6 +253,7 @@ export const processNPCAttackArrival = async ( allPlanets: Planet[] ): Promise<{ battleResult: BattleResult; moon: Planet | null; debrisField: DebrisField | null } | null> => { // 执行战斗(使用 Worker 进行异步计算) + const gameStore = useGameStore() const battleResult = await battleLogic.simulateBattle( mission.fleet, // NPC舰队 targetPlanet.fleet, // 玩家舰队 @@ -258,7 +262,8 @@ export const processNPCAttackArrival = async ( {} as Record, // NPC没有军官系统 defender.officers || ({} as Record), // 玩家军官 npc.technologies, // NPC科技等级 - defender.technologies // 玩家科技等级 + defender.technologies, // 玩家科技等级 + gameStore.battleToFinish ) // 更新战斗报告ID和参与者信息 @@ -721,12 +726,12 @@ export const processRecycleArrival = ( } /** - * 远征事件类型 + * 探险事件类型 */ export type ExpeditionEventType = 'resources' | 'darkMatter' | 'fleet' | 'nothing' | 'pirates' | 'aliens' /** - * 远征结果 + * 探险结果 */ export interface ExpeditionResult { eventType: ExpeditionEventType @@ -737,8 +742,8 @@ export interface ExpeditionResult { } /** - * 处理远征任务到达 - * 远征任务会随机触发各种事件,基于探险区域配置 + * 处理探险任务到达 + * 探险任务会随机触发各种事件,基于探险区域配置 */ export const processExpeditionArrival = (mission: FleetMission): ExpeditionResult => { // 获取探险区域配置,默认为近空区域 @@ -968,9 +973,18 @@ export interface DestroyResult { deathstarDestructionChance: number // 死星反向销毁概率 isMoon: boolean // 目标是否为月球 failReason?: DestroyFailReason // 失败原因 + battleResult?: BattleResult // 战斗结果(如果发生了战斗) + debrisField?: DebrisField // 战斗产生的残骸场 + moon?: Planet // 战斗产生的月球 } -export const processDestroyArrival = (mission: FleetMission, targetPlanet: Planet | undefined, attacker: Player): DestroyResult => { +export const processDestroyArrival = async ( + mission: FleetMission, + targetPlanet: Planet | undefined, + attacker: Player, + defender: Player | null, + allPlanets: Planet[] +): Promise => { if (!targetPlanet) { mission.status = 'returning' return { @@ -995,8 +1009,8 @@ export const processDestroyArrival = (mission: FleetMission, targetPlanet: Plane } // 检查是否有死星 - const deathstarCount = mission.fleet[ShipType.Deathstar] || 0 - if (deathstarCount === 0) { + const initialDeathstarCount = mission.fleet[ShipType.Deathstar] || 0 + if (initialDeathstarCount === 0) { mission.status = 'returning' return { success: false, @@ -1008,10 +1022,113 @@ export const processDestroyArrival = (mission: FleetMission, targetPlanet: Plane } } + // 检查目标是否有防御力量(舰队或防御设施) + const hasDefenderFleet = Object.values(targetPlanet.fleet || {}).some(count => count > 0) + const hasDefense = Object.values(targetPlanet.defense || {}).some(count => count > 0) + const needsBattle = hasDefenderFleet || hasDefense + + let battleResult: BattleResult | undefined + let debrisField: DebrisField | undefined + let newMoon: Planet | undefined + let survivingDeathstars = initialDeathstarCount + + // 如果目标有防御力量,先进行战斗 + if (needsBattle) { + const gameStore = useGameStore() + + // 执行战斗 + battleResult = await battleLogic.simulateBattle( + mission.fleet, + targetPlanet.fleet, + targetPlanet.defense, + targetPlanet.resources, + attacker.officers, + defender?.officers || ({} as Record), + attacker.technologies, + defender?.technologies || ({} as Record), + gameStore.battleToFinish + ) + + // 更新战斗报告 + battleResult.id = `battle_${Date.now()}` + battleResult.attackerId = attacker.id + battleResult.defenderId = targetPlanet.ownerId || 'unknown' + battleResult.attackerPlanetId = mission.originPlanetId + battleResult.defenderPlanetId = targetPlanet.id + + // 更新舰队 - 计算幸存舰船 + const survivingFleet: Partial = {} + Object.entries(mission.fleet).forEach(([shipType, initialCount]) => { + const lost = battleResult!.attackerLosses[shipType as ShipType] || 0 + const surviving = initialCount - lost + if (surviving > 0) { + survivingFleet[shipType as ShipType] = surviving + } + }) + mission.fleet = survivingFleet + + // 计算存活的死星数量 + survivingDeathstars = survivingFleet[ShipType.Deathstar] || 0 + + // 更新目标星球舰队和防御 + Object.entries(battleResult.defenderLosses.fleet).forEach(([shipType, lost]) => { + const current = targetPlanet.fleet[shipType as ShipType] || 0 + targetPlanet.fleet[shipType as ShipType] = Math.max(0, current - lost) + }) + Object.entries(battleResult.defenderLosses.defense).forEach(([defenseType, lost]) => { + const current = targetPlanet.defense[defenseType as DefenseType] || 0 + targetPlanet.defense[defenseType as DefenseType] = Math.max(0, current - lost) + }) + + // 计算残骸场 + const debrisResources = battleResult.debrisField + if (debrisResources.metal > 0 || debrisResources.crystal > 0) { + debrisField = { + id: `debris_${targetPlanet.position.galaxy}_${targetPlanet.position.system}_${targetPlanet.position.position}`, + position: { ...targetPlanet.position }, + resources: { + metal: debrisResources.metal, + crystal: debrisResources.crystal + }, + createdAt: Date.now() + } + } + + // 检查是否生成月球(只有非月球位置才能生成月球) + if (!targetPlanet.isMoon && debrisField) { + const moonExists = moonLogic.hasMoonAtPosition(allPlanets, targetPlanet.position) + if (!moonExists) { + newMoon = + moonLogic.tryGenerateMoon( + { ...debrisResources, deuterium: 0, darkMatter: 0, energy: 0 }, + targetPlanet.position, + targetPlanet.id, + targetPlanet.ownerId || attacker.id + ) || undefined + } + } + + // 如果攻击方失败或没有存活的死星,直接返回 + if (battleResult.winner === 'defender' || survivingDeathstars === 0) { + mission.status = 'returning' + return { + success: false, + destructionChance: 0, + deathstarsLost: initialDeathstarCount > 0 && survivingDeathstars === 0, + deathstarDestructionChance: 0, + isMoon: targetPlanet.isMoon || false, + failReason: survivingDeathstars === 0 ? 'noDeathstar' : 'chanceFailed', + battleResult, + debrisField, + moon: newMoon + } + } + } + // 根据目标类型使用不同的销毁逻辑 if (targetPlanet.isMoon) { // 月球销毁使用 OGame 公式 - const result = moonLogic.tryDestroyMoon(targetPlanet, deathstarCount) + const result = moonLogic.tryDestroyMoon(targetPlanet, survivingDeathstars) // 如果死星被反向销毁,从任务舰队中移除 if (result.deathstarsDestroyed) { @@ -1027,13 +1144,16 @@ export const processDestroyArrival = (mission: FleetMission, targetPlanet: Plane deathstarsLost: result.deathstarsDestroyed, deathstarDestructionChance: result.deathstarDestructionChance, isMoon: true, - failReason: result.moonDestroyed ? undefined : 'chanceFailed' + failReason: result.moonDestroyed ? undefined : 'chanceFailed', + battleResult, + debrisField, + moon: newMoon } } else { - // 行星销毁使用原有逻辑 + // 行星销毁使用原有逻辑(基于存活的死星数量) const planetaryShieldCount = targetPlanet.defense[DefenseType.PlanetaryShield] || 0 const defensePower = calculatePlanetDefensePower(targetPlanet.fleet, targetPlanet.defense) - const destructionChance = calculateDestructionChance(deathstarCount, planetaryShieldCount, defensePower) + const destructionChance = calculateDestructionChance(survivingDeathstars, planetaryShieldCount, defensePower) const randomValue = Math.random() * 100 const success = randomValue < destructionChance @@ -1047,7 +1167,10 @@ export const processDestroyArrival = (mission: FleetMission, targetPlanet: Plane deathstarsLost: false, deathstarDestructionChance: 0, isMoon: false, - failReason: success ? undefined : 'chanceFailed' + failReason: success ? undefined : 'chanceFailed', + battleResult, + debrisField, + moon: newMoon } } } @@ -1200,8 +1323,40 @@ export const updateFleetMissions = async ( } break - case MissionType.Destroy: - const destroyResult = processDestroyArrival(mission, targetPlanet, attacker) + case MissionType.Destroy: { + const destroyResult = await processDestroyArrival(mission, targetPlanet, attacker, defender, allPlanets) + + // 处理战斗报告 + if (destroyResult.battleResult) { + battleReports.push(destroyResult.battleResult) + } + + // 处理新生成的月球 + if (destroyResult.moon) { + newMoons.push(destroyResult.moon) + const moonKey = `${destroyResult.moon.position.galaxy}:${destroyResult.moon.position.system}:${destroyResult.moon.position.position}` + planets.set(moonKey, destroyResult.moon) + } + + // 处理残骸场 + if (destroyResult.debrisField) { + const existingDebris = debrisFields.get(destroyResult.debrisField.id) + if (existingDebris) { + const updatedDebris: DebrisField = { + ...existingDebris, + resources: { + metal: existingDebris.resources.metal + destroyResult.debrisField.resources.metal, + crystal: existingDebris.resources.crystal + destroyResult.debrisField.resources.crystal + } + } + debrisFields.set(destroyResult.debrisField.id, updatedDebris) + updatedDebrisFields.push(updatedDebris) + } else { + debrisFields.set(destroyResult.debrisField.id, destroyResult.debrisField) + newDebrisFields.push(destroyResult.debrisField) + } + } + if (destroyResult.success && destroyResult.planetId) { // 星球被摧毁 destroyedPlanetIds.push(destroyResult.planetId) @@ -1217,6 +1372,7 @@ export const updateFleetMissions = async ( planets.delete(targetKey) } break + } } } diff --git a/src/logic/gameLogic.ts b/src/logic/gameLogic.ts index d9bec39..fcaa805 100644 --- a/src/logic/gameLogic.ts +++ b/src/logic/gameLogic.ts @@ -150,11 +150,20 @@ export const processGameUpdate = ( } // 更新所有星球资源(直接同步计算,避免 Worker 通信开销) + // 获取采矿技术等级(用于矿脉恢复上限计算) + const miningTechLevel = player.technologies[TechnologyType.MiningTechnology] || 0 + // 获取资源研究科技等级 + const techBonuses = { + mineralResearchLevel: player.technologies[TechnologyType.MineralResearch] || 0, + crystalResearchLevel: player.technologies[TechnologyType.CrystalResearch] || 0, + fuelResearchLevel: player.technologies[TechnologyType.FuelResearch] || 0 + } + player.planets.forEach(planet => { // 计算更新前的资源(用于计算生产量) const resourcesBefore = { ...planet.resources } - resourceLogic.updatePlanetResources(planet, now, bonuses, gameSpeed) + resourceLogic.updatePlanetResources(planet, now, bonuses, gameSpeed, miningTechLevel, techBonuses) // 追踪资源生产统计 if (player.achievementStats) { @@ -209,6 +218,10 @@ export const processGameUpdate = ( onCompleted ) + // 重要:先更新 player.researchQueue,再处理等待队列 + // 这样等待队列处理时可以正确 push 新项目到队列中 + player.researchQueue = updatedResearchQueue + // 处理等待队列自动执行 const waitingResult = waitingQueueLogic.processAllWaitingQueues(player, now) // 如果有等待队列项被执行,可以在这里添加通知(可选) @@ -244,8 +257,9 @@ export const processGameUpdate = ( onUnlock(allUnlockedItems) } + // 返回当前的研究队列(包含等待队列处理后添加的新项) return { - updatedResearchQueue + updatedResearchQueue: player.researchQueue } } diff --git a/src/logic/npcBehaviorLogic.ts b/src/logic/npcBehaviorLogic.ts index 35178f6..a9c9bd7 100644 --- a/src/logic/npcBehaviorLogic.ts +++ b/src/logic/npcBehaviorLogic.ts @@ -17,14 +17,14 @@ import type { AllyDefenseNotification, AttitudeChangeNotification } from '@/types/game' -import { MissionType, ShipType, TechnologyType, RelationStatus, NPCAIType } from '@/types/game' +import { MissionType, ShipType, DefenseType, TechnologyType, RelationStatus, NPCAIType } from '@/types/game' // 重新导出类型供外部使用 export type { TradeOffer, IntelReport, JointAttackInvite, IntelType, AidNotification, AllyDefenseNotification, AttitudeChangeNotification } import * as fleetLogic from './fleetLogic' import * as diplomaticLogic from './diplomaticLogic' import * as resourceLogic from './resourceLogic' -import { DIPLOMATIC_CONFIG, SHIPS } from '@/config/gameConfig' +import { DIPLOMATIC_CONFIG, SHIPS, DEFENSES } from '@/config/gameConfig' // ========== 敌对NPC增强行为类型定义 ========== @@ -908,11 +908,69 @@ export const processNPCSpyArrival = ( } /** - * 决定NPC攻击舰队组成 - * 基于侦查报告和NPC实力 + * 计算舰队的战斗力 + * 使用 attack + shield + armor 作为单位战斗力 */ -const decideAttackFleet = (_npc: NPC, npcPlanet: Planet, _spyReport: SpyReport, config: DynamicBehaviorConfig): Partial | null => { - // 简单策略:派出一定比例的可用舰队 +const calculateFleetCombatPower = (fleet: Partial | undefined): number => { + if (!fleet) return 0 + let power = 0 + for (const [shipType, count] of Object.entries(fleet)) { + if (count && count > 0) { + const config = SHIPS[shipType as ShipType] + if (config) { + // 战斗力 = (攻击力 + 护盾 + 装甲) * 数量 + power += (config.attack + config.shield + config.armor) * count + } + } + } + return power +} + +/** + * 计算防御设施的战斗力 + */ +const calculateDefenseCombatPower = (defense: Partial> | undefined): number => { + if (!defense) return 0 + let power = 0 + for (const [defenseType, count] of Object.entries(defense)) { + if (count && count > 0) { + const config = DEFENSES[defenseType as DefenseType] + if (config) { + // 战斗力 = (攻击力 + 护盾 + 装甲) * 数量 + power += (config.attack + config.shield + config.armor) * count + } + } + } + return power +} + +/** + * 评估NPC是否能赢得战斗 + * 返回NPC战斗力与敌方战斗力的比值 + */ +export const evaluateWinProbability = (npcFleet: Partial, spyReport: SpyReport): number => { + const npcPower = calculateFleetCombatPower(npcFleet) + const enemyFleetPower = calculateFleetCombatPower(spyReport.fleet) + const enemyDefensePower = calculateDefenseCombatPower(spyReport.defense) + const totalEnemyPower = enemyFleetPower + enemyDefensePower + + // 如果敌方没有防御力,返回无限大(可以攻击) + if (totalEnemyPower === 0) return Infinity + + return npcPower / totalEnemyPower +} + +/** + * 决定NPC攻击舰队组成 + * 基于侦查报告和NPC实力,只有当有合理胜算时才攻击 + */ +const decideAttackFleet = (_npc: NPC, npcPlanet: Planet, spyReport: SpyReport, config: DynamicBehaviorConfig): Partial | null => { + // 计算敌方总战斗力 + const enemyFleetPower = calculateFleetCombatPower(spyReport.fleet) + const enemyDefensePower = calculateDefenseCombatPower(spyReport.defense) + const totalEnemyPower = enemyFleetPower + enemyDefensePower + + // 先计算可用的攻击舰队 const attackFleet: Partial = {} let hasShips = false @@ -939,7 +997,22 @@ const decideAttackFleet = (_npc: NPC, npcPlanet: Planet, _spyReport: SpyReport, } } - return hasShips ? attackFleet : null + if (!hasShips) { + return null + } + + // 计算NPC舰队战斗力 + const npcPower = calculateFleetCombatPower(attackFleet) + + // 如果敌方有防御力,检查是否有足够的胜算 + // 要求NPC战斗力至少是敌方的1.2倍才会发动攻击(确保有较大胜算) + const MIN_WIN_RATIO = 1.2 + if (totalEnemyPower > 0 && npcPower < totalEnemyPower * MIN_WIN_RATIO) { + // NPC战斗力不足,不发动攻击 + return null + } + + return attackFleet } /** @@ -1520,6 +1593,25 @@ export const createNPCRecycleMission = (npc: NPC, debris: DebrisField, player: P return null } + // 检查残骸位置是否有玩家星球 + const playerPlanetAtDebris = allPlanets.find( + p => + p.ownerId === player.id && + p.position.galaxy === debris.position.galaxy && + p.position.system === debris.position.system && + p.position.position === debris.position.position + ) + + // 如果残骸在玩家星球位置,检查玩家是否有防御 + // 如果玩家有防御,NPC不应该只派回收船去送死(会被击毁产生更多残骸,形成恶性循环) + if (playerPlanetAtDebris) { + // 计算玩家星球的总防御数量 + const totalDefense = Object.values(playerPlanetAtDebris.defense || {}).reduce((sum, count) => sum + (count || 0), 0) + if (totalDefense > 0) { + return null // 玩家有防御,不派纯回收船去送死 + } + } + // 检查NPC是否有回收船 const recyclers = closestPlanet.fleet[ShipType.Recycler] || 0 if (recyclers === 0) { @@ -1566,15 +1658,7 @@ export const createNPCRecycleMission = (npc: NPC, debris: DebrisField, player: P } npc.fleetMissions.push(mission) - // 检查残骸位置是否有玩家星球,如果有则发送警告 - const playerPlanetAtDebris = allPlanets.find( - p => - p.ownerId === player.id && - p.position.galaxy === debris.position.galaxy && - p.position.system === debris.position.system && - p.position.position === debris.position.position - ) - + // 如果残骸在玩家星球位置,发送警告(非敌对NPC才会执行到这里) if (playerPlanetAtDebris) { // 创建即将到来的舰队警告(非敌对) const alert = createIncomingFleetAlert(mission, npc, playerPlanetAtDebris) diff --git a/src/logic/oreDepositLogic.ts b/src/logic/oreDepositLogic.ts index 550c462..8566395 100644 --- a/src/logic/oreDepositLogic.ts +++ b/src/logic/oreDepositLogic.ts @@ -266,12 +266,12 @@ export const formatDepletionTime = (hours: number): string => { /** * 计算地质研究站带来的恢复速率加成 * @param geoStationLevel 地质研究站等级 - * @returns 恢复速率倍数(1 + 等级 * 0.5) + * @returns 恢复速率倍数(1 + 等级 * 0.1) */ export const calculateGeoStationBonus = (geoStationLevel: number): number => { // 每级地质研究站增加50%恢复速度 // 0级 = 1倍, 1级 = 1.5倍, 2级 = 2倍, ..., 10级 = 6倍 - return 1 + geoStationLevel * 0.5 + return 1 + geoStationLevel * 0.1 } /** @@ -280,8 +280,16 @@ export const calculateGeoStationBonus = (geoStationLevel: number): number => { * @param deposits 矿脉储量对象 * @param hoursElapsed 经过的小时数 * @param geoStationLevel 地质研究站等级(可选,影响恢复速度) + * @param deepDrillingLevel 深层钻探设施等级(可选,影响恢复上限) + * @param miningTechLevel 采矿技术等级(可选,影响恢复上限) */ -export const regenerateDeposits = (deposits: OreDeposits, hoursElapsed: number, geoStationLevel: number = 0): void => { +export const regenerateDeposits = ( + deposits: OreDeposits, + hoursElapsed: number, + geoStationLevel: number = 0, + deepDrillingLevel: number = 0, + miningTechLevel: number = 0 +): void => { const { REGENERATION } = ORE_DEPOSIT_CONFIG if (!REGENERATION.ENABLED || hoursElapsed <= 0) return @@ -289,32 +297,36 @@ export const regenerateDeposits = (deposits: OreDeposits, hoursElapsed: number, // 计算地质研究站加成 const geoBonus = calculateGeoStationBonus(geoStationLevel) - // 动态计算初始储量上限 - const initialDeposits = calculateInitialDeposits(deposits.position) + // 计算带有建筑和科技加成的储量上限 + const enhancedDeposits = calculateEnhancedDeposits(deposits.position, deepDrillingLevel, miningTechLevel) - // 计算恢复量(基于初始储量的百分比,乘以地质研究站加成) + // 计算恢复量(基于增强后储量的百分比,乘以地质研究站加成) const regenRate = REGENERATION.RATE_PER_HOUR * hoursElapsed * geoBonus const maxPercentage = REGENERATION.MAX_PERCENTAGE // 恢复每种资源 - const metalRegen = initialDeposits.metal * regenRate - const crystalRegen = initialDeposits.crystal * regenRate - const deuteriumRegen = initialDeposits.deuterium * regenRate + const metalRegen = enhancedDeposits.metal * regenRate + const crystalRegen = enhancedDeposits.crystal * regenRate + const deuteriumRegen = enhancedDeposits.deuterium * regenRate - // 添加恢复量,但不超过初始储量的最大百分比 - deposits.metal = Math.min(initialDeposits.metal * maxPercentage, deposits.metal + metalRegen) - deposits.crystal = Math.min(initialDeposits.crystal * maxPercentage, deposits.crystal + crystalRegen) - deposits.deuterium = Math.min(initialDeposits.deuterium * maxPercentage, deposits.deuterium + deuteriumRegen) + // 添加恢复量,但不超过增强后储量的最大百分比 + deposits.metal = Math.min(enhancedDeposits.metal * maxPercentage, deposits.metal + metalRegen) + deposits.crystal = Math.min(enhancedDeposits.crystal * maxPercentage, deposits.crystal + crystalRegen) + deposits.deuterium = Math.min(enhancedDeposits.deuterium * maxPercentage, deposits.deuterium + deuteriumRegen) } /** * 获取矿脉恢复状态信息 * @param deposits 矿脉储量 * @param geoStationLevel 地质研究站等级(可选,影响恢复时间计算) + * @param deepDrillingLevel 深层钻探设施等级(可选,影响恢复上限) + * @param miningTechLevel 采矿技术等级(可选,影响恢复上限) */ export const getRegenerationInfo = ( deposits: OreDeposits | undefined, - geoStationLevel: number = 0 + geoStationLevel: number = 0, + deepDrillingLevel: number = 0, + miningTechLevel: number = 0 ): { metalRecovering: boolean crystalRecovering: boolean @@ -338,26 +350,26 @@ export const getRegenerationInfo = ( } } - // 动态计算初始储量上限 - const initialDeposits = calculateInitialDeposits(deposits.position) + // 计算带有建筑和科技加成的储量上限 + const enhancedDeposits = calculateEnhancedDeposits(deposits.position, deepDrillingLevel, miningTechLevel) const { REGENERATION } = ORE_DEPOSIT_CONFIG const maxPercentage = REGENERATION.MAX_PERCENTAGE // 实际恢复速率 = 基础速率 * 地质研究站加成 const ratePerHour = REGENERATION.RATE_PER_HOUR * geoBonus - const metalMax = initialDeposits.metal * maxPercentage - const crystalMax = initialDeposits.crystal * maxPercentage - const deuteriumMax = initialDeposits.deuterium * maxPercentage + const metalMax = enhancedDeposits.metal * maxPercentage + const crystalMax = enhancedDeposits.crystal * maxPercentage + const deuteriumMax = enhancedDeposits.deuterium * maxPercentage const metalRecovering = deposits.metal < metalMax const crystalRecovering = deposits.crystal < crystalMax const deuteriumRecovering = deposits.deuterium < deuteriumMax // 计算恢复到满需要的小时数(考虑地质研究站加成) - const hoursToFullMetal = metalRecovering ? (metalMax - deposits.metal) / (initialDeposits.metal * ratePerHour) : 0 - const hoursToFullCrystal = crystalRecovering ? (crystalMax - deposits.crystal) / (initialDeposits.crystal * ratePerHour) : 0 - const hoursToFullDeuterium = deuteriumRecovering ? (deuteriumMax - deposits.deuterium) / (initialDeposits.deuterium * ratePerHour) : 0 + const hoursToFullMetal = metalRecovering ? (metalMax - deposits.metal) / (enhancedDeposits.metal * ratePerHour) : 0 + const hoursToFullCrystal = crystalRecovering ? (crystalMax - deposits.crystal) / (enhancedDeposits.crystal * ratePerHour) : 0 + const hoursToFullDeuterium = deuteriumRecovering ? (deuteriumMax - deposits.deuterium) / (enhancedDeposits.deuterium * ratePerHour) : 0 return { metalRecovering, diff --git a/src/logic/planetLogic.ts b/src/logic/planetLogic.ts index f48f3d3..f3f3de8 100644 --- a/src/logic/planetLogic.ts +++ b/src/logic/planetLogic.ts @@ -320,3 +320,63 @@ export const calculateDeuteriumTemperatureBonus = (maxTemperature: number): numb // 返回乘数,例如:-40°C时返回1.52,+100°C时返回0.96 return 1.36 - 0.004 * maxTemperature } + +/** + * 检查是否可以放弃殖民地 + * @param planets 玩家所有星球 + * @param planetId 要放弃的星球ID + * @returns 是否可以放弃及原因 + */ +export const canAbandonColony = ( + planets: Planet[], + planetId: string +): { canAbandon: boolean; reason?: string } => { + const planet = planets.find(p => p.id === planetId) + if (!planet) { + return { canAbandon: false, reason: 'errors.planetNotFound' } + } + + // 主星(第一个非月球星球)不能放弃 + const mainPlanet = planets.find(p => !p.isMoon) + if (mainPlanet && mainPlanet.id === planetId) { + return { canAbandon: false, reason: 'errors.cannotAbandonHomePlanet' } + } + + // 检查是否有正在进行的建造队列 + if (planet.buildQueue.length > 0) { + return { canAbandon: false, reason: 'errors.hasBuildQueue' } + } + + // 检查是否有舰队在该星球 + const hasFleet = Object.values(planet.fleet).some(count => count > 0) + if (hasFleet) { + return { canAbandon: false, reason: 'errors.hasFleetOnPlanet' } + } + + // 检查是否有防御在该星球 + const hasDefense = Object.values(planet.defense).some(count => count > 0) + if (hasDefense) { + return { canAbandon: false, reason: 'errors.hasDefenseOnPlanet' } + } + + return { canAbandon: true } +} + +/** + * 放弃殖民地 + * @param planets 玩家所有星球 + * @param planetId 要放弃的星球ID + * @returns 放弃后的星球列表 + */ +export const abandonColony = (planets: Planet[], planetId: string): Planet[] => { + const planet = planets.find(p => p.id === planetId) + if (!planet) return planets + + // 如果放弃的是行星,同时删除其月球 + if (!planet.isMoon) { + return planets.filter(p => p.id !== planetId && p.parentPlanetId !== planetId) + } + + // 如果放弃的是月球,只删除月球 + return planets.filter(p => p.id !== planetId) +} diff --git a/src/logic/publicLogic.ts b/src/logic/publicLogic.ts index 405d81c..1833d39 100644 --- a/src/logic/publicLogic.ts +++ b/src/logic/publicLogic.ts @@ -90,16 +90,27 @@ export const checkRequirements = ( } /** - * 计算星球的资源产量(包含军官加成) + * 计算星球的资源产量(包含军官加成和科技加成) * @param planet 星球对象 * @param officers 玩家的军官对象 + * @param resourceSpeed 游戏速度 + * @param techBonuses 科技加成(可选,矿物研究/晶体研究/燃料研究) * @returns 每小时各类资源的产量 */ -export const getResourceProduction = (planet: Planet, officers: Record, resourceSpeed: number = 1): Resources => { +export const getResourceProduction = ( + planet: Planet, + officers: Record, + resourceSpeed: number = 1, + techBonuses?: { + mineralResearchLevel?: number + crystalResearchLevel?: number + fuelResearchLevel?: number + } +): Resources => { // 计算当前激活的军官加成 const bonuses = officerLogic.calculateActiveBonuses(officers, Date.now()) // 根据建筑等级和军官加成计算资源产量 - const base = resourceLogic.calculateResourceProduction(planet, bonuses) + const base = resourceLogic.calculateResourceProduction(planet, bonuses, techBonuses) return scaleResources(base, resourceSpeed) } diff --git a/src/logic/researchLogic.ts b/src/logic/researchLogic.ts index 243435d..141fdaf 100644 --- a/src/logic/researchLogic.ts +++ b/src/logic/researchLogic.ts @@ -1,8 +1,57 @@ -import type { Resources, BuildQueueItem } from '@/types/game' +import type { Resources, BuildQueueItem, Planet } from '@/types/game' import { TechnologyType, BuildingType } from '@/types/game' import { TECHNOLOGIES } from '@/config/gameConfig' import * as pointsLogic from './pointsLogic' +/** + * 计算有效研究实验室等级(考虑星际研究网络) + * 星际研究网络允许连接多个星球的研究实验室,取等级最高的N个实验室等级之和 + * @param planets 玩家的所有星球 + * @param currentPlanetId 当前星球ID(研究所在的星球) + * @param intergalacticResearchNetworkLevel 星际研究网络等级 + * @returns 有效的研究实验室等级总和 + */ +export const calculateEffectiveLabLevel = ( + planets: Planet[], + currentPlanetId: string, + intergalacticResearchNetworkLevel: number +): number => { + // 收集所有星球的研究实验室等级 + const labLevels: { planetId: string; level: number }[] = [] + + for (const planet of planets) { + const labLevel = planet.buildings[BuildingType.ResearchLab] || 0 + if (labLevel > 0) { + labLevels.push({ planetId: planet.id, level: labLevel }) + } + } + + // 如果没有星际研究网络,只返回当前星球的实验室等级 + if (intergalacticResearchNetworkLevel === 0) { + const currentPlanet = planets.find(p => p.id === currentPlanetId) + return currentPlanet?.buildings[BuildingType.ResearchLab] || 0 + } + + // 按等级降序排序 + labLevels.sort((a, b) => b.level - a.level) + + // 可连接的实验室数量 = 1 + 星际研究网络等级 + // 等级1可连接2个实验室,等级2可连接3个,以此类推 + const maxLabs = 1 + intergalacticResearchNetworkLevel + + // 取前N个实验室的等级之和 + let totalLevel = 0 + const count = Math.min(maxLabs, labLevels.length) + for (let i = 0; i < count; i++) { + const lab = labLevels[i] + if (lab) { + totalLevel += lab.level + } + } + + return totalLevel +} + // 用于生成唯一ID的计数器 let researchQueueIdCounter = 0 @@ -23,31 +72,56 @@ export const calculateTechnologyCost = (techType: TechnologyType, targetLevel: n /** * 计算科技研究时间 + * 使用 2moons 公式(调整版): + * 1. 成本系数 = Σ (资源^0.3 / 0.003) + * 2. 时间(秒) = 成本系数 / ((1 + 研究实验室等级) × 能源加成 × 游戏速度) * @param techType 科技类型 - * @param currentLevel 当前等级 + * @param currentLevel 当前等级(要研究的目标等级 = currentLevel + 1) * @param researchSpeedBonus 军官等提供的研究速度加成百分比 * @param researchLabLevel 研究实验室等级 - * @param energyTechLevel 能源技术等级 + * @param energyTechLevel 能源技术等级(提供额外加速) + * @param gameSpeed 游戏速度(默认1) + * @param universityLevel 大学等级(每级减少研究时间8%) */ export const calculateTechnologyTime = ( techType: TechnologyType, currentLevel: number, researchSpeedBonus: number = 0, researchLabLevel: number = 1, - energyTechLevel: number = 0 + energyTechLevel: number = 0, + gameSpeed: number = 1, + universityLevel: number = 0 ): number => { - const config = TECHNOLOGIES[techType] - const baseTime = config.baseTime * Math.pow(config.costMultiplier, currentLevel) + // 目标等级 = 当前等级 + 1 + const targetLevel = currentLevel + 1 + + // 计算该等级的成本 + const cost = calculateTechnologyCost(techType, targetLevel) + + // 2moons 公式:成本系数 = Σ (资源^0.3 / 0.003) + let elementCost = 0 + if (cost.metal > 0) elementCost += Math.pow(cost.metal, 0.3) / 0.003 + if (cost.crystal > 0) elementCost += Math.pow(cost.crystal, 0.3) / 0.003 + if (cost.deuterium > 0) elementCost += Math.pow(cost.deuterium, 0.3) / 0.003 - // 研究实验室和能源技术的加速:研究时间 / (研究实验室等级 × (1 + 能源技术等级)) // 研究实验室等级至少为1,防止除以0 const labLevel = Math.max(1, researchLabLevel) - const techSpeedDivisor = labLevel * (1 + energyTechLevel) + + // 能源技术提供额外加速(每级5%) + const energyBonus = 1 + energyTechLevel * 0.05 + + // 简化公式:时间(秒) = 成本系数 / (实验室加成 × 能源加成 × 游戏速度) + const timeInSeconds = elementCost / ((1 + labLevel) * energyBonus * gameSpeed) // 军官等的百分比加成 const speedMultiplier = 1 - researchSpeedBonus / 100 - return Math.floor((baseTime / techSpeedDivisor) * speedMultiplier) + // 大学加成:每级减少研究时间8%(最高10级=57%减少,因为是乘法叠加) + // 使用乘法叠加:(1 - 0.08)^level + const universityMultiplier = Math.pow(0.92, universityLevel) + + // 确保最小时间为5秒 + return Math.max(5, Math.floor(timeInSeconds * speedMultiplier * universityMultiplier)) } /** diff --git a/src/logic/researchValidation.ts b/src/logic/researchValidation.ts index f662ae7..4b6355d 100644 --- a/src/logic/researchValidation.ts +++ b/src/logic/researchValidation.ts @@ -54,7 +54,8 @@ export const executeTechnologyResearch = ( techType: TechnologyType, currentLevel: number, officers: Record, - technologies: Partial> + technologies: Partial>, + allPlanets?: Planet[] ): { queueItem: BuildQueueItem } => { const targetLevel = currentLevel + 1 const cost = researchLogic.calculateTechnologyCost(techType, targetLevel) @@ -62,11 +63,30 @@ export const executeTechnologyResearch = ( // 计算军官加成 const bonuses = officerLogic.calculateActiveBonuses(officers, Date.now()) - // 获取研究实验室等级和能源技术等级 - const researchLabLevel = planet.buildings[BuildingType.ResearchLab] || 1 - const energyTechLevel = technologies[TechnologyType.EnergyTechnology] || 0 + // 获取星际研究网络等级 + const intergalacticResearchNetworkLevel = technologies[TechnologyType.IntergalacticResearchNetwork] || 0 - const time = researchLogic.calculateTechnologyTime(techType, currentLevel, bonuses.researchSpeedBonus, researchLabLevel, energyTechLevel) + // 计算有效研究实验室等级(考虑星际研究网络) + let researchLabLevel: number + if (allPlanets && intergalacticResearchNetworkLevel > 0) { + researchLabLevel = researchLogic.calculateEffectiveLabLevel(allPlanets, planet.id, intergalacticResearchNetworkLevel) + } else { + researchLabLevel = planet.buildings[BuildingType.ResearchLab] || 1 + } + + const energyTechLevel = technologies[TechnologyType.EnergyTechnology] || 0 + // 获取大学等级(加速研究) + const universityLevel = planet.buildings[BuildingType.University] || 0 + + const time = researchLogic.calculateTechnologyTime( + techType, + currentLevel, + bonuses.researchSpeedBonus, + researchLabLevel, + energyTechLevel, + 1, + universityLevel + ) // 扣除资源 resourceLogic.deductResources(planet.resources, cost) diff --git a/src/logic/resourceLogic.ts b/src/logic/resourceLogic.ts index 4aea2ee..106138a 100644 --- a/src/logic/resourceLogic.ts +++ b/src/logic/resourceLogic.ts @@ -5,6 +5,24 @@ import { OFFICERS } from '@/config/gameConfig' import * as oreDepositLogic from './oreDepositLogic' import * as planetLogic from './planetLogic' +/** + * 计算资源研究科技加成 + * @param mineralResearchLevel 矿物研究等级(每级+2%金属产量) + * @param crystalResearchLevel 晶体研究等级(每级+2%晶体产量) + * @param fuelResearchLevel 燃料研究等级(每级+2%重氢产量) + */ +export const calculateResearchProductionBonus = ( + mineralResearchLevel: number = 0, + crystalResearchLevel: number = 0, + fuelResearchLevel: number = 0 +): { metalBonus: number; crystalBonus: number; deuteriumBonus: number } => { + return { + metalBonus: mineralResearchLevel * 2, // 每级2% + crystalBonus: crystalResearchLevel * 2, + deuteriumBonus: fuelResearchLevel * 2 + } +} + /** * 计算电量产出 */ @@ -93,6 +111,9 @@ export const calculateEnergyConsumption = (planet: Planet): number => { /** * 计算资源产量(每小时) + * @param planet 星球 + * @param bonuses 军官等加成 + * @param techBonuses 科技加成(可选,矿物研究/晶体研究/燃料研究) */ export const calculateResourceProduction = ( planet: Planet, @@ -100,6 +121,11 @@ export const calculateResourceProduction = ( resourceProductionBonus: number darkMatterProductionBonus: number energyProductionBonus: number + }, + techBonuses?: { + mineralResearchLevel?: number + crystalResearchLevel?: number + fuelResearchLevel?: number } ): Resources => { const metalMineLevel = planet.buildings[BuildingType.MetalMine] || 0 @@ -110,6 +136,16 @@ export const calculateResourceProduction = ( const resourceBonus = 1 + (bonuses.resourceProductionBonus || 0) / 100 const darkMatterBonus = 1 + (bonuses.darkMatterProductionBonus || 0) / 100 + // 计算科技加成 + const researchBonus = calculateResearchProductionBonus( + techBonuses?.mineralResearchLevel || 0, + techBonuses?.crystalResearchLevel || 0, + techBonuses?.fuelResearchLevel || 0 + ) + const metalTechBonus = 1 + researchBonus.metalBonus / 100 + const crystalTechBonus = 1 + researchBonus.crystalBonus / 100 + const deuteriumTechBonus = 1 + researchBonus.deuteriumBonus / 100 + // 计算能量产出(每小时) const energyProduction = calculateEnergyProduction(planet, { energyProductionBonus: bonuses.energyProductionBonus }) @@ -131,13 +167,28 @@ export const calculateResourceProduction = ( const deuteriumTempBonus = planetLogic.calculateDeuteriumTemperatureBonus(planet.temperature?.max ?? 0) return { - metal: metalMineLevel * 1500 * Math.pow(1.5, metalMineLevel) * resourceBonus * productionEfficiency * metalDepositEfficiency, - crystal: crystalMineLevel * 1000 * Math.pow(1.5, crystalMineLevel) * resourceBonus * productionEfficiency * crystalDepositEfficiency, + metal: + metalMineLevel * + 1500 * + Math.pow(1.5, metalMineLevel) * + resourceBonus * + metalTechBonus * + productionEfficiency * + metalDepositEfficiency, + crystal: + crystalMineLevel * + 1000 * + Math.pow(1.5, crystalMineLevel) * + resourceBonus * + crystalTechBonus * + productionEfficiency * + crystalDepositEfficiency, deuterium: deuteriumSynthesizerLevel * 500 * Math.pow(1.5, deuteriumSynthesizerLevel) * resourceBonus * + deuteriumTechBonus * productionEfficiency * deuteriumDepositEfficiency * deuteriumTempBonus, @@ -183,7 +234,13 @@ export const updatePlanetResources = ( energyProductionBonus: number storageCapacityBonus: number }, - gameSpeed: number = 1 + gameSpeed: number = 1, + miningTechLevel: number = 0, + techBonuses?: { + mineralResearchLevel?: number + crystalResearchLevel?: number + fuelResearchLevel?: number + } ): void => { const timeDiff = (now - planet.lastUpdate) / 1000 // 转换为秒 @@ -214,11 +271,15 @@ export const updatePlanetResources = ( planet.resources.energy = Math.max(0, planet.resources.energy) // 计算资源产量(会检查能量是否充足,以及矿脉储量效率) - const production = calculateResourceProduction(planet, { - resourceProductionBonus: bonuses.resourceProductionBonus, - darkMatterProductionBonus: bonuses.darkMatterProductionBonus, - energyProductionBonus: bonuses.energyProductionBonus - }) + const production = calculateResourceProduction( + planet, + { + resourceProductionBonus: bonuses.resourceProductionBonus, + darkMatterProductionBonus: bonuses.darkMatterProductionBonus, + energyProductionBonus: bonuses.energyProductionBonus + }, + techBonuses + ) // 计算实际产出量(用于消耗矿脉储量) const metalProduced = (production.metal * effectiveTimeDiff) / 3600 @@ -232,10 +293,11 @@ export const updatePlanetResources = ( oreDepositLogic.consumeDeposit(planet.oreDeposits, 'deuterium', deuteriumProduced) // 矿脉缓慢恢复(每次更新时恢复一小部分) - // 地质研究站等级影响恢复速度 + // 地质研究站等级影响恢复速度,深层钻探设施和采矿技术影响恢复上限 const hoursElapsed = effectiveTimeDiff / 3600 const geoStationLevel = planet.buildings[BuildingType.GeoResearchStation] || 0 - oreDepositLogic.regenerateDeposits(planet.oreDeposits, hoursElapsed, geoStationLevel) + const deepDrillingLevel = planet.buildings[BuildingType.DeepDrillingFacility] || 0 + oreDepositLogic.regenerateDeposits(planet.oreDeposits, hoursElapsed, geoStationLevel, deepDrillingLevel, miningTechLevel) } // 更新资源(转换为每秒产量,应用游戏速度) @@ -386,12 +448,22 @@ export interface ConsumptionDetail { /** * 计算资源产量详细breakdown + * @param planet 星球 + * @param officers 军官 + * @param currentTime 当前时间 + * @param resourceSpeed 游戏速度 + * @param techBonuses 科技加成(可选,矿物研究/晶体研究/燃料研究) */ export const calculateProductionBreakdown = ( planet: Planet, officers: Record, currentTime: number, - resourceSpeed: number = 1 + resourceSpeed: number = 1, + techBonuses?: { + mineralResearchLevel?: number + crystalResearchLevel?: number + fuelResearchLevel?: number + } ): ProductionBreakdown => { const metalMineLevel = planet.buildings[BuildingType.MetalMine] || 0 const crystalMineLevel = planet.buildings[BuildingType.CrystalMine] || 0 @@ -432,6 +504,13 @@ export const calculateProductionBreakdown = ( const totalDarkMatterBonus = activeOfficerBonuses.reduce((sum, officer) => sum + officer.darkMatterBonus, 0) const totalEnergyBonus = activeOfficerBonuses.reduce((sum, officer) => sum + officer.energyBonus, 0) + // 计算科技加成 + const researchBonus = calculateResearchProductionBonus( + techBonuses?.mineralResearchLevel || 0, + techBonuses?.crystalResearchLevel || 0, + techBonuses?.fuelResearchLevel || 0 + ) + // 金属矿产量 const metalBase = metalMineLevel * 1500 * Math.pow(1.5, metalMineLevel) const metalBonuses: ProductionBonus[] = [] @@ -449,16 +528,27 @@ export const calculateProductionBreakdown = ( } }) + // 添加矿物研究科技加成 + if (researchBonus.metalBonus > 0) { + const techBonusValue = metalBase * (1 + totalResourceBonus / 100) * (researchBonus.metalBonus / 100) + metalBonuses.push({ + name: 'research.mineralResearch', + percentage: researchBonus.metalBonus, + value: techBonusValue, + source: 'technology' + }) + } + if (!hasPositiveEnergyBalance) { metalBonuses.push({ name: 'resources.noEnergy', percentage: -100, - value: -metalBase * (1 + totalResourceBonus / 100), + value: -metalBase * (1 + totalResourceBonus / 100) * (1 + researchBonus.metalBonus / 100), source: 'other' }) } - const metalFinal = metalBase * (1 + totalResourceBonus / 100) * productionEfficiency + const metalFinal = metalBase * (1 + totalResourceBonus / 100) * (1 + researchBonus.metalBonus / 100) * productionEfficiency // 晶体矿产量 const crystalBase = crystalMineLevel * 1000 * Math.pow(1.5, crystalMineLevel) @@ -476,16 +566,27 @@ export const calculateProductionBreakdown = ( } }) + // 添加晶体研究科技加成 + if (researchBonus.crystalBonus > 0) { + const techBonusValue = crystalBase * (1 + totalResourceBonus / 100) * (researchBonus.crystalBonus / 100) + crystalBonuses.push({ + name: 'research.crystalResearch', + percentage: researchBonus.crystalBonus, + value: techBonusValue, + source: 'technology' + }) + } + if (!hasPositiveEnergyBalance) { crystalBonuses.push({ name: 'resources.noEnergy', percentage: -100, - value: -crystalBase * (1 + totalResourceBonus / 100), + value: -crystalBase * (1 + totalResourceBonus / 100) * (1 + researchBonus.crystalBonus / 100), source: 'other' }) } - const crystalFinal = crystalBase * (1 + totalResourceBonus / 100) * productionEfficiency + const crystalFinal = crystalBase * (1 + totalResourceBonus / 100) * (1 + researchBonus.crystalBonus / 100) * productionEfficiency // 重氢合成器产量(受温度影响) // OGame 原版规则:温度越低,重氢产量越高 @@ -518,16 +619,27 @@ export const calculateProductionBreakdown = ( } }) + // 添加燃料研究科技加成 + if (researchBonus.deuteriumBonus > 0) { + const techBonusValue = deuteriumBase * (1 + totalResourceBonus / 100) * (researchBonus.deuteriumBonus / 100) + deuteriumBonuses.push({ + name: 'research.fuelResearch', + percentage: researchBonus.deuteriumBonus, + value: techBonusValue, + source: 'technology' + }) + } + if (!hasPositiveEnergyBalance) { deuteriumBonuses.push({ name: 'resources.noEnergy', percentage: -100, - value: -deuteriumBase * (1 + totalResourceBonus / 100), + value: -deuteriumBase * (1 + totalResourceBonus / 100) * (1 + researchBonus.deuteriumBonus / 100), source: 'other' }) } - const deuteriumFinal = deuteriumBase * (1 + totalResourceBonus / 100) * productionEfficiency + const deuteriumFinal = deuteriumBase * (1 + totalResourceBonus / 100) * (1 + researchBonus.deuteriumBonus / 100) * productionEfficiency // 暗物质收集器产量 const darkMatterBase = darkMatterCollectorLevel * 25 * Math.pow(1.5, darkMatterCollectorLevel) diff --git a/src/logic/shipLogic.ts b/src/logic/shipLogic.ts index 55586fb..35e36a0 100644 --- a/src/logic/shipLogic.ts +++ b/src/logic/shipLogic.ts @@ -322,3 +322,49 @@ export const addFleet = (currentFleet: Fleet, fleet: Partial): void => { } } } + +/** + * 计算舰船拆除返还资源 + * 返还50%的建造成本 + */ +export const calculateShipScrapRefund = (shipType: ShipType, quantity: number): Resources => { + const cost = calculateShipCost(shipType, quantity) + return { + metal: Math.floor(cost.metal * 0.5), + crystal: Math.floor(cost.crystal * 0.5), + deuterium: Math.floor(cost.deuterium * 0.5), + darkMatter: Math.floor(cost.darkMatter * 0.5), + energy: 0 + } +} + +/** + * 计算舰船拆除时间 + * 拆除时间为建造时间的50% + */ +export const calculateShipScrapTime = ( + shipType: ShipType, + quantity: number, + buildingSpeedBonus: number = 0, + roboticsFactoryLevel: number = 0, + naniteFactoryLevel: number = 0 +): number => { + const buildTime = calculateShipBuildTime(shipType, quantity, buildingSpeedBonus, roboticsFactoryLevel, naniteFactoryLevel) + return Math.floor(buildTime * 0.5) +} + +/** + * 创建舰船拆除队列项 + */ +export const createShipScrapQueueItem = (shipType: ShipType, quantity: number, scrapTime: number): BuildQueueItem => { + const now = Date.now() + shipQueueIdCounter++ + return { + id: `scrap_ship_${now}_${shipQueueIdCounter}`, + type: 'scrap_ship', + itemType: shipType, + quantity, + startTime: now, + endTime: now + scrapTime * 1000 + } +} diff --git a/src/logic/shipValidation.ts b/src/logic/shipValidation.ts index ba43154..0a1ba54 100644 --- a/src/logic/shipValidation.ts +++ b/src/logic/shipValidation.ts @@ -201,3 +201,66 @@ export const executeFleetDispatch = ( resourceLogic.deductResources(planet.resources, cargo) } } + +/** + * 验证舰船拆除的所有条件 + */ +export const validateShipScrap = ( + planet: Planet, + shipType: ShipType, + quantity: number +): { + valid: boolean + reason?: string +} => { + // 检查数量是否有效 + if (quantity <= 0) { + return { valid: false, reason: 'errors.invalidQuantity' } + } + + // 检查舰船数量是否足够 + const available = planet.fleet[shipType] || 0 + if (available < quantity) { + return { valid: false, reason: 'errors.insufficientShips' } + } + + return { valid: true } +} + +/** + * 执行舰船拆除 + */ +export const executeShipScrap = ( + planet: Planet, + shipType: ShipType, + quantity: number, + officers: Record +): BuildQueueItem => { + // 计算军官加成 + const bonuses = officerLogic.calculateActiveBonuses(officers, Date.now()) + + // 获取机器人工厂和纳米工厂等级 + const roboticsFactoryLevel = planet.buildings[BuildingType.RoboticsFactory] || 0 + const naniteFactoryLevel = planet.buildings[BuildingType.NaniteFactory] || 0 + + // 计算拆除时间 + const scrapTime = shipLogic.calculateShipScrapTime( + shipType, + quantity, + bonuses.buildingSpeedBonus, + roboticsFactoryLevel, + naniteFactoryLevel + ) + + // 计算返还资源 + const refund = shipLogic.calculateShipScrapRefund(shipType, quantity) + + // 扣除舰船(立即扣除,避免拆除过程中派遣) + planet.fleet[shipType] = (planet.fleet[shipType] || 0) - quantity + + // 返还资源 + resourceLogic.addResources(planet.resources, refund) + + // 创建队列项 + return shipLogic.createShipScrapQueueItem(shipType, quantity, scrapTime) +} diff --git a/src/stores/gameStore.ts b/src/stores/gameStore.ts index f410fa3..819441a 100644 --- a/src/stores/gameStore.ts +++ b/src/stores/gameStore.ts @@ -26,6 +26,7 @@ export const useGameStore = defineStore('game', { gameTime: Date.now(), isPaused: false, gameSpeed: 1, + battleToFinish: true, // 战斗到底模式:false=经典模式(6回合平局),true=战斗到底(最多100回合) player: { id: 'player1', name: '', diff --git a/src/style.css b/src/style.css index 87d1739..72f6689 100644 --- a/src/style.css +++ b/src/style.css @@ -160,12 +160,12 @@ @keyframes fade-in { from { opacity: 0; - transform: translateY(10px); + transform: translate3d(0, 10px, 0); } to { opacity: 1; - transform: translateY(0); + transform: translate3d(0, 0, 0); } } @@ -179,7 +179,7 @@ aside nav a { } aside nav a:hover button { - transform: translateX(4px); + transform: translate3d(4px, 0, 0); } /* 资源数字更新动画 */ diff --git a/src/types/game.ts b/src/types/game.ts index ab48d08..3c85510 100644 --- a/src/types/game.ts +++ b/src/types/game.ts @@ -50,7 +50,9 @@ export const BuildingType = { // 特殊建筑 PlanetDestroyerFactory: 'planetDestroyerFactory', // 行星毁灭者工厂 GeoResearchStation: 'geoResearchStation', // 地质研究站(影响矿脉恢复速度) - DeepDrillingFacility: 'deepDrillingFacility' // 深层钻探设施(提升矿脉上限) + DeepDrillingFacility: 'deepDrillingFacility', // 深层钻探设施(提升矿脉上限) + // 2moons新增建筑 + University: 'university' // 大学(加速研究) } as const export type BuildingType = (typeof BuildingType)[keyof typeof BuildingType] @@ -98,7 +100,12 @@ export const TechnologyType = { DarkMatterTechnology: 'darkMatterTechnology', // 暗物质技术 TerraformingTechnology: 'terraformingTechnology', // 地形改造技术 PlanetDestructionTech: 'planetDestructionTech', // 行星毁灭技术 - MiningTechnology: 'miningTechnology' // 采矿技术(提升矿脉上限) + MiningTechnology: 'miningTechnology', // 采矿技术(提升矿脉上限) + // 2moons新增科技 + IntergalacticResearchNetwork: 'intergalacticResearchNetwork', // 星际研究网络(连接多个研究实验室) + MineralResearch: 'mineralResearch', // 矿物研究(提升金属产量) + CrystalResearch: 'crystalResearch', // 晶体研究(提升晶体产量) + FuelResearch: 'fuelResearch' // 燃料研究(提升重氢产量) } as const export type TechnologyType = (typeof TechnologyType)[keyof typeof TechnologyType] @@ -496,6 +503,8 @@ export interface MissionReport { // 毁灭任务:概率和死星损失 destructionChance?: number deathstarsLost?: boolean + // 毁灭任务:是否发生了战斗 + hadBattle?: boolean // 部署任务:部署的舰队 deployedFleet?: Partial // 导弹攻击任务:导弹信息 @@ -656,7 +665,7 @@ export interface DebrisField { // 建造队列项 export interface BuildQueueItem { id: string - type: 'building' | 'technology' | 'ship' | 'defense' | 'demolish' + type: 'building' | 'technology' | 'ship' | 'defense' | 'demolish' | 'scrap_ship' itemType: BuildingType | TechnologyType | ShipType | DefenseType targetLevel?: number // 用于建筑和科技 quantity?: number // 用于舰船和防御 @@ -667,7 +676,7 @@ export interface BuildQueueItem { // 等待队列项(尚未开始执行,不需要 startTime/endTime) export interface WaitingQueueItem { id: string - type: 'building' | 'technology' | 'ship' | 'defense' | 'demolish' + type: 'building' | 'technology' | 'ship' | 'defense' | 'demolish' | 'scrap_ship' itemType: BuildingType | TechnologyType | ShipType | DefenseType targetLevel?: number // 用于建筑和科技 quantity?: number // 用于舰船和防御 diff --git a/src/utils/battleSimulator.ts b/src/utils/battleSimulator.ts index e504e5a..fcdd6b6 100644 --- a/src/utils/battleSimulator.ts +++ b/src/utils/battleSimulator.ts @@ -109,7 +109,10 @@ const COMBAT_EFFECTS = { * 计算一个单位对另一个单位造成的伤害 * 增强版:包含护盾弹回、重型武器穿透、装甲损坏累积 */ -const calculateDamage = (attacker: CombatUnit, defender: CombatUnit): { destroyed: number; damagedShield: number; armorDamageDealt: number } => { +const calculateDamage = ( + attacker: CombatUnit, + defender: CombatUnit +): { destroyed: number; damagedShield: number; armorDamageDealt: number } => { const attackPower = attacker.attack // 使用当前护盾值(如果有),否则使用最大护盾 const defenderCurrentShield = defender.currentShield ?? defender.shield @@ -157,14 +160,8 @@ const calculateDamage = (attacker: CombatUnit, defender: CombatUnit): { destroye // 穿透护盾后对装甲造成损坏累积 if (remainingDamage > 0) { - armorDamageDealt = Math.min( - COMBAT_EFFECTS.ARMOR_DAMAGE_RATE, - COMBAT_EFFECTS.MAX_ARMOR_DAMAGE - (defender.armorDamage ?? 0) - ) - defender.armorDamage = Math.min( - COMBAT_EFFECTS.MAX_ARMOR_DAMAGE, - (defender.armorDamage ?? 0) + armorDamageDealt - ) + armorDamageDealt = Math.min(COMBAT_EFFECTS.ARMOR_DAMAGE_RATE, COMBAT_EFFECTS.MAX_ARMOR_DAMAGE - (defender.armorDamage ?? 0)) + defender.armorDamage = Math.min(COMBAT_EFFECTS.MAX_ARMOR_DAMAGE, (defender.armorDamage ?? 0) + armorDamageDealt) } // 再消耗装甲 @@ -453,8 +450,24 @@ export const simulateBattle = ( } else if (defenderUnits.length === 0) { winner = 'attacker' } else { - // OGame原版规则:6回合后双方都有剩余单位时判定为平局 - winner = 'draw' + // 达到最大回合数后双方都有剩余单位 + // 如果是战斗到底模式(maxRounds > 6),根据剩余战力判定胜负 + if (maxRounds > 6) { + // 计算剩余战力 + const attackerPower = attackerUnits.reduce((sum, u) => sum + u.count * u.armor, 0) + const defenderPower = defenderUnits.reduce((sum, u) => sum + u.count * u.armor, 0) + // 战力差距超过20%判定胜负,否则平局 + if (attackerPower > defenderPower * 1.2) { + winner = 'attacker' + } else if (defenderPower > attackerPower * 1.2) { + winner = 'defender' + } else { + winner = 'draw' + } + } else { + // OGame原版规则:6回合后双方都有剩余单位时判定为平局 + winner = 'draw' + } } return { diff --git a/src/views/BattleSimulatorView.vue b/src/views/BattleSimulatorView.vue index 7e4a783..1655800 100644 --- a/src/views/BattleSimulatorView.vue +++ b/src/views/BattleSimulatorView.vue @@ -57,9 +57,15 @@ - - {{ t('simulatorView.defenderConfig') }} - {{ t('simulatorView.defenderConfigDesc') }} + +
+ {{ t('simulatorView.defenderConfig') }} + {{ t('simulatorView.defenderConfigDesc') }} +
+ @@ -147,28 +153,80 @@ + + + + + + {{ t('simulatorView.selectSpyReport') }} + +
+
+ {{ t('simulatorView.noSpyReports') }} +
+
+
+
+
{{ report.targetPlanetName }}
+
+ [{{ report.targetPosition.galaxy }}:{{ report.targetPosition.system }}:{{ report.targetPosition.position }}] +
+
+
+ {{ formatTime(report.timestamp) }} +
+
+
+ + + {{ formatNumber(report.resources.metal) }} + + + + {{ formatNumber(report.resources.crystal) }} + + + + {{ formatNumber(report.resources.deuterium) }} + +
+
+
+
+
diff --git a/src/views/FleetView.vue b/src/views/FleetView.vue index bed1b85..b9c5dd5 100644 --- a/src/views/FleetView.vue +++ b/src/views/FleetView.vue @@ -10,8 +10,8 @@ {{ t(`fleetView.${tab.labelKey}`) }} - - {{ gameStore.player.fleetMissions.length }} + + {{ totalMissionsCount }} @@ -294,13 +294,14 @@ - + {{ t('fleetView.noFlightMissions') }} +
@@ -378,6 +379,44 @@
+ + + + +
+
+ + + {{ t('galaxyView.missileAttackTitle') }} + + + {{ getPlanetName(missileAttack.originPlanetId) }} → [{{ missileAttack.targetPosition.galaxy }}:{{ missileAttack.targetPosition.system }}:{{ + missileAttack.targetPosition.position + }}] + +
+ + {{ t('fleetView.outbound') }} + +
+
+ + +
+

{{ t('galaxyView.missileCount') }}:

+ {{ missileAttack.missileCount }} +
+ + +
+
+ {{ t('fleetView.arrivalTime') }}: + {{ formatTime(getMissileRemainingTime(missileAttack)) }} +
+ +
+
+
@@ -591,7 +630,8 @@ Clock, Check, Globe, - Moon + Moon, + Crosshair } from 'lucide-vue-next' import { formatNumber, formatTime } from '@/utils/format' import * as shipValidation from '@/logic/shipValidation' @@ -628,6 +668,16 @@ return publicLogic.getMaxFleetMissions(bonuses.additionalFleetSlots, computerTechLevel) }) + // 飞行中的导弹攻击 + const flyingMissileAttacks = computed(() => { + return gameStore.player.missileAttacks?.filter(m => m.status === 'flying') || [] + }) + + // 总任务数量(舰队任务 + 导弹攻击) + const totalMissionsCount = computed(() => { + return gameStore.player.fleetMissions.length + flyingMissileAttacks.value.length + }) + const activeTab = ref<'send' | 'missions' | 'jumpGate'>('send') // Tab 配置 @@ -837,6 +887,8 @@ selectedMission.value = MissionType.Attack } else if (mission === 'colonize') { selectedMission.value = MissionType.Colonize + } else if (mission === 'recycle') { + selectedMission.value = MissionType.Recycle } else if (gift === '1') { // 如果有gift参数,设置为运输任务并启用赠送模式 selectedMission.value = MissionType.Transport @@ -1413,4 +1465,18 @@ return Math.max(0, Math.min(100, (elapsed / total) * 100)) } } + + // 获取导弹任务剩余时间 + const getMissileRemainingTime = (missileAttack: any): number => { + const now = currentTime.value + return Math.max(0, (missileAttack.arrivalTime - now) / 1000) + } + + // 获取导弹任务进度 + const getMissileProgress = (missileAttack: any): number => { + const now = currentTime.value + const total = missileAttack.arrivalTime - missileAttack.launchTime + const elapsed = now - missileAttack.launchTime + return Math.max(0, Math.min(100, (elapsed / total) * 100)) + } diff --git a/src/views/GalaxyView.vue b/src/views/GalaxyView.vue index 5c9e85a..9c5b8b9 100644 --- a/src/views/GalaxyView.vue +++ b/src/views/GalaxyView.vue @@ -66,7 +66,7 @@ {{ t('galaxyView.myPlanets') }} - +
{{ t('galaxyView.selectPlanetToView') }} @@ -114,7 +114,7 @@ {{ highlightedNpc.name }} ({{ highlightedNpc.planets.length }}) - +
{{ t('galaxyView.selectPlanetToView') }} diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue index 6b3a452..03c3980 100644 --- a/src/views/HomeView.vue +++ b/src/views/HomeView.vue @@ -149,11 +149,11 @@ @keyframes fadeIn { from { opacity: 0; - transform: translateY(-10px); + transform: translate3d(0, -10px, 0); } to { opacity: 1; - transform: translateY(0); + transform: translate3d(0, 0, 0); } } diff --git a/src/views/OverviewView.vue b/src/views/OverviewView.vue index 1cca6d2..eaa773f 100644 --- a/src/views/OverviewView.vue +++ b/src/views/OverviewView.vue @@ -22,8 +22,47 @@
+ +
+ +
+ + + + + {{ t('planet.confirmAbandon') }} + + {{ t('planet.abandonWarning', { name: planet.name }) }} + + + + {{ t('common.cancel') }} + + {{ t('planet.confirmAbandonButton') }} + + + + + + + + + + {{ t('planet.abandonFailed') }} + + {{ errorMessage }} + + + + {{ t('common.confirm') }} + + + + @@ -195,25 +234,45 @@ import { useGameStore } from '@/stores/gameStore' import { useI18n } from '@/composables/useI18n' import { useGameConfig } from '@/composables/useGameConfig' - import { computed } from 'vue' + import { computed, ref } from 'vue' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' + import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle + } from '@/components/ui/alert-dialog' import ResourceIcon from '@/components/common/ResourceIcon.vue' import { formatNumber, getResourceColor } from '@/utils/format' import { scaleNumber } from '@/utils/speed' import type { Planet } from '@/types/game' + import { TechnologyType } from '@/types/game' import * as publicLogic from '@/logic/publicLogic' import * as resourceLogic from '@/logic/resourceLogic' + import * as planetLogic from '@/logic/planetLogic' const gameStore = useGameStore() const { t } = useI18n() const { SHIPS } = useGameConfig() const planet = computed(() => gameStore.currentPlanet) + + // 获取科技加成 + const techBonuses = computed(() => ({ + mineralResearchLevel: gameStore.player.technologies[TechnologyType.MineralResearch] || 0, + crystalResearchLevel: gameStore.player.technologies[TechnologyType.CrystalResearch] || 0, + fuelResearchLevel: gameStore.player.technologies[TechnologyType.FuelResearch] || 0 + })) + const production = computed(() => - planet.value ? publicLogic.getResourceProduction(planet.value, gameStore.player.officers, gameStore.gameSpeed) : null + planet.value ? publicLogic.getResourceProduction(planet.value, gameStore.player.officers, gameStore.gameSpeed, techBonuses.value) : null ) const capacity = computed(() => (planet.value ? publicLogic.getResourceCapacity(planet.value, gameStore.player.officers) : null)) @@ -226,7 +285,7 @@ // 资源产量详细breakdown const productionBreakdown = computed(() => { if (!planet.value) return null - return resourceLogic.calculateProductionBreakdown(planet.value, gameStore.player.officers, Date.now(), gameStore.gameSpeed) + return resourceLogic.calculateProductionBreakdown(planet.value, gameStore.player.officers, Date.now(), gameStore.gameSpeed, techBonuses.value) }) // 资源消耗详细breakdown @@ -286,4 +345,45 @@ gameStore.currentPlanetId = planet.value.parentPlanetId } } + + // 放弃殖民地相关 + const showAbandonDialog = ref(false) + const showErrorDialog = ref(false) + const errorMessage = ref('') + + // 是否显示放弃按钮(非主星才显示) + const canShowAbandonButton = computed(() => { + if (!planet.value) return false + // 找到主星(第一个非月球星球) + const mainPlanet = gameStore.player.planets.find(p => !p.isMoon) + // 当前星球不是主星时才显示放弃按钮 + return mainPlanet && mainPlanet.id !== planet.value.id + }) + + // 处理放弃殖民地 + const handleAbandonColony = () => { + if (!planet.value) return + + const check = planetLogic.canAbandonColony(gameStore.player.planets, planet.value.id) + if (!check.canAbandon) { + showAbandonDialog.value = false + errorMessage.value = check.reason ? t(check.reason) : t('planet.abandonFailed') + showErrorDialog.value = true + return + } + + // 记录当前星球ID用于后续切换 + const abandonedPlanetId = planet.value.id + + // 执行放弃 + gameStore.player.planets = planetLogic.abandonColony(gameStore.player.planets, abandonedPlanetId) + + // 切换到主星 + const mainPlanet = gameStore.player.planets.find(p => !p.isMoon) + if (mainPlanet) { + gameStore.currentPlanetId = mainPlanet.id + } + + showAbandonDialog.value = false + } diff --git a/src/views/ResearchView.vue b/src/views/ResearchView.vue index 8eb954a..b4b7749 100644 --- a/src/views/ResearchView.vue +++ b/src/views/ResearchView.vue @@ -175,7 +175,8 @@ techType, currentLevel, gameStore.player.officers, - gameStore.player.technologies + gameStore.player.technologies, + gameStore.player.planets ) gameStore.player.researchQueue.push(queueItem) return true @@ -333,11 +334,33 @@ const getResearchTime = (techType: TechnologyType): number => { if (!planet.value) return 0 const currentLevel = getTechLevel(techType) - const researchLabLevel = planet.value.buildings['researchLab'] || 0 + const intergalacticResearchNetworkLevel = player.value.technologies[TechnologyType.IntergalacticResearchNetwork] || 0 + + // 计算有效研究实验室等级(考虑星际研究网络) + let researchLabLevel: number + if (intergalacticResearchNetworkLevel > 0) { + researchLabLevel = researchLogic.calculateEffectiveLabLevel( + gameStore.player.planets, + planet.value.id, + intergalacticResearchNetworkLevel + ) + } else { + researchLabLevel = planet.value.buildings['researchLab'] || 0 + } + const energyTechLevel = player.value.technologies['energyTechnology'] || 0 + const universityLevel = planet.value.buildings['university'] || 0 const bonuses = officerLogic.calculateActiveBonuses(player.value.officers, gameStore.gameTime) - return researchLogic.calculateTechnologyTime(techType, currentLevel, bonuses.researchSpeedBonus, researchLabLevel, energyTechLevel) + return researchLogic.calculateTechnologyTime( + techType, + currentLevel, + bonuses.researchSpeedBonus, + researchLabLevel, + energyTechLevel, + 1, + universityLevel + ) } // 检查是否可以添加到等待队列 diff --git a/src/views/SettingsView.vue b/src/views/SettingsView.vue index e966a90..3e6e798 100644 --- a/src/views/SettingsView.vue +++ b/src/views/SettingsView.vue @@ -114,6 +114,15 @@ {{ gameStore.isPaused ? t('settings.resume') : t('settings.pause') }}
+ + +
+
+

{{ t('settings.battleMode') }}

+

{{ t('settings.battleModeDesc') }}

+
+ +
@@ -581,12 +590,22 @@ const fileName = `${pkg.name}-${new Date().toISOString().slice(0, 10)}-${Date.now()}.json` const jsonString = JSON.stringify(exportData, null, 2) - // Android 保存到 Documents 目录 + // Android 保存到公共 Downloads 目录 if (Capacitor.isNativePlatform()) { + // 检查并请求存储权限 + const permStatus = await Filesystem.checkPermissions() + if (permStatus.publicStorage !== 'granted') { + const reqResult = await Filesystem.requestPermissions() + if (reqResult.publicStorage !== 'granted') { + toast.error(t('settings.storagePermissionDenied')) + return + } + } + const result = await Filesystem.writeFile({ - path: fileName, + path: `Download/${fileName}`, data: jsonString, - directory: Directory.Documents, + directory: Directory.ExternalStorage, encoding: Encoding.UTF8 }) toast.success(t('settings.exportSuccessWithPath', { path: result.uri })) diff --git a/src/views/ShipyardView.vue b/src/views/ShipyardView.vue index b70b141..72bab0a 100644 --- a/src/views/ShipyardView.vue +++ b/src/views/ShipyardView.vue @@ -101,6 +101,20 @@ />
+ +
+ + +
+

{{ t('shipyardView.totalCost') }}:

@@ -133,6 +147,36 @@ > {{ t('queue.addToWaiting') }} + + +
+

{{ t('shipyardView.scrapRefund') }}:

+
+
+ + {{ t(`resources.${resourceType.key}`) }}: + + +{{ formatNumber(getScrapRefund(shipType)[resourceType.key]) }} + +
+
+
+ + +
@@ -243,6 +287,25 @@ [ShipType.Deathstar]: 0 }) + // 每种舰船的拆除数量 + const scrapQuantities = ref>({ + [ShipType.LightFighter]: 0, + [ShipType.HeavyFighter]: 0, + [ShipType.Cruiser]: 0, + [ShipType.Battleship]: 0, + [ShipType.Battlecruiser]: 0, + [ShipType.Bomber]: 0, + [ShipType.Destroyer]: 0, + [ShipType.SmallCargo]: 0, + [ShipType.LargeCargo]: 0, + [ShipType.ColonyShip]: 0, + [ShipType.Recycler]: 0, + [ShipType.EspionageProbe]: 0, + [ShipType.SolarSatellite]: 0, + [ShipType.DarkMatterHarvester]: 0, + [ShipType.Deathstar]: 0 + }) + const buildShip = (shipType: ShipType, quantity: number): { success: boolean; reason?: string } => { if (!gameStore.currentPlanet) return { success: false } const validation = shipValidation.validateShipBuild(gameStore.currentPlanet, shipType, quantity, gameStore.player.technologies) @@ -380,4 +443,54 @@ waitingQueueLogic.addToBuildWaitingQueue(planet.value, item) quantities.value[shipType] = 0 } + + // 计算拆除返还资源 + const getScrapRefund = (shipType: ShipType) => { + const quantity = scrapQuantities.value[shipType] + return shipLogic.calculateShipScrapRefund(shipType, quantity) + } + + // 检查是否可以拆除 + const canScrap = (shipType: ShipType): boolean => { + if (!planet.value) return false + + const quantity = scrapQuantities.value[shipType] + if (quantity <= 0) return false + + const available = planet.value.fleet[shipType] || 0 + return available >= quantity + } + + // 拆除舰船 + const handleScrap = (shipType: ShipType, _event: MouseEvent) => { + // 防抖:防止快速点击 + if (isProcessing.value) return + isProcessing.value = true + setTimeout(() => { + isProcessing.value = false + }, DEBOUNCE_DELAY) + + const quantity = scrapQuantities.value[shipType] + if (quantity <= 0) { + alertDialogTitle.value = t('shipyardView.inputError') + alertDialogMessage.value = t('shipyardView.inputErrorMessage') + alertDialogOpen.value = true + return + } + + if (!gameStore.currentPlanet) return + + const validation = shipValidation.validateShipScrap(gameStore.currentPlanet, shipType, quantity) + if (!validation.valid) { + alertDialogTitle.value = t('shipyardView.scrapFailed') + alertDialogMessage.value = validation.reason ? t(validation.reason) : t('shipyardView.scrapFailedMessage') + alertDialogOpen.value = true + return + } + + // 执行拆除 + const queueItem = shipValidation.executeShipScrap(gameStore.currentPlanet, shipType, quantity, gameStore.player.officers) + gameStore.currentPlanet.buildQueue.push(queueItem) + scrapQuantities.value[shipType] = 0 + } diff --git a/src/workers/battle.worker.ts b/src/workers/battle.worker.ts index 05e3591..278a69d 100644 --- a/src/workers/battle.worker.ts +++ b/src/workers/battle.worker.ts @@ -304,8 +304,24 @@ const simulateBattle = (attacker: BattleSideData, defender: BattleSideData, maxR } else if (defenderUnits.length === 0) { winner = 'attacker' } else { - // OGame原版规则:6回合后双方都有剩余单位时判定为平局 - winner = 'draw' + // 达到最大回合数后双方都有剩余单位 + // 如果是战斗到底模式(maxRounds > 6),根据剩余战力判定胜负 + if (maxRounds > 6) { + // 计算剩余战力 + const attackerPower = attackerUnits.reduce((sum, u) => sum + u.count * u.armor, 0) + const defenderPower = defenderUnits.reduce((sum, u) => sum + u.count * u.armor, 0) + // 战力差距超过20%判定胜负,否则平局 + if (attackerPower > defenderPower * 1.2) { + winner = 'attacker' + } else if (defenderPower > attackerPower * 1.2) { + winner = 'defender' + } else { + winner = 'draw' + } + } else { + // OGame原版规则:6回合后双方都有剩余单位时判定为平局 + winner = 'draw' + } } return { diff --git a/vite.config.ts b/vite.config.ts index 2be8e01..c4fed7f 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -23,14 +23,7 @@ export default defineConfig(async () => { background_color: '#000000', display: 'fullscreen', orientation: 'any', - icons: [ - { - src: 'logo.svg', - sizes: 'any', - type: 'image/svg+xml', - purpose: 'any' - } - ] + icons: [{ src: 'logo.svg', sizes: 'any', type: 'image/svg+xml', purpose: 'any' }] }, workbox: { globPatterns: ['**/*.{js,css,html,ico,png,svg,mp3,wav,json}'], @@ -39,13 +32,7 @@ export default defineConfig(async () => { { urlPattern: ({ request }) => request.destination === 'image' || request.destination === 'audio', handler: 'CacheFirst', // 优先使用缓存 - options: { - cacheName: 'game-assets', - expiration: { - maxEntries: 100, - maxAgeSeconds: 30 * 24 * 60 * 60 // 缓存 30 天 - } - } + options: { cacheName: 'game-assets', expiration: { maxEntries: 100, maxAgeSeconds: 30 * 24 * 60 * 60 } } } ] } @@ -113,16 +100,14 @@ export default defineConfig(async () => { // 使用 lightningcss 处理 CSS,自动转换 oklch 等新语法为兼容格式 transformer: 'lightningcss', lightningcss: { - // 目标浏览器:Android 5+, iOS 10+, Chrome 60+ + // 目标浏览器:降低到更保守的版本以支持华为等国产手机 WebView targets: { - android: 5 << 16, // Android 5.0 - chrome: 60 << 16, // Chrome 60 - ios_saf: 10 << 16 // iOS Safari 10 + android: (4 << 16) | (4 << 8), // Android 4.4 + chrome: 49 << 16, // Chrome 49 (Android 4.4 WebView) + ios_saf: (9 << 16) | (3 << 8) // iOS Safari 9.3 }, // 禁用现代 CSS 特性,确保兼容旧版浏览器 - drafts: { - customMedia: false - } + drafts: { customMedia: false } } }, // 优化依赖预构建 diff --git a/调整基础矿脉恢复速度.ini b/调整基础矿脉恢复速度.ini new file mode 100644 index 0000000..73801a0 --- /dev/null +++ b/调整基础矿脉恢复速度.ini @@ -0,0 +1,28 @@ +OGame-Vue-Ts v1.6.0 更新说明 + +调整基础矿脉恢复速度 +调整地质研究站每级恢复速率 +调整建造死星所需资源 +修复研究等待队列资源扣除但等级不增加的问题 +修复攻击NPC后NPC拥有资源不减少的问题 +修复导弹攻击后反弹道导弹不减少的问题 +修复矿脉上限加成计算错误问题 +为战斗模拟器新增加从侦查报告一键填入的功能 +调整建筑与研究升级时间 +修复文本丢失问题 +调整月球基地初始建造成本 +修复无法派遣舰队到自己星球位置的问题 +修复敌对NPC会无脑派遣舰队回收残骸导致产生更多残骸的恶性循环问题 +修复敌对NPC反复派回收船到玩家星球的问题 +修复NPC无脑进攻问题 +修复贸易邮件大量生成导致淹没其他邮件问题 +添加舰船拆除功能 +添加放弃殖民地功能 +修复从月球切换回母星会触发白屏问题 +修复死星毁灭任务跳过战斗的问题 +修复对战动画偶现卡顿导致弹窗无响应问题 +增加战斗到底模式, 开启后支持最多战斗100回合 + +添加建筑: 大学 +添加科技: 星际研究网络, 矿物研究, 晶体研究, 燃料研究 +