Files
ogame-vue-ts/src/logic/buildingLogic.ts
谦君 1fc807915f 1.6.5
2026-01-23 01:28:57 +08:00

291 lines
10 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, BuildQueueItem } from '@/types/game'
import { BuildingType, TechnologyType, ShipType, DefenseType } from '@/types/game'
import { BUILDINGS } from '@/config/gameConfig'
import * as pointsLogic from './pointsLogic'
// 用于生成唯一ID的计数器
let queueIdCounter = 0
/**
* 计算建筑升级成本
*/
export const calculateBuildingCost = (buildingType: BuildingType, targetLevel: number): Resources => {
const config = BUILDINGS[buildingType]
const multiplier = Math.pow(config.costMultiplier, targetLevel - 1)
return {
metal: Math.floor(config.baseCost.metal * multiplier),
crystal: Math.floor(config.baseCost.crystal * multiplier),
deuterium: Math.floor(config.baseCost.deuterium * multiplier),
darkMatter: Math.floor(config.baseCost.darkMatter * multiplier),
energy: 0
}
}
/**
* 计算建筑升级时间
* @param buildingType 建筑类型
* @param targetLevel 目标等级
* @param buildingSpeedBonus 指挥官等提供的速度加成百分比
* @param roboticsFactoryLevel 机器人工厂等级
* @param naniteFactoryLevel 纳米工厂等级
*/
export const calculateBuildingTime = (
buildingType: BuildingType,
targetLevel: number,
buildingSpeedBonus: number = 0,
roboticsFactoryLevel: number = 0,
naniteFactoryLevel: number = 0
): number => {
const config = BUILDINGS[buildingType]
const multiplier = Math.pow(config.costMultiplier, targetLevel - 1)
const baseTime = config.baseTime * multiplier
// 机器人工厂和纳米工厂的加速:建造时间 / (1 + 机器人工厂等级 + 纳米工厂等级 × 2)
const factorySpeedDivisor = 1 + roboticsFactoryLevel + naniteFactoryLevel * 2
// 指挥官等的百分比加成
const speedMultiplier = 1 - buildingSpeedBonus / 100
return Math.floor((baseTime / factorySpeedDivisor) * speedMultiplier)
}
/**
* 计算已用空间
*/
export const calculateUsedSpace = (planet: Planet): number => {
let usedSpace = 0
Object.entries(planet.buildings).forEach(([buildingType, level]) => {
if (level > 0) {
const config = BUILDINGS[buildingType as BuildingType]
usedSpace += config.spaceUsage * level
}
})
return usedSpace
}
/**
* 检查建筑升级条件(包括基础要求和等级门槛要求)
*/
export const checkBuildingRequirements = (
buildingType: BuildingType,
planet: Planet,
technologies: Partial<Record<TechnologyType, number>>,
targetLevel?: number
): boolean => {
const config = BUILDINGS[buildingType]
const currentLevel = planet.buildings[buildingType] || 0
const level = targetLevel ?? currentLevel + 1
// 检查基础 requirements
const requirements = (config as any).requirements
if (requirements) {
for (const [key, reqLevel] of Object.entries(requirements)) {
const requiredLevel = reqLevel as number
if (Object.values(BuildingType).includes(key as BuildingType)) {
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)) {
if ((technologies[key as TechnologyType] || 0) < requiredLevel) {
return false
}
}
}
}
// 检查等级门槛 levelRequirements
const levelRequirements = (config as any).levelRequirements
if (levelRequirements) {
// 找出所有小于等于目标等级的门槛
const applicableLevels = Object.keys(levelRequirements)
.map(Number)
.filter(l => l <= level)
.sort((a, b) => a - b)
for (const threshold of applicableLevels) {
const reqs = levelRequirements[threshold]
if (!reqs) continue
for (const [key, reqLevel] of Object.entries(reqs)) {
const requiredLevel = reqLevel as number
if (Object.values(BuildingType).includes(key as BuildingType)) {
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)) {
if ((technologies[key as TechnologyType] || 0) < requiredLevel) {
return false
}
}
}
}
}
return true
}
/**
* 检查是否有足够空间建造
*/
export const checkSpaceAvailable = (planet: Planet, buildingType: BuildingType): boolean => {
const usedSpace = calculateUsedSpace(planet)
const buildingConfig = BUILDINGS[buildingType]
const requiredSpace = buildingConfig.spaceUsage
return usedSpace + requiredSpace <= planet.maxSpace
}
/**
* 创建建造队列项
*/
export const createBuildQueueItem = (buildingType: BuildingType, targetLevel: number, buildTime: number): BuildQueueItem => {
const now = Date.now()
queueIdCounter++
return {
id: `build_${now}_${queueIdCounter}`,
type: 'building',
itemType: buildingType,
targetLevel,
startTime: now,
endTime: now + buildTime * 1000
}
}
/**
* 处理建造完成
*/
export const completeBuildQueue = (
planet: Planet,
now: number,
onPointsEarned?: (points: number, type: 'building' | 'ship' | 'defense', itemType: string, level?: number, quantity?: number) => void,
onCompleted?: (type: 'building' | 'ship' | 'defense' | 'demolish', itemType: string, level?: number, quantity?: number) => void
): void => {
planet.buildQueue = planet.buildQueue.filter(item => {
if (now >= item.endTime) {
// 建造完成
if (item.type === 'building') {
const oldLevel = planet.buildings[item.itemType as BuildingType] || 0
// 升级完成时,等级+1而不是直接使用targetLevel避免在升级过程中被拆除后跳级
const newLevel = oldLevel + 1
planet.buildings[item.itemType as BuildingType] = newLevel
// 计算并累积积分
if (onPointsEarned && newLevel > oldLevel) {
const points = pointsLogic.calculateBuildingPoints(item.itemType as BuildingType, oldLevel, newLevel)
onPointsEarned(points, 'building', item.itemType, newLevel)
}
if (onCompleted) {
onCompleted('building', item.itemType, newLevel)
}
} else if (item.type === 'ship') {
const shipType = item.itemType as ShipType
const quantity = item.quantity || 0
planet.fleet[shipType] = (planet.fleet[shipType] || 0) + quantity
// 计算并累积积分
if (onPointsEarned && quantity > 0) {
const points = pointsLogic.calculateShipPoints(shipType, quantity)
onPointsEarned(points, 'ship', item.itemType, undefined, quantity)
}
} else if (item.type === 'defense') {
const defenseType = item.itemType as DefenseType
const quantity = item.quantity || 0
planet.defense[defenseType] = (planet.defense[defenseType] || 0) + quantity
// 计算并累积积分
if (onPointsEarned && quantity > 0) {
const points = pointsLogic.calculateDefensePoints(defenseType, quantity)
onPointsEarned(points, 'defense', item.itemType, undefined, quantity)
}
} else if (item.type === 'demolish') {
// 拆除完成,降低建筑等级
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
}
return true
})
}
/**
* 计算拆除返还资源
* @param buildingType 建筑类型
* @param currentLevel 当前等级
* @returns 返还50%的当前等级建造成本
*/
export const calculateDemolishRefund = (buildingType: BuildingType, currentLevel: number): Resources => {
const cost = calculateBuildingCost(buildingType, currentLevel)
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
}
}
/**
* 计算拆除时间
* @param buildingType 建筑类型
* @param currentLevel 当前等级
* @param buildingSpeedBonus 建筑速度加成
* @param roboticsFactoryLevel 机器人工厂等级
* @param naniteFactoryLevel 纳米工厂等级
* @returns 拆除时间建造时间的50%
*/
export const calculateDemolishTime = (
buildingType: BuildingType,
currentLevel: number,
buildingSpeedBonus: number = 0,
roboticsFactoryLevel: number = 0,
naniteFactoryLevel: number = 0
): number => {
const buildTime = calculateBuildingTime(buildingType, currentLevel, buildingSpeedBonus, roboticsFactoryLevel, naniteFactoryLevel)
return Math.floor(buildTime * 0.5)
}
/**
* 创建拆除队列项
* @param buildingType 建筑类型
* @param currentLevel 当前等级
* @param demolishTime 拆除时间
* @returns 拆除队列项
*/
export const createDemolishQueueItem = (buildingType: BuildingType, currentLevel: number, demolishTime: number): BuildQueueItem => {
const now = Date.now()
queueIdCounter++
return {
id: `demolish_${now}_${queueIdCounter}`,
type: 'demolish',
itemType: buildingType,
targetLevel: currentLevel - 1, // 目标等级为当前等级-1
startTime: now,
endTime: now + demolishTime * 1000
}
}