Files
text-adventure-game/utils/environmentSystem.js

487 lines
14 KiB
JavaScript
Raw Normal View History

/**
* 环境系统 - 环境惩罚计算被动技能获取
* Phase 6 核心系统实现
*/
import { LOCATION_CONFIG } from '@/config/locations.js'
import { SKILL_CONFIG } from '@/config/skills.js'
import { applyMilestoneBonus } from './skillSystem.js'
/**
* 环境类型枚举
*/
export const ENVIRONMENT_TYPES = {
NORMAL: 'normal', // 普通环境
DARK: 'dark', // 黑暗环境
NARROW: 'narrow', // 狭窄空间
HARSH: 'harsh' // 恶劣环境
}
/**
* 环境惩罚配置
*/
const ENVIRONMENT_PENALTIES = {
[ENVIRONMENT_TYPES.DARK]: {
apPenalty: 0.2, // AP -20%
epPenalty: 0.2, // EP -20%
readingPenalty: 0.5, // 阅读效率 -50%
adaptSkill: 'night_vision', // 适应技能
description: '黑暗'
},
[ENVIRONMENT_TYPES.NARROW]: {
apPenalty: 0, // AP 无惩罚
epPenalty: 0.3, // EP -30%
readingPenalty: 0, // 阅读无惩罚
adaptSkill: 'narrow_fighting', // 适应技能
description: '狭窄'
},
[ENVIRONMENT_TYPES.HARSH]: {
apPenalty: 0.1, // AP -10%
epPenalty: 0.1, // EP -10%
readingPenalty: 0.2, // 阅读效率 -20%
adaptSkill: 'survivalist', // 适应技能
description: '恶劣'
},
[ENVIRONMENT_TYPES.NORMAL]: {
apPenalty: 0,
epPenalty: 0,
readingPenalty: 0,
adaptSkill: null,
description: '普通'
}
}
/**
* 获取当前位置的环境惩罚
* @param {String} locationId - 位置ID
* @param {Object} playerStore - 玩家Store
* @returns {Object} 惩罚信息
*/
export function getEnvironmentPenalty(locationId, playerStore) {
const location = LOCATION_CONFIG[locationId]
if (!location) {
return getDefaultPenalty()
}
const environmentType = location.environment || ENVIRONMENT_TYPES.NORMAL
const basePenalty = ENVIRONMENT_PENALTIES[environmentType] || ENVIRONMENT_PENALTIES[ENVIRONMENT_TYPES.NORMAL]
// 应用技能减少惩罚
const penalty = { ...basePenalty }
// 夜视技能减少黑暗惩罚
if (environmentType === ENVIRONMENT_TYPES.DARK) {
const darkPenaltyReduce = playerStore.globalBonus?.darkPenaltyReduce || 0
penalty.apPenalty = Math.max(0, penalty.apPenalty * (1 - darkPenaltyReduce / 100))
penalty.epPenalty = Math.max(0, penalty.epPenalty * (1 - darkPenaltyReduce / 100))
penalty.readingPenalty = Math.max(0, penalty.readingPenalty * (1 - darkPenaltyReduce / 100))
}
return penalty
}
/**
* 获取默认惩罚普通环境
*/
function getDefaultPenalty() {
return {
apPenalty: 0,
epPenalty: 0,
readingPenalty: 0,
adaptSkill: null,
description: '普通'
}
}
/**
* 计算AP环境修正
* @param {String} locationId - 位置ID
* @param {Object} playerStore - 玩家Store
* @returns {Number} 修正倍率 (0-1)
*/
export function getAPModifier(locationId, playerStore) {
const penalty = getEnvironmentPenalty(locationId, playerStore)
return 1 - penalty.apPenalty
}
/**
* 计算EP环境修正
* @param {String} locationId - 位置ID
* @param {Object} playerStore - 玩家Store
* @returns {Number} 修正倍率 (0-1)
*/
export function getEPModifier(locationId, playerStore) {
const penalty = getEnvironmentPenalty(locationId, playerStore)
return 1 - penalty.epPenalty
}
/**
* 计算阅读效率修正
* @param {String} locationId - 位置ID
* @param {Object} playerStore - 玩家Store
* @returns {Number} 修正倍率 (0-1)
*/
export function getReadingModifier(locationId, playerStore) {
const penalty = getEnvironmentPenalty(locationId, playerStore)
return 1 - penalty.readingPenalty
}
/**
* 处理环境被动经验
* 在特定环境中被动获得技能经验
* @param {Object} gameStore - 游戏Store
* @param {Object} playerStore - 玩家Store
* @param {String} locationId - 位置ID
* @param {Number} deltaTime - 时间增量
* @returns {Object} 获得的经验 { skillId: exp }
*/
export function processEnvironmentExp(gameStore, playerStore, locationId, deltaTime = 1) {
const location = LOCATION_CONFIG[locationId]
if (!location) return {}
const environmentType = location.environment || ENVIRONMENT_TYPES.NORMAL
const penalty = ENVIRONMENT_PENALTIES[environmentType]
if (!penalty.adaptSkill) {
return {}
}
const adaptSkillId = penalty.adaptSkill
const skillConfig = SKILL_CONFIG[adaptSkillId]
if (!skillConfig) {
return {}
}
// 检查技能是否已解锁
if (!playerStore.skills[adaptSkillId] || !playerStore.skills[adaptSkillId].unlocked) {
// 检查解锁条件
if (skillConfig.unlockCondition) {
const condition = skillConfig.unlockCondition
if (condition.location === locationId) {
// 首次进入该环境,解锁技能
if (!playerStore.skills[adaptSkillId]) {
playerStore.skills[adaptSkillId] = {
level: 0,
exp: 0,
unlocked: true
}
if (gameStore.addLog) {
gameStore.addLog(`解锁了被动技能: ${skillConfig.name}`, 'system')
}
}
}
}
return {}
}
// 计算被动经验(每秒获得基础经验)
const baseExpRate = 0.5 // 每秒0.5经验
const expGain = baseExpRate * deltaTime
// 应用阅读速度加成
const readingSpeedBonus = playerStore.globalBonus?.readingSpeed || 1
const finalExp = expGain * readingSpeedBonus
// 添加经验
playerStore.skills[adaptSkillId].exp += finalExp
// 检查升级
const exp = playerStore.skills[adaptSkillId].exp
const maxExp = skillConfig.expPerLevel(playerStore.skills[adaptSkillId].level + 1)
if (exp >= maxExp && playerStore.skills[adaptSkillId].level < skillConfig.maxLevel) {
playerStore.skills[adaptSkillId].level++
playerStore.skills[adaptSkillId].exp -= maxExp
if (gameStore.addLog) {
gameStore.addLog(`${skillConfig.name} 提升到了 Lv.${playerStore.skills[adaptSkillId].level}!`, 'reward')
}
// 检查里程碑奖励(需要调用技能系统)
const newLevel = playerStore.skills[adaptSkillId].level
if (SKILL_CONFIG[adaptSkillId].milestones && SKILL_CONFIG[adaptSkillId].milestones[newLevel]) {
applyMilestoneBonus(playerStore, adaptSkillId, newLevel)
}
}
return { [adaptSkillId]: finalExp }
}
/**
* 检查位置解锁条件
* @param {String} locationId - 位置ID
* @param {Object} playerStore - 玩家Store
* @returns {Object} { unlocked: boolean, reason: string }
*/
export function checkLocationUnlock(locationId, playerStore) {
const location = LOCATION_CONFIG[locationId]
if (!location) {
return { unlocked: false, reason: '位置不存在' }
}
if (!location.unlockCondition) {
return { unlocked: true, reason: '' }
}
const condition = location.unlockCondition
switch (condition.type) {
case 'kill':
// 击杀条件
const killCount = (playerStore.killCount || {})[condition.target] || 0
if (killCount < condition.count) {
return {
unlocked: false,
reason: `需要击杀 ${condition.count}${getEnemyName(condition.target)} (当前: ${killCount})`
}
}
break
case 'item':
// 物品条件
const hasItem = playerStore.inventory?.some(i => i.id === condition.item)
if (!hasItem) {
const itemName = getItemName(condition.item)
return { unlocked: false, reason: `需要 ${itemName}` }
}
break
case 'level':
// 等级条件
const playerLevel = playerStore.level?.current || 1
if (playerLevel < condition.level) {
return { unlocked: false, reason: `需要等级 ${condition.level}` }
}
break
case 'skill':
// 技能条件
const skill = playerStore.skills[condition.skillId]
if (!skill || skill.level < condition.level) {
return { unlocked: false, reason: `需要技能达到指定等级` }
}
break
case 'flag':
// 标志条件
if (!playerStore.flags?.[condition.flag]) {
return { unlocked: false, reason: '需要完成特定事件' }
}
break
}
return { unlocked: true, reason: '' }
}
/**
* 获取敌人名称辅助函数
*/
function getEnemyName(enemyId) {
// 简化实现,实际应该从 ENEMY_CONFIG 获取
const names = {
wild_dog: '野狗',
test_boss: '测试Boss'
}
return names[enemyId] || enemyId
}
/**
* 获取物品名称辅助函数
*/
function getItemName(itemId) {
// 简化实现,实际应该从 ITEM_CONFIG 获取
const names = {
basement_key: '地下室钥匙',
old_book: '破旧书籍'
}
return names[itemId] || itemId
}
/**
* 检查位置是否安全
* @param {String} locationId - 位置ID
* @returns {Boolean}
*/
export function isSafeLocation(locationId) {
const location = LOCATION_CONFIG[locationId]
return location?.type === 'safe'
}
/**
* 检查位置是否为战斗区域
* @param {String} locationId - 位置ID
* @returns {Boolean}
*/
export function isCombatLocation(locationId) {
const location = LOCATION_CONFIG[locationId]
return location?.type === 'danger' || location?.type === 'dungeon'
}
/**
* 获取位置可用的活动
* @param {String} locationId - 位置ID
* @returns {Array} 活动列表
*/
export function getLocationActivities(locationId) {
const location = LOCATION_CONFIG[locationId]
return location?.activities || []
}
/**
* 获取位置连接
* @param {String} locationId - 位置ID
* @returns {Array} 连接的位置ID列表
*/
export function getLocationConnections(locationId) {
const location = LOCATION_CONFIG[locationId]
return location?.connections || []
}
/**
* 检查位置是否可到达
* @param {String} fromId - 起始位置ID
* @param {String} toId - 目标位置ID
* @param {Object} playerStore - 玩家Store
* @returns {Object} { reachable: boolean, reason: string }
*/
export function canTravelTo(fromId, toId, playerStore) {
const fromLocation = LOCATION_CONFIG[fromId]
if (!fromLocation) {
return { reachable: false, reason: '当前位置不存在' }
}
// 检查是否直接连接
if (!fromLocation.connections?.includes(toId)) {
return { reachable: false, reason: '无法直接到达' }
}
// 检查目标位置解锁条件
return checkLocationUnlock(toId, playerStore)
}
/**
* 计算位置转移时间
* @param {String} fromId - 起始位置ID
* @param {String} toId - 目标位置ID
* @returns {Number} 转移时间
*/
export function getTravelTime(fromId, toId) {
// 简化实现所有位置间转移时间为5秒
return 5
}
/**
* 获取环境描述
* @param {String} locationId - 位置ID
* @param {Object} playerStore - 玩家Store
* @returns {String} 环境描述
*/
export function getEnvironmentDescription(locationId, playerStore) {
const location = LOCATION_CONFIG[locationId]
if (!location) return ''
const penalty = getEnvironmentPenalty(locationId, playerStore)
let description = location.description || ''
// 添加环境效果描述
if (location.environment === ENVIRONMENT_TYPES.DARK) {
const hasNightVision = playerStore.skills.night_vision?.level > 0
if (!hasNightVision) {
description += ' [黑暗: AP/EP-20% 阅读效率-50%]'
} else {
const reduce = playerStore.globalBonus?.darkPenaltyReduce || 0
description += ` [黑暗: 惩罚减少${reduce}%]`
}
}
return description
}
/**
* 获取位置的可敌人列表
* @param {String} locationId - 位置ID
* @returns {Array} 敌人ID列表
*/
export function getLocationEnemies(locationId) {
const location = LOCATION_CONFIG[locationId]
return location?.enemies || []
}
/**
* 获取位置的NPC列表
* @param {String} locationId - 位置ID
* @returns {Array} NPC ID列表
*/
export function getLocationNPCs(locationId) {
const location = LOCATION_CONFIG[locationId]
return location?.npcs || []
}
/**
* 检查是否有负面状态来自环境
* @param {String} locationId - 位置ID
* @param {Object} playerStore - 玩家Store
* @returns {Array} 负面状态列表
*/
export function getEnvironmentNegativeStatus(locationId, playerStore) {
const location = LOCATION_CONFIG[locationId]
if (!location) return []
const status = []
// 黑暗环境可能造成精神压力
if (location.environment === ENVIRONMENT_TYPES.DARK) {
const hasNightVision = playerStore.skills.night_vision?.level || 0
if (hasNightVision < 5) {
status.push({
type: 'darkness',
name: '黑暗恐惧',
effect: '精神逐渐下降',
severity: hasNightVision > 0 ? 'mild' : 'moderate'
})
}
}
return status
}
/**
* 处理环境负面状态效果
* @param {Object} playerStore - 玩家Store
* @param {String} locationId - 位置ID
* @param {Number} deltaTime - 时间增量
*/
export function processEnvironmentEffects(playerStore, locationId, deltaTime = 1) {
const location = LOCATION_CONFIG[locationId]
if (!location) return
// 黑暗环境的精神压力
if (location.environment === ENVIRONMENT_TYPES.DARK) {
const nightVisionLevel = playerStore.skills.night_vision?.level || 0
// 夜视5级以下会缓慢消耗精神
if (nightVisionLevel < 5) {
const sanityDrain = 0.1 * (1 - nightVisionLevel * 0.1) * deltaTime
playerStore.currentStats.sanity = Math.max(
0,
playerStore.currentStats.sanity - sanityDrain
)
}
}
// 恶劣环境的持续影响
if (location.environment === ENVIRONMENT_TYPES.HARSH) {
const survivalistLevel = playerStore.skills.survivalist?.level || 0
// 生存技能可以减少恶劣环境影响
if (survivalistLevel < 5) {
const staminaDrain = 0.2 * (1 - survivalistLevel * 0.1) * deltaTime
playerStore.currentStats.stamina = Math.max(
0,
playerStore.currentStats.stamina - staminaDrain
)
}
}
}