mirror of
https://github.com/setube/ogame-vue-ts.git
synced 2026-05-12 07:55:11 +08:00
feat: 新增多语言README并优化文档结构
新增德语、俄语、韩语、繁体中文多语言README,英文与简体中文README同步优化,统一下载链接与徽章样式,完善多语言入口。提升国际化支持与文档可读性。
This commit is contained in:
603
src/logic/campaignLogic.ts
Normal file
603
src/logic/campaignLogic.ts
Normal file
@@ -0,0 +1,603 @@
|
||||
/**
|
||||
* 战役系统逻辑
|
||||
* 处理任务进度、解锁、完成等核心逻辑
|
||||
*/
|
||||
|
||||
import {
|
||||
QuestStatus,
|
||||
ObjectiveType,
|
||||
type Player,
|
||||
type PlayerCampaignProgress,
|
||||
type QuestObjective,
|
||||
type QuestReward,
|
||||
type QuestNotification,
|
||||
type CampaignQuestConfig,
|
||||
type NPC,
|
||||
type Resources,
|
||||
RelationStatus,
|
||||
type BuildingType,
|
||||
type TechnologyType,
|
||||
type ShipType
|
||||
} from '@/types/game'
|
||||
import { MAIN_CAMPAIGN, getAllQuests, getQuestById, getQuestsByChapter } from '@/config/campaignConfig'
|
||||
import * as resourceLogic from './resourceLogic'
|
||||
|
||||
/**
|
||||
* 初始化玩家战役进度
|
||||
*/
|
||||
export const initializeCampaignProgress = (player: Player): PlayerCampaignProgress => {
|
||||
// 如果已有进度,返回现有进度
|
||||
if (player.campaignProgress) {
|
||||
return player.campaignProgress
|
||||
}
|
||||
|
||||
// 创建初始进度,第一个任务默认解锁
|
||||
const firstQuest = getQuestsByChapter(1)[0]
|
||||
const progress: PlayerCampaignProgress = {
|
||||
campaignId: MAIN_CAMPAIGN.id,
|
||||
currentChapter: 1,
|
||||
currentQuestId: firstQuest?.id,
|
||||
questProgress: {},
|
||||
completedQuests: [],
|
||||
unlockedQuests: firstQuest ? [firstQuest.id] : [],
|
||||
branchChoices: {}
|
||||
}
|
||||
|
||||
// 初始化第一个任务为可接取状态
|
||||
if (firstQuest) {
|
||||
progress.questProgress[firstQuest.id] = {
|
||||
questId: firstQuest.id,
|
||||
status: QuestStatus.Available,
|
||||
objectives: {}
|
||||
}
|
||||
// 初始化目标进度
|
||||
const questProgress = progress.questProgress[firstQuest.id]
|
||||
if (questProgress) {
|
||||
firstQuest.objectives.forEach(obj => {
|
||||
questProgress.objectives[obj.id] = {
|
||||
current: 0,
|
||||
completed: false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return progress
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务状态
|
||||
*/
|
||||
export const getQuestStatus = (progress: PlayerCampaignProgress, questId: string): QuestStatus => {
|
||||
const questProgress = progress.questProgress[questId]
|
||||
if (questProgress) {
|
||||
return questProgress.status
|
||||
}
|
||||
|
||||
// 检查是否已解锁
|
||||
if (progress.unlockedQuests.includes(questId)) {
|
||||
return QuestStatus.Available
|
||||
}
|
||||
|
||||
return QuestStatus.Locked
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始任务
|
||||
*/
|
||||
export const startQuest = (player: Player, questId: string): { success: boolean; error?: string } => {
|
||||
const progress = player.campaignProgress
|
||||
if (!progress) {
|
||||
return { success: false, error: 'campaign.errors.notInitialized' }
|
||||
}
|
||||
|
||||
const quest = getQuestById(questId)
|
||||
if (!quest) {
|
||||
return { success: false, error: 'campaign.errors.questNotFound' }
|
||||
}
|
||||
|
||||
// 检查是否已解锁
|
||||
if (!progress.unlockedQuests.includes(questId)) {
|
||||
return { success: false, error: 'campaign.errors.questLocked' }
|
||||
}
|
||||
|
||||
// 检查是否已完成
|
||||
if (progress.completedQuests.includes(questId)) {
|
||||
return { success: false, error: 'campaign.errors.questAlreadyCompleted' }
|
||||
}
|
||||
|
||||
// 初始化或更新任务进度
|
||||
if (!progress.questProgress[questId]) {
|
||||
progress.questProgress[questId] = {
|
||||
questId,
|
||||
status: QuestStatus.Active,
|
||||
objectives: {},
|
||||
startedAt: Date.now()
|
||||
}
|
||||
}
|
||||
const questProgress = progress.questProgress[questId]
|
||||
if (questProgress) {
|
||||
questProgress.status = QuestStatus.Active
|
||||
questProgress.startedAt = Date.now()
|
||||
// 初始化目标进度
|
||||
quest.objectives.forEach(obj => {
|
||||
if (!questProgress.objectives[obj.id]) {
|
||||
questProgress.objectives[obj.id] = {
|
||||
current: 0,
|
||||
completed: false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
progress.currentQuestId = questId
|
||||
|
||||
return { success: true }
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查单个目标的进度
|
||||
*/
|
||||
export const checkObjectiveProgress = (player: Player, objective: QuestObjective, npcs: NPC[]): number => {
|
||||
switch (objective.type) {
|
||||
case ObjectiveType.BuildBuilding: {
|
||||
// 检查玩家所有星球上该建筑的最高等级
|
||||
const targetLevel = objective.targetSecondary as number
|
||||
const buildingType = objective.target as BuildingType
|
||||
const hasBuilding = player.planets.some(planet => {
|
||||
const level = planet.buildings[buildingType] || 0
|
||||
return level >= targetLevel
|
||||
})
|
||||
return hasBuilding ? 1 : 0
|
||||
}
|
||||
|
||||
case ObjectiveType.ResearchTech: {
|
||||
const targetLevel = objective.targetSecondary as number
|
||||
const techType = objective.target as TechnologyType
|
||||
const currentLevel = player.technologies[techType] || 0
|
||||
return currentLevel >= targetLevel ? 1 : 0
|
||||
}
|
||||
|
||||
case ObjectiveType.ProduceShips: {
|
||||
// 统计所有星球上该类型舰船的总数
|
||||
const shipType = objective.target as ShipType
|
||||
let totalShips = 0
|
||||
player.planets.forEach(planet => {
|
||||
totalShips += planet.fleet[shipType] || 0
|
||||
})
|
||||
return Math.min(totalShips, objective.required)
|
||||
}
|
||||
|
||||
case ObjectiveType.AccumulateResources: {
|
||||
// 统计所有星球的资源总量
|
||||
let totalResources = 0
|
||||
player.planets.forEach(planet => {
|
||||
totalResources += planet.resources.metal + planet.resources.crystal + planet.resources.deuterium
|
||||
})
|
||||
return Math.min(totalResources, objective.required)
|
||||
}
|
||||
|
||||
case ObjectiveType.Colonize: {
|
||||
// 统计殖民地数量(不包括母星)
|
||||
const colonyCount = player.planets.length - 1
|
||||
return Math.min(colonyCount, objective.required)
|
||||
}
|
||||
|
||||
case ObjectiveType.SpyTarget: {
|
||||
// 统计侦查报告数量
|
||||
const target = objective.target
|
||||
if (target === 'any') {
|
||||
return Math.min(player.spyReports.length, objective.required)
|
||||
} else if (target === 'hostile') {
|
||||
// 统计敌对NPC的侦查报告
|
||||
const hostileNpcIds = npcs
|
||||
.filter(npc => {
|
||||
const relation = npc.relations?.[player.id]
|
||||
return relation?.status === RelationStatus.Hostile
|
||||
})
|
||||
.map(npc => npc.id)
|
||||
const hostileReports = player.spyReports.filter(report => hostileNpcIds.includes(report.targetPlayerId || ''))
|
||||
return Math.min(hostileReports.length, objective.required)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
case ObjectiveType.SendGift: {
|
||||
// 从成就统计中获取送礼次数
|
||||
return Math.min(player.achievementStats?.giftsSent || 0, objective.required)
|
||||
}
|
||||
|
||||
case ObjectiveType.Expedition: {
|
||||
// 从成就统计中获取探险次数(使用 expeditionsTotal)
|
||||
return Math.min(player.achievementStats?.expeditionsTotal || 0, objective.required)
|
||||
}
|
||||
|
||||
case ObjectiveType.WinBattles: {
|
||||
const target = objective.target
|
||||
if (target === 'attack') {
|
||||
return Math.min(player.achievementStats?.attacksWon || 0, objective.required)
|
||||
} else if (target === 'defense') {
|
||||
// 使用 defensesSuccessful 代替 defensesWon
|
||||
return Math.min(player.achievementStats?.defensesSuccessful || 0, objective.required)
|
||||
}
|
||||
const totalWins = (player.achievementStats?.attacksWon || 0) + (player.achievementStats?.defensesSuccessful || 0)
|
||||
return Math.min(totalWins, objective.required)
|
||||
}
|
||||
|
||||
case ObjectiveType.RecycleDebris: {
|
||||
return Math.min(player.achievementStats?.recyclingMissions || 0, objective.required)
|
||||
}
|
||||
|
||||
case ObjectiveType.ReachRelation: {
|
||||
// 检查是否有任何NPC达到指定关系等级
|
||||
const targetStatus = objective.target as string
|
||||
const hasRelation = npcs.some(npc => {
|
||||
const relation = npc.relations?.[player.id]
|
||||
return relation?.status === targetStatus
|
||||
})
|
||||
return hasRelation ? 1 : 0
|
||||
}
|
||||
|
||||
case ObjectiveType.FormAlliance: {
|
||||
// 检查是否有盟友(使用 Friendly 作为最高关系等级)
|
||||
const hasAlliance = npcs.some(npc => {
|
||||
const relation = npc.relations?.[player.id]
|
||||
return relation?.status === RelationStatus.Friendly && (relation.reputation || 0) >= 80
|
||||
})
|
||||
return hasAlliance ? 1 : 0
|
||||
}
|
||||
|
||||
case ObjectiveType.DefeatNPC: {
|
||||
// 检查攻击NPC获胜次数
|
||||
return Math.min(player.achievementStats?.attacksWon || 0, objective.required)
|
||||
}
|
||||
|
||||
case ObjectiveType.DestroyPlanet: {
|
||||
return Math.min(player.achievementStats?.planetDestructions || 0, objective.required)
|
||||
}
|
||||
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新任务进度
|
||||
*/
|
||||
export const updateQuestProgress = (
|
||||
player: Player,
|
||||
questId: string,
|
||||
npcs: NPC[]
|
||||
): {
|
||||
updated: boolean
|
||||
completedObjectives: string[]
|
||||
questCompleted: boolean
|
||||
} => {
|
||||
const result = {
|
||||
updated: false,
|
||||
completedObjectives: [] as string[],
|
||||
questCompleted: false
|
||||
}
|
||||
|
||||
const progress = player.campaignProgress
|
||||
if (!progress) return result
|
||||
|
||||
const questProgress = progress.questProgress[questId]
|
||||
if (!questProgress || questProgress.status !== QuestStatus.Active) return result
|
||||
|
||||
const quest = getQuestById(questId)
|
||||
if (!quest) return result
|
||||
|
||||
// 检查每个目标的进度
|
||||
quest.objectives.forEach(objective => {
|
||||
const objProgress = questProgress.objectives[objective.id]
|
||||
if (!objProgress || objProgress.completed) return
|
||||
|
||||
const newProgress = checkObjectiveProgress(player, objective, npcs)
|
||||
if (newProgress !== objProgress.current) {
|
||||
objProgress.current = newProgress
|
||||
result.updated = true
|
||||
|
||||
// 检查目标是否完成
|
||||
if (newProgress >= objective.required && !objProgress.completed) {
|
||||
objProgress.completed = true
|
||||
result.completedObjectives.push(objective.id)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 检查任务是否全部完成
|
||||
const allCompleted = quest.objectives.every(obj => questProgress.objectives[obj.id]?.completed)
|
||||
|
||||
if (allCompleted && questProgress.status === QuestStatus.Active) {
|
||||
questProgress.status = QuestStatus.Completed
|
||||
questProgress.completedAt = Date.now()
|
||||
result.questCompleted = true
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 领取任务奖励
|
||||
*/
|
||||
export const claimQuestRewards = (
|
||||
player: Player,
|
||||
questId: string
|
||||
): {
|
||||
success: boolean
|
||||
rewards?: QuestReward
|
||||
error?: string
|
||||
} => {
|
||||
const progress = player.campaignProgress
|
||||
if (!progress) {
|
||||
return { success: false, error: 'campaign.errors.notInitialized' }
|
||||
}
|
||||
|
||||
const questProgress = progress.questProgress[questId]
|
||||
if (!questProgress) {
|
||||
return { success: false, error: 'campaign.errors.questNotFound' }
|
||||
}
|
||||
|
||||
if (questProgress.status !== QuestStatus.Completed) {
|
||||
return { success: false, error: 'campaign.errors.questNotCompleted' }
|
||||
}
|
||||
|
||||
if (questProgress.rewardsClaimed) {
|
||||
return { success: false, error: 'campaign.errors.rewardsAlreadyClaimed' }
|
||||
}
|
||||
|
||||
const quest = getQuestById(questId)
|
||||
if (!quest) {
|
||||
return { success: false, error: 'campaign.errors.questNotFound' }
|
||||
}
|
||||
|
||||
// 发放奖励
|
||||
const rewards = quest.rewards
|
||||
const currentPlanet = player.planets[0] // 默认发放到第一个星球
|
||||
|
||||
if (rewards.resources && currentPlanet) {
|
||||
resourceLogic.addResources(currentPlanet.resources, rewards.resources as Resources)
|
||||
}
|
||||
|
||||
if (rewards.darkMatter && currentPlanet) {
|
||||
currentPlanet.resources.darkMatter += rewards.darkMatter
|
||||
}
|
||||
|
||||
if (rewards.points) {
|
||||
player.points += rewards.points
|
||||
}
|
||||
|
||||
if (rewards.ships && currentPlanet) {
|
||||
Object.entries(rewards.ships).forEach(([shipType, count]) => {
|
||||
const ship = shipType as ShipType
|
||||
currentPlanet.fleet[ship] = (currentPlanet.fleet[ship] || 0) + count
|
||||
})
|
||||
}
|
||||
|
||||
// 标记奖励已领取
|
||||
questProgress.rewardsClaimed = true
|
||||
|
||||
// 将任务添加到已完成列表
|
||||
if (!progress.completedQuests.includes(questId)) {
|
||||
progress.completedQuests.push(questId)
|
||||
}
|
||||
|
||||
// 解锁后续任务
|
||||
unlockNextQuests(player, questId)
|
||||
|
||||
return { success: true, rewards }
|
||||
}
|
||||
|
||||
/**
|
||||
* 解锁后续任务
|
||||
*/
|
||||
export const unlockNextQuests = (player: Player, _completedQuestId: string): string[] => {
|
||||
const progress = player.campaignProgress
|
||||
if (!progress) return []
|
||||
|
||||
const unlockedQuests: string[] = []
|
||||
const allQuests = getAllQuests()
|
||||
|
||||
allQuests.forEach(quest => {
|
||||
// 跳过已解锁的任务
|
||||
if (progress.unlockedQuests.includes(quest.id)) return
|
||||
|
||||
// 检查前置任务是否完成
|
||||
if (quest.requiredQuestIds && quest.requiredQuestIds.length > 0) {
|
||||
const allRequiredCompleted = quest.requiredQuestIds.every(reqId => progress.completedQuests.includes(reqId))
|
||||
|
||||
if (allRequiredCompleted) {
|
||||
progress.unlockedQuests.push(quest.id)
|
||||
unlockedQuests.push(quest.id)
|
||||
|
||||
// 初始化任务进度
|
||||
progress.questProgress[quest.id] = {
|
||||
questId: quest.id,
|
||||
status: QuestStatus.Available,
|
||||
objectives: {}
|
||||
}
|
||||
const questProgress = progress.questProgress[quest.id]
|
||||
if (questProgress) {
|
||||
quest.objectives.forEach(obj => {
|
||||
questProgress.objectives[obj.id] = {
|
||||
current: 0,
|
||||
completed: false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 更新当前章节
|
||||
if (quest.chapter > progress.currentChapter) {
|
||||
progress.currentChapter = quest.chapter
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return unlockedQuests
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算战役总进度百分比
|
||||
*/
|
||||
export const calculateCampaignProgress = (progress: PlayerCampaignProgress): number => {
|
||||
const totalQuests = getAllQuests().length
|
||||
const completedCount = progress.completedQuests.length
|
||||
return Math.round((completedCount / totalQuests) * 100)
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算章节进度百分比
|
||||
*/
|
||||
export const calculateChapterProgress = (progress: PlayerCampaignProgress, chapterNumber: number): number => {
|
||||
const chapterQuests = getQuestsByChapter(chapterNumber)
|
||||
const completedCount = chapterQuests.filter(quest => progress.completedQuests.includes(quest.id)).length
|
||||
return Math.round((completedCount / chapterQuests.length) * 100)
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算单个任务的进度百分比
|
||||
*/
|
||||
export const calculateQuestProgress = (progress: PlayerCampaignProgress, questId: string): number => {
|
||||
const questProgress = progress.questProgress[questId]
|
||||
if (!questProgress) return 0
|
||||
|
||||
const quest = getQuestById(questId)
|
||||
if (!quest) return 0
|
||||
|
||||
// 计算所有目标的平均进度
|
||||
const objectives = quest.objectives
|
||||
if (objectives.length === 0) return 0
|
||||
|
||||
let totalProgress = 0
|
||||
objectives.forEach(obj => {
|
||||
const objProgress = questProgress.objectives[obj.id]
|
||||
if (objProgress) {
|
||||
if (objProgress.completed) {
|
||||
totalProgress += 100
|
||||
} else {
|
||||
totalProgress += Math.min((objProgress.current / obj.required) * 100, 100)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return Math.round(totalProgress / objectives.length)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前可进行的任务列表
|
||||
*/
|
||||
export const getAvailableQuests = (progress: PlayerCampaignProgress): CampaignQuestConfig[] => {
|
||||
return getAllQuests().filter(quest => {
|
||||
const status = getQuestStatus(progress, quest.id)
|
||||
return status === QuestStatus.Available || status === QuestStatus.Active
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前激活的任务
|
||||
*/
|
||||
export const getActiveQuest = (progress: PlayerCampaignProgress): CampaignQuestConfig | undefined => {
|
||||
if (!progress.currentQuestId) return undefined
|
||||
return getQuestById(progress.currentQuestId)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建任务通知
|
||||
*/
|
||||
export const createQuestNotification = (
|
||||
questId: string,
|
||||
eventType: QuestNotification['eventType'],
|
||||
messageKey: string,
|
||||
messageParams?: Record<string, string | number>,
|
||||
rewards?: QuestReward
|
||||
): QuestNotification => {
|
||||
const quest = getQuestById(questId)
|
||||
return {
|
||||
id: `quest_notification_${Date.now()}`,
|
||||
timestamp: Date.now(),
|
||||
questId,
|
||||
questTitleKey: quest?.titleKey || '',
|
||||
eventType,
|
||||
messageKey,
|
||||
messageParams,
|
||||
rewards,
|
||||
read: false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加任务通知到玩家
|
||||
*/
|
||||
export const addQuestNotification = (player: Player, notification: QuestNotification): void => {
|
||||
if (!player.questNotifications) {
|
||||
player.questNotifications = []
|
||||
}
|
||||
player.questNotifications.unshift(notification)
|
||||
|
||||
// 限制通知数量
|
||||
if (player.questNotifications.length > 50) {
|
||||
player.questNotifications = player.questNotifications.slice(0, 50)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记通知为已读
|
||||
*/
|
||||
export const markQuestNotificationRead = (player: Player, notificationId: string): void => {
|
||||
const notification = player.questNotifications?.find(n => n.id === notificationId)
|
||||
if (notification) {
|
||||
notification.read = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取未读通知数量
|
||||
*/
|
||||
export const getUnreadQuestNotificationCount = (player: Player): number => {
|
||||
return player.questNotifications?.filter(n => !n.read).length || 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查并更新所有激活任务的进度
|
||||
*/
|
||||
export const checkAllActiveQuestsProgress = (player: Player, npcs: NPC[]): QuestNotification[] => {
|
||||
const notifications: QuestNotification[] = []
|
||||
const progress = player.campaignProgress
|
||||
|
||||
if (!progress) return notifications
|
||||
|
||||
// 遍历所有激活的任务
|
||||
Object.entries(progress.questProgress).forEach(([questId, questProgress]) => {
|
||||
if (questProgress.status !== QuestStatus.Active) return
|
||||
|
||||
const result = updateQuestProgress(player, questId, npcs)
|
||||
|
||||
// 为完成的目标创建通知
|
||||
result.completedObjectives.forEach(objId => {
|
||||
const quest = getQuestById(questId)
|
||||
const objective = quest?.objectives.find(o => o.id === objId)
|
||||
if (objective) {
|
||||
notifications.push(
|
||||
createQuestNotification(questId, 'objective_completed', 'campaign.notifications.objectiveCompleted', {
|
||||
objective: objective.descriptionKey
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
// 任务完成通知
|
||||
if (result.questCompleted) {
|
||||
const quest = getQuestById(questId)
|
||||
notifications.push(createQuestNotification(questId, 'quest_completed', 'campaign.notifications.questCompleted', {}, quest?.rewards))
|
||||
}
|
||||
})
|
||||
|
||||
// 添加通知到玩家
|
||||
notifications.forEach(notification => {
|
||||
addQuestNotification(player, notification)
|
||||
})
|
||||
|
||||
return notifications
|
||||
}
|
||||
Reference in New Issue
Block a user