Files
ogame-vue-ts/src/logic/oreDepositLogic.ts
2026-01-06 03:00:02 +08:00

384 lines
13 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, OreDeposits } from '@/types/game'
import { ORE_DEPOSIT_CONFIG } from '@/config/gameConfig'
/**
* 矿脉上限加成配置
*/
export const ORE_CAPACITY_BONUS = {
// 深层钻探设施每级增加20%矿脉上限
DEEP_DRILLING_BONUS_PER_LEVEL: 0.2,
// 采矿技术每级增加15%矿脉上限(全局)
MINING_TECH_BONUS_PER_LEVEL: 0.15
}
/**
* 计算深层钻探设施的矿脉上限加成
* @param deepDrillingLevel 深层钻探设施等级
* @returns 加成倍数1 + 等级 * 0.2
*/
export const calculateDeepDrillingBonus = (deepDrillingLevel: number): number => {
return 1 + deepDrillingLevel * ORE_CAPACITY_BONUS.DEEP_DRILLING_BONUS_PER_LEVEL
}
/**
* 计算采矿技术的矿脉上限加成
* @param miningTechLevel 采矿技术等级
* @returns 加成倍数1 + 等级 * 0.15
*/
export const calculateMiningTechBonus = (miningTechLevel: number): number => {
return 1 + miningTechLevel * ORE_CAPACITY_BONUS.MINING_TECH_BONUS_PER_LEVEL
}
/**
* 根据星球位置动态计算基础储量上限(不含建筑/科技加成)
* 这样修改配置后,所有星球的上限都会自动更新
*/
export const calculateInitialDeposits = (
position:
| {
galaxy: number
system: number
position: number
}
| undefined
): { metal: number; crystal: number; deuterium: number } => {
const { BASE_DEPOSITS, POSITION_MULTIPLIERS, GALAXY_MULTIPLIER } = ORE_DEPOSIT_CONFIG
// 防御性检查如果position无效返回默认值位置8银河系1
if (!position || typeof position.position !== 'number' || typeof position.galaxy !== 'number') {
console.warn('[OreDeposits] Invalid position, using defaults:', position)
return {
metal: BASE_DEPOSITS.metal,
crystal: BASE_DEPOSITS.crystal,
deuterium: BASE_DEPOSITS.deuterium
}
}
// 位置索引 (0-14)
const posIndex = Math.max(0, Math.min(14, position.position - 1))
// 银河系加成 (银河系1为基础每增加1个银河系增加5%)
const galaxyBonus = 1 + (position.galaxy - 1) * GALAXY_MULTIPLIER
// 计算每种资源的储量上限(不含随机浮动,确保一致性)
const metal = Math.floor(BASE_DEPOSITS.metal * (POSITION_MULTIPLIERS.metal[posIndex] ?? 1) * galaxyBonus)
const crystal = Math.floor(BASE_DEPOSITS.crystal * (POSITION_MULTIPLIERS.crystal[posIndex] ?? 1) * galaxyBonus)
const deuterium = Math.floor(BASE_DEPOSITS.deuterium * (POSITION_MULTIPLIERS.deuterium[posIndex] ?? 1) * galaxyBonus)
return { metal, crystal, deuterium }
}
/**
* 计算带有建筑和科技加成的矿脉储量上限
* @param position 星球位置
* @param deepDrillingLevel 深层钻探设施等级(星球级)
* @param miningTechLevel 采矿技术等级(全局)
* @returns 包含加成的储量上限
*/
export const calculateEnhancedDeposits = (
position: { galaxy: number; system: number; position: number } | undefined,
deepDrillingLevel: number = 0,
miningTechLevel: number = 0
): { metal: number; crystal: number; deuterium: number; bonusMultiplier: number } => {
const baseDeposits = calculateInitialDeposits(position)
// 计算总加成倍数
const deepDrillingBonus = calculateDeepDrillingBonus(deepDrillingLevel)
const miningTechBonus = calculateMiningTechBonus(miningTechLevel)
const totalBonus = deepDrillingBonus * miningTechBonus
return {
metal: Math.floor(baseDeposits.metal * totalBonus),
crystal: Math.floor(baseDeposits.crystal * totalBonus),
deuterium: Math.floor(baseDeposits.deuterium * totalBonus),
bonusMultiplier: totalBonus
}
}
/**
* 根据星球位置生成初始矿脉储量
*/
export const generateOreDeposits = (position: { galaxy: number; system: number; position: number }): OreDeposits => {
const initialDeposits = calculateInitialDeposits(position)
return {
metal: initialDeposits.metal,
crystal: initialDeposits.crystal,
deuterium: initialDeposits.deuterium,
position: { ...position }
}
}
/**
* 计算矿脉储量对产量的效率系数
* 当储量低于衰减阈值时,产量会线性下降
* 但即使耗尽也保留最低产量MIN_PRODUCTION_EFFICIENCY
* @returns MIN_PRODUCTION_EFFICIENCY-1 之间的效率系数
*/
export const calculateDepositEfficiency = (deposits: OreDeposits | undefined, resourceType: 'metal' | 'crystal' | 'deuterium'): number => {
if (!deposits) return 1 // 没有储量数据时返回满效率(向后兼容)
const { DECAY_START_THRESHOLD, MIN_PRODUCTION_EFFICIENCY } = ORE_DEPOSIT_CONFIG
const currentDeposit = deposits[resourceType]
const initialDeposits = calculateInitialDeposits(deposits.position)
const initialDeposit = initialDeposits[resourceType]
// 如果初始储量为0返回最低效率避免除以0
if (initialDeposit <= 0) return MIN_PRODUCTION_EFFICIENCY
// 计算剩余百分比
const remainingPercentage = currentDeposit / initialDeposit
// 如果高于衰减阈值,返回满效率
if (remainingPercentage >= DECAY_START_THRESHOLD) return 1
// 如果已耗尽,返回最低效率(保底产量)
if (currentDeposit <= 0) return MIN_PRODUCTION_EFFICIENCY
// 在衰减阈值以下,线性衰减
// 从 DECAY_START_THRESHOLD 到 0效率从 1 降到 MIN_PRODUCTION_EFFICIENCY
const decayRange = 1 - MIN_PRODUCTION_EFFICIENCY
const decayProgress = remainingPercentage / DECAY_START_THRESHOLD
return MIN_PRODUCTION_EFFICIENCY + decayRange * decayProgress
}
/**
* 消耗矿脉储量
* @param deposits 矿脉储量对象
* @param resourceType 资源类型
* @param amount 要消耗的量
* @returns 实际消耗的量(不会超过剩余储量)
*/
export const consumeDeposit = (deposits: OreDeposits, resourceType: 'metal' | 'crystal' | 'deuterium', amount: number): number => {
const currentDeposit = deposits[resourceType]
const actualConsumption = Math.min(currentDeposit, amount)
deposits[resourceType] = Math.max(0, currentDeposit - actualConsumption)
return actualConsumption
}
/**
* 获取矿脉剩余百分比
*/
export const getDepositPercentage = (deposits: OreDeposits | undefined, resourceType: 'metal' | 'crystal' | 'deuterium'): number => {
if (!deposits) return 100
// 如果没有position信息返回100%(向后兼容旧数据)
if (!deposits.position) return 100
const currentDeposit = deposits[resourceType]
const initialDeposits = calculateInitialDeposits(deposits.position)
const initialDeposit = initialDeposits[resourceType]
if (initialDeposit <= 0) return 0
return (currentDeposit / initialDeposit) * 100
}
/**
* 检查矿脉是否处于警告状态(低于警告阈值)
*/
export const isDepositWarning = (deposits: OreDeposits | undefined, resourceType: 'metal' | 'crystal' | 'deuterium'): boolean => {
if (!deposits) return false
const percentage = getDepositPercentage(deposits, resourceType)
return percentage < ORE_DEPOSIT_CONFIG.WARNING_THRESHOLD * 100 && percentage > 0
}
/**
* 检查矿脉是否已耗尽
*/
export const isDepositDepleted = (deposits: OreDeposits | undefined, resourceType: 'metal' | 'crystal' | 'deuterium'): boolean => {
if (!deposits) return false
return deposits[resourceType] <= 0
}
/**
* 为现有星球迁移/初始化矿脉储量
* 如果星球没有矿脉数据,则生成新的储量
* 如果有矿脉数据但缺少position则补充position信息
*/
export const migrateOreDeposits = (planet: Planet): void => {
// 月球不需要矿脉(没有采矿建筑)
if (planet.isMoon) return
if (!planet.oreDeposits) {
planet.oreDeposits = generateOreDeposits(planet.position)
} else if (!planet.oreDeposits.position) {
// 旧数据迁移补充position信息
planet.oreDeposits.position = { ...planet.position }
}
}
/**
* 计算预计耗尽时间(小时)
* @param deposits 矿脉储量
* @param resourceType 资源类型
* @param productionPerHour 每小时产量
* @returns 预计耗尽时间小时如果产量为0则返回Infinity
*/
export const calculateDepletionTime = (
deposits: OreDeposits | undefined,
resourceType: 'metal' | 'crystal' | 'deuterium',
productionPerHour: number
): number => {
if (!deposits || productionPerHour <= 0) return Infinity
const currentDeposit = deposits[resourceType]
if (currentDeposit <= 0) return 0
return currentDeposit / productionPerHour
}
/**
* 格式化耗尽时间为可读字符串
*/
export const formatDepletionTime = (hours: number): string => {
if (!isFinite(hours) || hours < 0) return '∞'
if (hours === 0) return '0'
const days = Math.floor(hours / 24)
const remainingHours = Math.floor(hours % 24)
if (days > 365) {
const years = Math.floor(days / 365)
return `${years}y+`
}
if (days > 0) {
return `${days}d ${remainingHours}h`
}
if (hours < 1) {
const minutes = Math.floor(hours * 60)
return `${minutes}m`
}
return `${remainingHours}h`
}
/**
* 计算地质研究站带来的恢复速率加成
* @param geoStationLevel 地质研究站等级
* @returns 恢复速率倍数1 + 等级 * 0.1
*/
export const calculateGeoStationBonus = (geoStationLevel: number): number => {
// 每级地质研究站增加50%恢复速度
// 0级 = 1倍, 1级 = 1.5倍, 2级 = 2倍, ..., 10级 = 6倍
return 1 + geoStationLevel * 0.1
}
/**
* 恢复矿脉储量
* 矿脉会随时间缓慢恢复,模拟地质活动
* @param deposits 矿脉储量对象
* @param hoursElapsed 经过的小时数
* @param geoStationLevel 地质研究站等级(可选,影响恢复速度)
* @param deepDrillingLevel 深层钻探设施等级(可选,影响恢复上限)
* @param miningTechLevel 采矿技术等级(可选,影响恢复上限)
*/
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
// 计算地质研究站加成
const geoBonus = calculateGeoStationBonus(geoStationLevel)
// 计算带有建筑和科技加成的储量上限
const enhancedDeposits = calculateEnhancedDeposits(deposits.position, deepDrillingLevel, miningTechLevel)
// 计算恢复量(基于增强后储量的百分比,乘以地质研究站加成)
const regenRate = REGENERATION.RATE_PER_HOUR * hoursElapsed * geoBonus
const maxPercentage = REGENERATION.MAX_PERCENTAGE
// 恢复每种资源
const metalRegen = enhancedDeposits.metal * regenRate
const crystalRegen = enhancedDeposits.crystal * regenRate
const deuteriumRegen = enhancedDeposits.deuterium * regenRate
// 添加恢复量,但不超过增强后储量的最大百分比
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,
deepDrillingLevel: number = 0,
miningTechLevel: number = 0
): {
metalRecovering: boolean
crystalRecovering: boolean
deuteriumRecovering: boolean
hoursToFullMetal: number
hoursToFullCrystal: number
hoursToFullDeuterium: number
geoStationBonus: number // 地质研究站加成倍数
} => {
const geoBonus = calculateGeoStationBonus(geoStationLevel)
if (!deposits) {
return {
metalRecovering: false,
crystalRecovering: false,
deuteriumRecovering: false,
hoursToFullMetal: 0,
hoursToFullCrystal: 0,
hoursToFullDeuterium: 0,
geoStationBonus: geoBonus
}
}
// 计算带有建筑和科技加成的储量上限
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 = 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) / (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,
crystalRecovering,
deuteriumRecovering,
hoursToFullMetal,
hoursToFullCrystal,
hoursToFullDeuterium,
geoStationBonus: geoBonus
}
}