601 lines
16 KiB
JavaScript
601 lines
16 KiB
JavaScript
|
|
/**
|
|||
|
|
* 任务系统 - 挂机任务管理、互斥检测
|
|||
|
|
* Phase 6 核心系统实现
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
import { SKILL_CONFIG } from '@/config/skills.js'
|
|||
|
|
import { ITEM_CONFIG } from '@/config/items.js'
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 任务类型枚举
|
|||
|
|
*/
|
|||
|
|
export const TASK_TYPES = {
|
|||
|
|
READING: 'reading', // 阅读
|
|||
|
|
RESTING: 'resting', // 休息
|
|||
|
|
TRAINING: 'training', // 训练
|
|||
|
|
WORKING: 'working', // 工作
|
|||
|
|
COMBAT: 'combat', // 战斗
|
|||
|
|
EXPLORE: 'explore', // 探索
|
|||
|
|
PRAYING: 'praying' // 祈祷
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 任务互斥规则
|
|||
|
|
*/
|
|||
|
|
const MUTEX_RULES = {
|
|||
|
|
// 完全互斥(不能同时进行)
|
|||
|
|
full: [
|
|||
|
|
[TASK_TYPES.COMBAT, TASK_TYPES.TRAINING], // 战斗 vs 训练
|
|||
|
|
[TASK_TYPES.COMBAT, TASK_TYPES.WORKING], // 战斗 vs 工作
|
|||
|
|
[TASK_TYPES.TRAINING, TASK_TYPES.WORKING], // 训练 vs 工作
|
|||
|
|
[TASK_TYPES.EXPLORE, TASK_TYPES.RESTING] // 探索 vs 休息
|
|||
|
|
],
|
|||
|
|
|
|||
|
|
// 部分互斥(需要一心多用技能)
|
|||
|
|
partial: [
|
|||
|
|
[TASK_TYPES.READING, TASK_TYPES.COMBAT], // 阅读 vs 战斗
|
|||
|
|
[TASK_TYPES.READING, TASK_TYPES.TRAINING], // 阅读 vs 训练
|
|||
|
|
[TASK_TYPES.READING, TASK_TYPES.WORKING] // 阅读 vs 工作
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 开始任务
|
|||
|
|
* @param {Object} gameStore - 游戏Store
|
|||
|
|
* @param {Object} playerStore - 玩家Store
|
|||
|
|
* @param {String} taskType - 任务类型
|
|||
|
|
* @param {Object} taskData - 任务数据
|
|||
|
|
* @returns {Object} { success: boolean, message: string, taskId: string|null }
|
|||
|
|
*/
|
|||
|
|
export function startTask(gameStore, playerStore, taskType, taskData = {}) {
|
|||
|
|
// 检查是否可以开始任务
|
|||
|
|
const canStart = canStartTask(gameStore, playerStore, taskType)
|
|||
|
|
if (!canStart.canStart) {
|
|||
|
|
return { success: false, message: canStart.reason }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查任务特定条件
|
|||
|
|
const taskCheck = checkTaskConditions(playerStore, taskType, taskData)
|
|||
|
|
if (!taskCheck.canStart) {
|
|||
|
|
return { success: false, message: taskCheck.reason }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 创建任务
|
|||
|
|
const task = {
|
|||
|
|
id: Date.now(),
|
|||
|
|
type: taskType,
|
|||
|
|
data: taskData,
|
|||
|
|
startTime: Date.now(),
|
|||
|
|
progress: 0,
|
|||
|
|
totalDuration: taskData.duration || 0,
|
|||
|
|
lastTickTime: Date.now()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
gameStore.activeTasks.push(task)
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
success: true,
|
|||
|
|
message: '任务已开始',
|
|||
|
|
taskId: task.id
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 检查是否可以开始任务
|
|||
|
|
* @param {Object} gameStore - 游戏Store
|
|||
|
|
* @param {Object} playerStore - 玩家Store
|
|||
|
|
* @param {String} taskType - 任务类型
|
|||
|
|
* @returns {Object} { canStart: boolean, reason: string }
|
|||
|
|
*/
|
|||
|
|
export function canStartTask(gameStore, playerStore, taskType) {
|
|||
|
|
// 检查是否已有相同类型的任务
|
|||
|
|
const existingTask = gameStore.activeTasks.find(t => t.type === taskType)
|
|||
|
|
if (existingTask) {
|
|||
|
|
return { canStart: false, reason: '已有相同类型的任务正在进行' }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查互斥规则
|
|||
|
|
for (const [type1, type2] of MUTEX_RULES.full) {
|
|||
|
|
if (taskType === type1) {
|
|||
|
|
const conflictTask = gameStore.activeTasks.find(t => t.type === type2)
|
|||
|
|
if (conflictTask) {
|
|||
|
|
return { canStart: false, reason: `与${getTaskTypeName(type2)}任务冲突` }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (taskType === type2) {
|
|||
|
|
const conflictTask = gameStore.activeTasks.find(t => t.type === type1)
|
|||
|
|
if (conflictTask) {
|
|||
|
|
return { canStart: false, reason: `与${getTaskTypeName(type1)}任务冲突` }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查部分互斥(需要一心多用技能)
|
|||
|
|
const multitaskingLevel = playerStore.skills.multitasking?.level || 0
|
|||
|
|
const maxConcurrentTasks = 1 + Math.floor(multitaskingLevel / 5) // 每5级一心多用可多1个任务
|
|||
|
|
|
|||
|
|
const activePartialTasks = gameStore.activeTasks.filter(t =>
|
|||
|
|
MUTEX_RULES.partial.some(pair => pair.includes(t.type))
|
|||
|
|
).length
|
|||
|
|
|
|||
|
|
const isPartialConflict = MUTEX_RULES.partial.some(pair =>
|
|||
|
|
pair.includes(taskType) && pair.some(type =>
|
|||
|
|
gameStore.activeTasks.some(t => t.type === type)
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
if (isPartialConflict && activePartialTasks >= maxConcurrentTasks) {
|
|||
|
|
return { canStart: false, reason: `需要一心多用技能Lv.${multitaskingLevel + 1}` }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return { canStart: true, reason: '' }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 检查任务特定条件
|
|||
|
|
*/
|
|||
|
|
function checkTaskConditions(playerStore, taskType, taskData) {
|
|||
|
|
switch (taskType) {
|
|||
|
|
case TASK_TYPES.READING:
|
|||
|
|
// 需要书籍
|
|||
|
|
if (!taskData.itemId) {
|
|||
|
|
return { canStart: false, reason: '需要选择一本书' }
|
|||
|
|
}
|
|||
|
|
const bookConfig = ITEM_CONFIG[taskData.itemId]
|
|||
|
|
if (!bookConfig || bookConfig.type !== 'book') {
|
|||
|
|
return { canStart: false, reason: '这不是一本书' }
|
|||
|
|
}
|
|||
|
|
// 检查是否已拥有
|
|||
|
|
const hasBook = playerStore.inventory.some(i => i.id === taskData.itemId)
|
|||
|
|
if (!hasBook) {
|
|||
|
|
return { canStart: false, reason: '你没有这本书' }
|
|||
|
|
}
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
case TASK_TYPES.TRAINING:
|
|||
|
|
// 需要耐力
|
|||
|
|
if (playerStore.currentStats.stamina < 10) {
|
|||
|
|
return { canStart: false, reason: '耐力不足' }
|
|||
|
|
}
|
|||
|
|
// 需要武器技能
|
|||
|
|
if (!taskData.skillId) {
|
|||
|
|
return { canStart: false, reason: '需要选择训练技能' }
|
|||
|
|
}
|
|||
|
|
const skill = playerStore.skills[taskData.skillId]
|
|||
|
|
if (!skill || !skill.unlocked) {
|
|||
|
|
return { canStart: false, reason: '技能未解锁' }
|
|||
|
|
}
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
case TASK_TYPES.RESTING:
|
|||
|
|
// 只能在安全区休息
|
|||
|
|
const safeZones = ['camp', 'market', 'blackmarket']
|
|||
|
|
if (!safeZones.includes(playerStore.currentLocation)) {
|
|||
|
|
return { canStart: false, reason: '只能在安全区休息' }
|
|||
|
|
}
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
case TASK_TYPES.PRAYING:
|
|||
|
|
// 需要圣经
|
|||
|
|
const hasBible = playerStore.inventory.some(i => i.id === 'bible')
|
|||
|
|
if (!hasBible) {
|
|||
|
|
return { canStart: false, reason: '需要圣经' }
|
|||
|
|
}
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return { canStart: true, reason: '' }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 结束任务
|
|||
|
|
* @param {Object} gameStore - 游戏Store
|
|||
|
|
* @param {Object} playerStore - 玩家Store
|
|||
|
|
* @param {String|Number} taskId - 任务ID
|
|||
|
|
* @param {Boolean} completed - 是否完成
|
|||
|
|
* @returns {Object} { success: boolean, rewards: Object }
|
|||
|
|
*/
|
|||
|
|
export function endTask(gameStore, playerStore, taskId, completed = false) {
|
|||
|
|
const taskIndex = gameStore.activeTasks.findIndex(t => t.id === taskId)
|
|||
|
|
if (taskIndex === -1) {
|
|||
|
|
return { success: false, message: '任务不存在' }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const task = gameStore.activeTasks[taskIndex]
|
|||
|
|
const rewards = {}
|
|||
|
|
|
|||
|
|
// 如果完成,给予奖励
|
|||
|
|
if (completed) {
|
|||
|
|
const taskRewards = getTaskRewards(playerStore, task)
|
|||
|
|
Object.assign(rewards, taskRewards)
|
|||
|
|
applyTaskRewards(playerStore, task, taskRewards)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 移除任务
|
|||
|
|
gameStore.activeTasks.splice(taskIndex, 1)
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
success: true,
|
|||
|
|
message: completed ? '任务完成' : '任务已取消',
|
|||
|
|
rewards
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 处理任务tick(每秒调用)
|
|||
|
|
* @param {Object} gameStore - 游戏Store
|
|||
|
|
* @param {Object} playerStore - 玩家Store
|
|||
|
|
* @param {Number} deltaTime - 时间增量(毫秒)
|
|||
|
|
* @returns {Array} 完成的任务列表
|
|||
|
|
*/
|
|||
|
|
export function processTaskTick(gameStore, playerStore, deltaTime = 1000) {
|
|||
|
|
const completedTasks = []
|
|||
|
|
|
|||
|
|
for (const task of gameStore.activeTasks) {
|
|||
|
|
const result = processSingleTask(gameStore, playerStore, task, deltaTime)
|
|||
|
|
if (result.completed) {
|
|||
|
|
completedTasks.push({ task, rewards: result.rewards })
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 移除已完成的任务
|
|||
|
|
for (const { task } of completedTasks) {
|
|||
|
|
const index = gameStore.activeTasks.findIndex(t => t.id === task.id)
|
|||
|
|
if (index !== -1) {
|
|||
|
|
gameStore.activeTasks.splice(index, 1)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return completedTasks
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 处理单个任务
|
|||
|
|
*/
|
|||
|
|
function processSingleTask(gameStore, playerStore, task, deltaTime) {
|
|||
|
|
const now = Date.now()
|
|||
|
|
const elapsedSeconds = (now - task.lastTickTime) / 1000
|
|||
|
|
task.lastTickTime = now
|
|||
|
|
|
|||
|
|
task.progress += elapsedSeconds
|
|||
|
|
|
|||
|
|
switch (task.type) {
|
|||
|
|
case TASK_TYPES.READING:
|
|||
|
|
return processReadingTask(gameStore, playerStore, task, elapsedSeconds)
|
|||
|
|
|
|||
|
|
case TASK_TYPES.RESTING:
|
|||
|
|
return processRestingTask(gameStore, playerStore, task, elapsedSeconds)
|
|||
|
|
|
|||
|
|
case TASK_TYPES.TRAINING:
|
|||
|
|
return processTrainingTask(gameStore, playerStore, task, elapsedSeconds)
|
|||
|
|
|
|||
|
|
case TASK_TYPES.WORKING:
|
|||
|
|
return processWorkingTask(gameStore, playerStore, task, elapsedSeconds)
|
|||
|
|
|
|||
|
|
case TASK_TYPES.PRAYING:
|
|||
|
|
return processPrayingTask(gameStore, playerStore, task, elapsedSeconds)
|
|||
|
|
|
|||
|
|
default:
|
|||
|
|
return { completed: false }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 处理阅读任务
|
|||
|
|
*/
|
|||
|
|
function processReadingTask(gameStore, playerStore, task, elapsedSeconds) {
|
|||
|
|
const bookConfig = ITEM_CONFIG[task.data.itemId]
|
|||
|
|
if (!bookConfig) {
|
|||
|
|
return { completed: true, error: '书籍不存在' }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const readingTime = bookConfig.readingTime || 60
|
|||
|
|
|
|||
|
|
// 检查环境惩罚
|
|||
|
|
const location = playerStore.currentLocation
|
|||
|
|
let timeMultiplier = 1.0
|
|||
|
|
|
|||
|
|
// 黑暗区域阅读效率-50%
|
|||
|
|
if (location === 'basement') {
|
|||
|
|
const darkPenaltyReduce = playerStore.globalBonus?.darkPenaltyReduce || 0
|
|||
|
|
timeMultiplier = 0.5 + (darkPenaltyReduce / 100) * 0.5
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 计算有效进度
|
|||
|
|
const effectiveProgress = task.progress * timeMultiplier
|
|||
|
|
|
|||
|
|
if (effectiveProgress >= readingTime) {
|
|||
|
|
// 阅读完成
|
|||
|
|
const rewards = {}
|
|||
|
|
|
|||
|
|
// 给予技能经验
|
|||
|
|
if (bookConfig.expReward) {
|
|||
|
|
for (const [skillId, exp] of Object.entries(bookConfig.expReward)) {
|
|||
|
|
rewards[skillId] = exp
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 完成奖励
|
|||
|
|
if (bookConfig.completionBonus) {
|
|||
|
|
rewards.completionBonus = bookConfig.completionBonus
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 添加日志
|
|||
|
|
if (gameStore.addLog) {
|
|||
|
|
gameStore.addLog(`读完了《${bookConfig.name}》`, 'reward')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return { completed: true, rewards }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 阅读进行中,给予少量经验
|
|||
|
|
if (bookConfig.expReward) {
|
|||
|
|
for (const [skillId, expPerSecond] of Object.entries(bookConfig.expReward)) {
|
|||
|
|
const expPerTick = (expPerSecond / readingTime) * elapsedSeconds * timeMultiplier
|
|||
|
|
// 累积经验,到完成时一次性给予
|
|||
|
|
if (!task.accumulatedExp) {
|
|||
|
|
task.accumulatedExp = {}
|
|||
|
|
}
|
|||
|
|
if (!task.accumulatedExp[skillId]) {
|
|||
|
|
task.accumulatedExp[skillId] = 0
|
|||
|
|
}
|
|||
|
|
task.accumulatedExp[skillId] += expPerTick
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return { completed: false }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 处理休息任务
|
|||
|
|
*/
|
|||
|
|
function processRestingTask(gameStore, playerStore, task, elapsedSeconds) {
|
|||
|
|
// 恢复耐力和生命值
|
|||
|
|
const staminaRecovery = 5 * elapsedSeconds // 每秒恢复5点
|
|||
|
|
const healthRecovery = 2 * elapsedSeconds // 每秒恢复2点
|
|||
|
|
|
|||
|
|
const oldStamina = playerStore.currentStats.stamina
|
|||
|
|
const oldHealth = playerStore.currentStats.health
|
|||
|
|
|
|||
|
|
playerStore.currentStats.stamina = Math.min(
|
|||
|
|
playerStore.currentStats.maxStamina,
|
|||
|
|
playerStore.currentStats.stamina + staminaRecovery
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
playerStore.currentStats.health = Math.min(
|
|||
|
|
playerStore.currentStats.maxHealth,
|
|||
|
|
playerStore.currentStats.health + healthRecovery
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// 检查是否完成
|
|||
|
|
if (task.data.duration && task.progress >= task.data.duration) {
|
|||
|
|
return { completed: true, rewards: {} }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 满状态自动完成
|
|||
|
|
if (playerStore.currentStats.stamina >= playerStore.currentStats.maxStamina &&
|
|||
|
|
playerStore.currentStats.health >= playerStore.currentStats.maxHealth) {
|
|||
|
|
return { completed: true, rewards: {} }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return { completed: false }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 处理训练任务
|
|||
|
|
*/
|
|||
|
|
function processTrainingTask(gameStore, playerStore, task, elapsedSeconds) {
|
|||
|
|
const skillId = task.data.skillId
|
|||
|
|
const skillConfig = SKILL_CONFIG[skillId]
|
|||
|
|
if (!skillConfig) {
|
|||
|
|
return { completed: true, error: '技能不存在' }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 消耗耐力
|
|||
|
|
const staminaCost = 2 * elapsedSeconds
|
|||
|
|
if (playerStore.currentStats.stamina < staminaCost) {
|
|||
|
|
// 耐力不足,任务结束
|
|||
|
|
return { completed: true, rewards: {} }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
playerStore.currentStats.stamina -= staminaCost
|
|||
|
|
|
|||
|
|
// 给予技能经验
|
|||
|
|
const expPerSecond = 1
|
|||
|
|
const expGain = expPerSecond * elapsedSeconds
|
|||
|
|
|
|||
|
|
if (!task.accumulatedExp) {
|
|||
|
|
task.accumulatedExp = {}
|
|||
|
|
}
|
|||
|
|
if (!task.accumulatedExp[skillId]) {
|
|||
|
|
task.accumulatedExp[skillId] = 0
|
|||
|
|
}
|
|||
|
|
task.accumulatedExp[skillId] += expGain
|
|||
|
|
|
|||
|
|
// 检查是否完成
|
|||
|
|
if (task.data.duration && task.progress >= task.data.duration) {
|
|||
|
|
const rewards = { [skillId]: task.accumulatedExp[skillId] || 0 }
|
|||
|
|
return { completed: true, rewards }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return { completed: false }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 处理工作任务
|
|||
|
|
*/
|
|||
|
|
function processWorkingTask(gameStore, playerStore, task, elapsedSeconds) {
|
|||
|
|
// 消耗耐力
|
|||
|
|
const staminaCost = 1.5 * elapsedSeconds
|
|||
|
|
if (playerStore.currentStats.stamina < staminaCost) {
|
|||
|
|
return { completed: true, rewards: {} }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
playerStore.currentStats.stamina -= staminaCost
|
|||
|
|
|
|||
|
|
// 累积货币
|
|||
|
|
if (!task.accumulatedCurrency) {
|
|||
|
|
task.accumulatedCurrency = 0
|
|||
|
|
}
|
|||
|
|
task.accumulatedCurrency += 1 * elapsedSeconds // 每秒1铜币
|
|||
|
|
|
|||
|
|
// 给予相关技能经验(如果有)
|
|||
|
|
if (task.data.skillId) {
|
|||
|
|
if (!task.accumulatedExp) {
|
|||
|
|
task.accumulatedExp = {}
|
|||
|
|
}
|
|||
|
|
if (!task.accumulatedExp[task.data.skillId]) {
|
|||
|
|
task.accumulatedExp[task.data.skillId] = 0
|
|||
|
|
}
|
|||
|
|
task.accumulatedExp[task.data.skillId] += 0.5 * elapsedSeconds
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查是否完成
|
|||
|
|
if (task.data.duration && task.progress >= task.data.duration) {
|
|||
|
|
const rewards = {
|
|||
|
|
currency: Math.floor(task.accumulatedCurrency || 0),
|
|||
|
|
...task.accumulatedExp
|
|||
|
|
}
|
|||
|
|
return { completed: true, rewards }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return { completed: false }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 处理祈祷任务
|
|||
|
|
*/
|
|||
|
|
function processPrayingTask(gameStore, playerStore, task, elapsedSeconds) {
|
|||
|
|
// 祈祷获得信仰经验
|
|||
|
|
if (!task.accumulatedExp) {
|
|||
|
|
task.accumulatedExp = {}
|
|||
|
|
}
|
|||
|
|
if (!task.accumulatedExp.faith) {
|
|||
|
|
task.accumulatedExp.faith = 0
|
|||
|
|
}
|
|||
|
|
task.accumulatedExp.faith += 0.8 * elapsedSeconds
|
|||
|
|
|
|||
|
|
// 恢复精神
|
|||
|
|
const sanityRecovery = 3 * elapsedSeconds
|
|||
|
|
playerStore.currentStats.sanity = Math.min(
|
|||
|
|
playerStore.currentStats.maxSanity,
|
|||
|
|
playerStore.currentStats.sanity + sanityRecovery
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// 检查是否完成
|
|||
|
|
if (task.data.duration && task.progress >= task.data.duration) {
|
|||
|
|
const rewards = { faith: task.accumulatedExp.faith || 0 }
|
|||
|
|
return { completed: true, rewards }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return { completed: false }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取任务奖励
|
|||
|
|
*/
|
|||
|
|
function getTaskRewards(playerStore, task) {
|
|||
|
|
const rewards = {}
|
|||
|
|
|
|||
|
|
if (task.accumulatedExp) {
|
|||
|
|
for (const [skillId, exp] of Object.entries(task.accumulatedExp)) {
|
|||
|
|
rewards[skillId] = Math.floor(exp)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (task.accumulatedCurrency) {
|
|||
|
|
rewards.currency = Math.floor(task.accumulatedCurrency)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return rewards
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 应用任务奖励
|
|||
|
|
*/
|
|||
|
|
function applyTaskRewards(playerStore, task, rewards) {
|
|||
|
|
// 应用技能经验
|
|||
|
|
for (const [skillId, exp] of Object.entries(rewards)) {
|
|||
|
|
if (skillId === 'currency') {
|
|||
|
|
playerStore.currency.copper += exp
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
if (skillId === 'faith') {
|
|||
|
|
// 信仰技能经验
|
|||
|
|
if (!playerStore.skills.faith) {
|
|||
|
|
playerStore.skills.faith = { level: 0, exp: 0, unlocked: true }
|
|||
|
|
}
|
|||
|
|
playerStore.skills.faith.exp += exp
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 普通技能经验
|
|||
|
|
if (playerStore.skills[skillId]) {
|
|||
|
|
playerStore.skills[skillId].exp += exp
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取任务类型名称
|
|||
|
|
*/
|
|||
|
|
function getTaskTypeName(taskType) {
|
|||
|
|
const names = {
|
|||
|
|
reading: '阅读',
|
|||
|
|
resting: '休息',
|
|||
|
|
training: '训练',
|
|||
|
|
working: '工作',
|
|||
|
|
combat: '战斗',
|
|||
|
|
explore: '探索',
|
|||
|
|
praying: '祈祷'
|
|||
|
|
}
|
|||
|
|
return names[taskType] || taskType
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取任务进度信息
|
|||
|
|
* @param {Object} task - 任务对象
|
|||
|
|
* @returns {Object} 进度信息
|
|||
|
|
*/
|
|||
|
|
export function getTaskProgress(task) {
|
|||
|
|
const progress = {
|
|||
|
|
current: task.progress,
|
|||
|
|
total: task.totalDuration || 0,
|
|||
|
|
percentage: task.totalDuration > 0 ? Math.min(100, (task.progress / task.totalDuration) * 100) : 0
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (task.type === TASK_TYPES.READING) {
|
|||
|
|
const bookConfig = ITEM_CONFIG[task.data.itemId]
|
|||
|
|
if (bookConfig) {
|
|||
|
|
progress.total = bookConfig.readingTime || 60
|
|||
|
|
progress.percentage = Math.min(100, (task.progress / progress.total) * 100)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return progress
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取活动中的任务列表
|
|||
|
|
* @param {Object} gameStore - 游戏Store
|
|||
|
|
* @returns {Array} 任务列表
|
|||
|
|
*/
|
|||
|
|
export function getActiveTasks(gameStore) {
|
|||
|
|
return gameStore.activeTasks.map(task => ({
|
|||
|
|
...task,
|
|||
|
|
progress: getTaskProgress(task),
|
|||
|
|
typeName: getTaskTypeName(task.type)
|
|||
|
|
}))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 取消所有任务
|
|||
|
|
* @param {Object} gameStore - 游戏Store
|
|||
|
|
* @returns {Number} 取消的任务数量
|
|||
|
|
*/
|
|||
|
|
export function cancelAllTasks(gameStore) {
|
|||
|
|
const count = gameStore.activeTasks.length
|
|||
|
|
gameStore.activeTasks = []
|
|||
|
|
return count
|
|||
|
|
}
|