Files
ogame-vue-ts/src/logic/resourceLogic.ts
lpj 690e6cbbf5 fix: 同步 gameSpeed 倍率展示并修复移动端资源栏遮挡
- 顶部资源栏/概览页:产量、能耗、明细按 gameSpeed 统一缩放,避免显示与实际产出不一致
- 支持 gameSpeed=0:避免 “|| 1” 抹掉 0,并在循环间隔计算中规避除 0
- 修复移动端资源横向滚动时被菜单按钮遮挡(min-w-0/overflow-hidden + 对齐规则)
2025-12-17 22:23:27 +08:00

526 lines
18 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
},
gameSpeed: number = 1
): void => {
const timeDiff = (now - planet.lastUpdate) / 1000 // 转换为秒
// 应用游戏速度到时间差(游戏速度影响资源产出速率)
const effectiveTimeDiff = timeDiff * gameSpeed
// 计算能量消耗(每小时)
const energyConsumption = calculateEnergyConsumption(planet)
// 先增加能量产出
const energyProduction = calculateEnergyProduction(planet, { energyProductionBonus: bonuses.energyProductionBonus })
planet.resources.energy += (energyProduction * effectiveTimeDiff) / 3600
// 限制能量上限
const capacity = calculateResourceCapacity(planet, bonuses.storageCapacityBonus)
planet.resources.energy = Math.min(planet.resources.energy, capacity.energy)
// 扣除能量消耗
planet.resources.energy -= (energyConsumption * effectiveTimeDiff) / 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 * effectiveTimeDiff) / 3600
planet.resources.crystal += (production.crystal * effectiveTimeDiff) / 3600
planet.resources.deuterium += (production.deuterium * effectiveTimeDiff) / 3600
planet.resources.darkMatter += (production.darkMatter * effectiveTimeDiff) / 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,
resourceSpeed: number = 1
): 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)
const speed = resourceSpeed
const scaleBonuses = (bonuses: ProductionBonus[]) =>
bonuses.map(bonus => ({
...bonus,
value: bonus.value * speed
}))
const scaleSources = (sources?: ProductionSource[]) =>
sources?.map(source => ({
...source,
production: source.production * speed
}))
return {
metal: {
baseProduction: metalBase * speed,
buildingLevel: metalMineLevel,
buildingName: 'buildings.metalMine',
bonuses: scaleBonuses(metalBonuses),
finalProduction: metalFinal * speed
},
crystal: {
baseProduction: crystalBase * speed,
buildingLevel: crystalMineLevel,
buildingName: 'buildings.crystalMine',
bonuses: scaleBonuses(crystalBonuses),
finalProduction: crystalFinal * speed
},
deuterium: {
baseProduction: deuteriumBase * speed,
buildingLevel: deuteriumSynthesizerLevel,
buildingName: 'buildings.deuteriumSynthesizer',
bonuses: scaleBonuses(deuteriumBonuses),
finalProduction: deuteriumFinal * speed
},
darkMatter: {
baseProduction: darkMatterBase * speed,
buildingLevel: darkMatterCollectorLevel,
buildingName: 'buildings.darkMatterCollector',
bonuses: scaleBonuses(darkMatterBonuses),
finalProduction: darkMatterFinal * speed
},
energy: {
baseProduction: energyBase * speed,
buildingLevel: solarPlantLevel,
buildingName: 'buildings.solarPlant',
bonuses: scaleBonuses(energyBonuses),
finalProduction: energyFinal * speed,
sources: scaleSources(energySources)
}
}
}
/**
* 计算能量消耗详细breakdown
*/
export const calculateConsumptionBreakdown = (planet: Planet, resourceSpeed: number = 1): 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)
const speed = resourceSpeed
return {
metalMine: {
buildingLevel: metalMineLevel,
buildingName: 'buildings.metalMine',
consumption: metalConsumption * speed
},
crystalMine: {
buildingLevel: crystalMineLevel,
buildingName: 'buildings.crystalMine',
consumption: crystalConsumption * speed
},
deuteriumSynthesizer: {
buildingLevel: deuteriumSynthesizerLevel,
buildingName: 'buildings.deuteriumSynthesizer',
consumption: deuteriumConsumption * speed
},
total: (metalConsumption + crystalConsumption + deuteriumConsumption) * speed
}
}