Files
ogame-vue-ts/src/logic/resourceLogic.ts
谦君 9b9fda0400 feat: 新增NPC与外交逻辑,优化UI组件结构
重构并精简了部分UI组件,移除冗余弹窗与详情组件,新增NPC相关逻辑(npcBehaviorLogic、npcGrowthLogic、npcStore等)及外交逻辑(diplomaticLogic、DiplomacyView)。完善分页、标签、复选框等通用UI组件。优化战报弹窗,调整README下载链接为相对路径,修复部分国际化内容。
2025-12-15 08:23:45 +08:00

505 lines
17 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Planet, Resources, Officer } from '@/types/game'
import { BuildingType, OfficerType } from '@/types/game'
import * as officerLogic from './officerLogic'
import { OFFICERS } from '@/config/gameConfig'
/**
* 计算电量产出
*/
export const calculateEnergyProduction = (
planet: Planet,
bonuses: {
energyProductionBonus: number
}
): number => {
const solarPlantLevel = planet.buildings[BuildingType.SolarPlant] || 0
const fusionReactorLevel = planet.buildings[BuildingType.FusionReactor] || 0
const solarSatelliteCount = planet.fleet.solarSatellite || 0
const energyBonus = 1 + (bonuses.energyProductionBonus || 0) / 100
// 太阳能电站每级产出50 * 1.1^等级
const solarPlantProduction = solarPlantLevel * 50 * Math.pow(1.1, solarPlantLevel)
// 核聚变反应堆每级产出150 * 1.15^等级(消耗重氢)
const fusionReactorProduction = fusionReactorLevel * 150 * Math.pow(1.15, fusionReactorLevel)
// 太阳能卫星每个产出50点能量
const solarSatelliteProduction = solarSatelliteCount * 50
return (solarPlantProduction + fusionReactorProduction + solarSatelliteProduction) * energyBonus
}
/**
* 计算电量消耗
*/
export const calculateEnergyConsumption = (planet: Planet): number => {
const metalMineLevel = planet.buildings[BuildingType.MetalMine] || 0
const crystalMineLevel = planet.buildings[BuildingType.CrystalMine] || 0
const deuteriumSynthesizerLevel = planet.buildings[BuildingType.DeuteriumSynthesizer] || 0
// 矿场每级消耗10 * 1.1^等级
const metalConsumption = metalMineLevel * 10 * Math.pow(1.1, metalMineLevel)
const crystalConsumption = crystalMineLevel * 10 * Math.pow(1.1, crystalMineLevel)
const deuteriumConsumption = deuteriumSynthesizerLevel * 15 * Math.pow(1.1, deuteriumSynthesizerLevel)
return metalConsumption + crystalConsumption + deuteriumConsumption
}
/**
* 计算资源产量(每小时)
*/
export const calculateResourceProduction = (
planet: Planet,
bonuses: {
resourceProductionBonus: number
darkMatterProductionBonus: number
energyProductionBonus: number
}
): Resources => {
const metalMineLevel = planet.buildings[BuildingType.MetalMine] || 0
const crystalMineLevel = planet.buildings[BuildingType.CrystalMine] || 0
const deuteriumSynthesizerLevel = planet.buildings[BuildingType.DeuteriumSynthesizer] || 0
const darkMatterCollectorLevel = planet.buildings[BuildingType.DarkMatterCollector] || 0
const resourceBonus = 1 + (bonuses.resourceProductionBonus || 0) / 100
const darkMatterBonus = 1 + (bonuses.darkMatterProductionBonus || 0) / 100
// 计算能量产出(每小时)
const energyProduction = calculateEnergyProduction(planet, { energyProductionBonus: bonuses.energyProductionBonus })
// 检查当前能量是否充足
// 如果当前能量 <= 0矿场停止生产
const hasEnergy = planet.resources.energy > 0
const productionEfficiency = hasEnergy ? 1 : 0
return {
metal: metalMineLevel * 1500 * Math.pow(1.5, metalMineLevel) * resourceBonus * productionEfficiency,
crystal: crystalMineLevel * 1000 * Math.pow(1.5, crystalMineLevel) * resourceBonus * productionEfficiency,
deuterium: deuteriumSynthesizerLevel * 500 * Math.pow(1.5, deuteriumSynthesizerLevel) * resourceBonus * productionEfficiency,
darkMatter: darkMatterCollectorLevel * 25 * Math.pow(1.5, darkMatterCollectorLevel) * darkMatterBonus,
energy: energyProduction
}
}
/**
* 计算资源容量
*/
export const calculateResourceCapacity = (planet: Planet, storageCapacityBonus: number): Resources => {
const metalStorageLevel = planet.buildings[BuildingType.MetalStorage] || 0
const crystalStorageLevel = planet.buildings[BuildingType.CrystalStorage] || 0
const deuteriumTankLevel = planet.buildings[BuildingType.DeuteriumTank] || 0
const darkMatterTankLevel = planet.buildings[BuildingType.DarkMatterTank] || 0
const solarPlantLevel = planet.buildings[BuildingType.SolarPlant] || 0
const bonus = 1 + (storageCapacityBonus || 0) / 100
const baseCapacity = 10000
const darkMatterBaseCapacity = 1000 // 暗物质基础容量较小
return {
metal: baseCapacity * Math.pow(2, metalStorageLevel) * bonus,
crystal: baseCapacity * Math.pow(2, crystalStorageLevel) * bonus,
deuterium: baseCapacity * Math.pow(2, deuteriumTankLevel) * bonus,
darkMatter: darkMatterBaseCapacity * Math.pow(2, darkMatterTankLevel) * bonus,
energy: 1000 + solarPlantLevel * 500 // 能量容量基于太阳能电站等级
}
}
/**
* 更新星球资源
*/
export const updatePlanetResources = (
planet: Planet,
now: number,
bonuses: {
resourceProductionBonus: number
darkMatterProductionBonus: number
energyProductionBonus: number
storageCapacityBonus: number
}
): void => {
const timeDiff = (now - planet.lastUpdate) / 1000 // 转换为秒
// 计算能量消耗(每小时)
const energyConsumption = calculateEnergyConsumption(planet)
// 先增加能量产出
const energyProduction = calculateEnergyProduction(planet, { energyProductionBonus: bonuses.energyProductionBonus })
planet.resources.energy += (energyProduction * timeDiff) / 3600
// 限制能量上限
const capacity = calculateResourceCapacity(planet, bonuses.storageCapacityBonus)
planet.resources.energy = Math.min(planet.resources.energy, capacity.energy)
// 扣除能量消耗
planet.resources.energy -= (energyConsumption * timeDiff) / 3600
// 能量不能为负数最低为0
planet.resources.energy = Math.max(0, planet.resources.energy)
// 计算资源产量(会检查能量是否充足)
const production = calculateResourceProduction(planet, {
resourceProductionBonus: bonuses.resourceProductionBonus,
darkMatterProductionBonus: bonuses.darkMatterProductionBonus,
energyProductionBonus: bonuses.energyProductionBonus
})
// 更新资源(转换为每秒产量)
planet.resources.metal += (production.metal * timeDiff) / 3600
planet.resources.crystal += (production.crystal * timeDiff) / 3600
planet.resources.deuterium += (production.deuterium * timeDiff) / 3600
planet.resources.darkMatter += (production.darkMatter * timeDiff) / 3600
// 限制资源上限
planet.resources.metal = Math.min(planet.resources.metal, capacity.metal)
planet.resources.crystal = Math.min(planet.resources.crystal, capacity.crystal)
planet.resources.deuterium = Math.min(planet.resources.deuterium, capacity.deuterium)
planet.resources.darkMatter = Math.min(planet.resources.darkMatter, capacity.darkMatter)
planet.lastUpdate = now
}
/**
* 检查资源是否足够
*/
export const checkResourcesAvailable = (currentResources: Resources, cost: Resources): boolean => {
return (
currentResources.metal >= cost.metal &&
currentResources.crystal >= cost.crystal &&
currentResources.deuterium >= cost.deuterium &&
currentResources.darkMatter >= cost.darkMatter
)
}
/**
* 扣除资源
*/
export const deductResources = (currentResources: Resources, cost: Resources): void => {
currentResources.metal -= cost.metal
currentResources.crystal -= cost.crystal
currentResources.deuterium -= cost.deuterium
currentResources.darkMatter -= cost.darkMatter
}
/**
* 添加资源
*/
export const addResources = (currentResources: Resources, amount: Resources): void => {
currentResources.metal += amount.metal
currentResources.crystal += amount.crystal
currentResources.deuterium += amount.deuterium
currentResources.darkMatter += amount.darkMatter
}
/**
* 资源产量详细信息用于UI展示
*/
export interface ProductionBreakdown {
metal: ProductionDetail
crystal: ProductionDetail
deuterium: ProductionDetail
darkMatter: ProductionDetail
energy: ProductionDetail
}
export interface ProductionDetail {
baseProduction: number // 建筑基础产量
buildingLevel: number // 建筑等级
buildingName: string // 建筑名称(用于显示)
bonuses: ProductionBonus[] // 加成列表
finalProduction: number // 最终产量
sources?: ProductionSource[] // 多个产量来源(用于能量)
}
export interface ProductionSource {
name: string // 来源名称
level: number // 等级或数量
production: number // 产量
}
export interface ProductionBonus {
name: string // 加成名称
percentage: number // 加成百分比
value: number // 实际增加的产量
source: 'technology' | 'officer' | 'other' // 加成来源类型
}
/**
* 能量消耗详细信息
*/
export interface ConsumptionBreakdown {
metalMine: ConsumptionDetail
crystalMine: ConsumptionDetail
deuteriumSynthesizer: ConsumptionDetail
total: number
}
export interface ConsumptionDetail {
buildingLevel: number
buildingName: string
consumption: number
}
/**
* 计算资源产量详细breakdown
*/
export const calculateProductionBreakdown = (
planet: Planet,
officers: Record<OfficerType, Officer>,
currentTime: number
): ProductionBreakdown => {
const metalMineLevel = planet.buildings[BuildingType.MetalMine] || 0
const crystalMineLevel = planet.buildings[BuildingType.CrystalMine] || 0
const deuteriumSynthesizerLevel = planet.buildings[BuildingType.DeuteriumSynthesizer] || 0
const darkMatterCollectorLevel = planet.buildings[BuildingType.DarkMatterCollector] || 0
const solarPlantLevel = planet.buildings[BuildingType.SolarPlant] || 0
const hasEnergy = planet.resources.energy > 0
const productionEfficiency = hasEnergy ? 1 : 0
// 收集每个军官的加成信息
const activeOfficerBonuses: Array<{
type: OfficerType
name: string
resourceBonus: number
darkMatterBonus: number
energyBonus: number
}> = []
Object.values(officers).forEach(officer => {
if (officerLogic.isOfficerActive(officer, currentTime)) {
const config = OFFICERS[officer.type]
activeOfficerBonuses.push({
type: officer.type,
name: config.name,
resourceBonus: config.benefits.resourceProductionBonus || 0,
darkMatterBonus: config.benefits.darkMatterProductionBonus || 0,
energyBonus: config.benefits.energyProductionBonus || 0
})
}
})
// 计算总加成
const totalResourceBonus = activeOfficerBonuses.reduce((sum, officer) => sum + officer.resourceBonus, 0)
const totalDarkMatterBonus = activeOfficerBonuses.reduce((sum, officer) => sum + officer.darkMatterBonus, 0)
const totalEnergyBonus = activeOfficerBonuses.reduce((sum, officer) => sum + officer.energyBonus, 0)
// 金属矿产量
const metalBase = metalMineLevel * 1500 * Math.pow(1.5, metalMineLevel)
const metalBonuses: ProductionBonus[] = []
// 为每个激活的军官添加加成项
activeOfficerBonuses.forEach(officer => {
if (officer.resourceBonus > 0) {
const bonusValue = metalBase * (officer.resourceBonus / 100)
metalBonuses.push({
name: `officers.${officer.type}`,
percentage: officer.resourceBonus,
value: bonusValue,
source: 'officer'
})
}
})
if (!hasEnergy) {
metalBonuses.push({
name: 'resources.noEnergy',
percentage: -100,
value: -metalBase * (1 + totalResourceBonus / 100),
source: 'other'
})
}
const metalFinal = metalBase * (1 + totalResourceBonus / 100) * productionEfficiency
// 晶体矿产量
const crystalBase = crystalMineLevel * 1000 * Math.pow(1.5, crystalMineLevel)
const crystalBonuses: ProductionBonus[] = []
activeOfficerBonuses.forEach(officer => {
if (officer.resourceBonus > 0) {
const bonusValue = crystalBase * (officer.resourceBonus / 100)
crystalBonuses.push({
name: `officers.${officer.type}`,
percentage: officer.resourceBonus,
value: bonusValue,
source: 'officer'
})
}
})
if (!hasEnergy) {
crystalBonuses.push({
name: 'resources.noEnergy',
percentage: -100,
value: -crystalBase * (1 + totalResourceBonus / 100),
source: 'other'
})
}
const crystalFinal = crystalBase * (1 + totalResourceBonus / 100) * productionEfficiency
// 重氢合成器产量
const deuteriumBase = deuteriumSynthesizerLevel * 500 * Math.pow(1.5, deuteriumSynthesizerLevel)
const deuteriumBonuses: ProductionBonus[] = []
activeOfficerBonuses.forEach(officer => {
if (officer.resourceBonus > 0) {
const bonusValue = deuteriumBase * (officer.resourceBonus / 100)
deuteriumBonuses.push({
name: `officers.${officer.type}`,
percentage: officer.resourceBonus,
value: bonusValue,
source: 'officer'
})
}
})
if (!hasEnergy) {
deuteriumBonuses.push({
name: 'resources.noEnergy',
percentage: -100,
value: -deuteriumBase * (1 + totalResourceBonus / 100),
source: 'other'
})
}
const deuteriumFinal = deuteriumBase * (1 + totalResourceBonus / 100) * productionEfficiency
// 暗物质收集器产量
const darkMatterBase = darkMatterCollectorLevel * 25 * Math.pow(1.5, darkMatterCollectorLevel)
const darkMatterBonuses: ProductionBonus[] = []
activeOfficerBonuses.forEach(officer => {
if (officer.darkMatterBonus > 0) {
const bonusValue = darkMatterBase * (officer.darkMatterBonus / 100)
darkMatterBonuses.push({
name: `officers.${officer.type}`,
percentage: officer.darkMatterBonus,
value: bonusValue,
source: 'officer'
})
}
})
const darkMatterFinal = darkMatterBase * (1 + totalDarkMatterBonus / 100)
// 能量产量(包含多个来源)
const fusionReactorLevel = planet.buildings[BuildingType.FusionReactor] || 0
const solarSatelliteCount = planet.fleet.solarSatellite || 0
const solarPlantProduction = solarPlantLevel * 50 * Math.pow(1.1, solarPlantLevel)
const fusionReactorProduction = fusionReactorLevel * 150 * Math.pow(1.15, fusionReactorLevel)
const solarSatelliteProduction = solarSatelliteCount * 50
const energyBase = solarPlantProduction + fusionReactorProduction + solarSatelliteProduction
const energySources: ProductionSource[] = []
if (solarPlantLevel > 0) {
energySources.push({
name: 'buildings.solarPlant',
level: solarPlantLevel,
production: solarPlantProduction
})
}
if (fusionReactorLevel > 0) {
energySources.push({
name: 'buildings.fusionReactor',
level: fusionReactorLevel,
production: fusionReactorProduction
})
}
if (solarSatelliteCount > 0) {
energySources.push({
name: 'ships.solarSatellite',
level: solarSatelliteCount,
production: solarSatelliteProduction
})
}
const energyBonuses: ProductionBonus[] = []
activeOfficerBonuses.forEach(officer => {
if (officer.energyBonus > 0) {
const bonusValue = energyBase * (officer.energyBonus / 100)
energyBonuses.push({
name: `officers.${officer.type}`,
percentage: officer.energyBonus,
value: bonusValue,
source: 'officer'
})
}
})
const energyFinal = energyBase * (1 + totalEnergyBonus / 100)
return {
metal: {
baseProduction: metalBase,
buildingLevel: metalMineLevel,
buildingName: 'buildings.metalMine',
bonuses: metalBonuses,
finalProduction: metalFinal
},
crystal: {
baseProduction: crystalBase,
buildingLevel: crystalMineLevel,
buildingName: 'buildings.crystalMine',
bonuses: crystalBonuses,
finalProduction: crystalFinal
},
deuterium: {
baseProduction: deuteriumBase,
buildingLevel: deuteriumSynthesizerLevel,
buildingName: 'buildings.deuteriumSynthesizer',
bonuses: deuteriumBonuses,
finalProduction: deuteriumFinal
},
darkMatter: {
baseProduction: darkMatterBase,
buildingLevel: darkMatterCollectorLevel,
buildingName: 'buildings.darkMatterCollector',
bonuses: darkMatterBonuses,
finalProduction: darkMatterFinal
},
energy: {
baseProduction: energyBase,
buildingLevel: solarPlantLevel,
buildingName: 'buildings.solarPlant',
bonuses: energyBonuses,
finalProduction: energyFinal,
sources: energySources
}
}
}
/**
* 计算能量消耗详细breakdown
*/
export const calculateConsumptionBreakdown = (planet: Planet): ConsumptionBreakdown => {
const metalMineLevel = planet.buildings[BuildingType.MetalMine] || 0
const crystalMineLevel = planet.buildings[BuildingType.CrystalMine] || 0
const deuteriumSynthesizerLevel = planet.buildings[BuildingType.DeuteriumSynthesizer] || 0
const metalConsumption = metalMineLevel * 10 * Math.pow(1.1, metalMineLevel)
const crystalConsumption = crystalMineLevel * 10 * Math.pow(1.1, crystalMineLevel)
const deuteriumConsumption = deuteriumSynthesizerLevel * 15 * Math.pow(1.1, deuteriumSynthesizerLevel)
return {
metalMine: {
buildingLevel: metalMineLevel,
buildingName: 'buildings.metalMine',
consumption: metalConsumption
},
crystalMine: {
buildingLevel: crystalMineLevel,
buildingName: 'buildings.crystalMine',
consumption: crystalConsumption
},
deuteriumSynthesizer: {
buildingLevel: deuteriumSynthesizerLevel,
buildingName: 'buildings.deuteriumSynthesizer',
consumption: deuteriumConsumption
},
total: metalConsumption + crystalConsumption + deuteriumConsumption
}
}