/** * 肉鸽模式配置脚本 - 增强版 * * 功能说明: * - 提供基础的刷怪配置:刷什么怪,刷多少怪 * - 支持程序化关卡生成逻辑,每一关的怪物组合、数量和强度应随关卡进度递增而变化 * - 支持随机事件系统 * * * 3. 全局动态 Scaling 算法既然是 15 分钟单局,属性不应一成不变。 * 建议引入 Wave_Factor (波次因子): * 公式建议: Current_Stat = Base_Stat * (1 + (time / 60) * 0.15) ^ Growth_Type * •HP 成长: 设为指数级 (Growth_Type = 1.2)。后期怪物血量会呈几何倍数增加,适配『神装英雄』。 * •AP 成长: 设为线性 (Growth_Type = 1.0)。保证怪物能击穿后期护盾,但不会一击必杀。 * •Speed 成长: 设为对数级 (Growth_Type = 0.5)。防止后期怪物速度过快导致画面瞬移。 * * @author 游戏开发团队 * @version 2.0 增强版 * @date 2025-10-19 */ import { HeroInfo } from "../common/config/heroSet"; /** * 怪物类型枚举 */ export enum MonType { NORMAL = 0, // 普通怪物 ELITE = 1, // 精英怪物 BOSS = 2 // Boss怪物 } /** * 怪物配置接口 */ export interface IMonsConfig { uuid: number; // 怪物ID type: MonType; // 怪物类型 level: number; // 等级 position?: number; // 位置(可选) buffs?: any[]; // buff列表(可选) } /** * 怪物属性接口 */ export interface MonAttrs { hp: number; mp: number; ap: number; def: number; speed: number; } /** * 成长类型枚举 */ enum GrowthType { EXPONENTIAL = 1.15, // 指数级 - HP LINEAR = 1.05, // 线性 - AP LOGARITHMIC = 0.3 // 对数级 - Speed } /** * 全局刷怪配置接口 */ export interface IRogueGlobalConfig { /** 场上最大怪物数量限制 */ maxMonsterCount: number; /** 刷怪逻辑执行间隔(秒) - 决定多久计算一次生成 */ spawnLogicInterval: number; /** 单个怪物生成间隔(秒) - 队列中怪物的实际生成频率 */ spawnInterval: number; /** 基础威胁预算 - 每秒产生的基础点数 */ baseBudget: number; /** 时间难度因子 - 每分钟增加的预算比例 (0.2 = 20%) */ timeDifficultyFactor: number; /** 绝地求生阈值 - 英雄血量低于此比例时触发减缓刷怪 */ survivalHpThreshold: number; /** 绝地求生预算乘数 - 触发阈值时的预算折扣 */ survivalBudgetMultiplier: number; /** 单次逻辑最大生成怪物数限制 - 防止瞬间生成过多 */ maxSpawnPerLogic: number; } /** * 默认配置 */ export const DefaultRogueConfig: IRogueGlobalConfig = { maxMonsterCount: 50, // 默认同屏50只 spawnLogicInterval: 1.0, // 每秒计算一次 spawnInterval: 0.6, // 队列出怪间隔0.6秒 baseBudget: 5.0, // 基础预算 timeDifficultyFactor: 0.5, // 每分钟增加50%预算 survivalHpThreshold: 0.4, // 40%血量触发保护 survivalBudgetMultiplier: 0.7, // 保护时预算打7折 maxSpawnPerLogic: 5 // 单次最多生成5只 }; // 当前配置实例 let currentConfig: IRogueGlobalConfig = { ...DefaultRogueConfig }; /** * 获取当前全局配置 */ export function getRogueConfig(): IRogueGlobalConfig { return currentConfig; } /** * 更新全局配置 * @param config 部分或全部配置 */ export function updateRogueConfig(config: Partial) { currentConfig = { ...currentConfig, ...config }; console.log("[RogueConfig] Configuration updated:", currentConfig); } /** * 计算当前威胁点数预算 * @param timeInSeconds 游戏时间(秒) * @param heroHpRatio 英雄血量比例 (0-1) */ export function calculateBudget(timeInSeconds: number, heroHpRatio: number = 1.0): number { const config = getRogueConfig(); // 基础预算 const Base_Budget = config.baseBudget; // 时间因子:随时间增加难度 const timeFactor = 1 + (timeInSeconds / 60) * config.timeDifficultyFactor; // 强度乘数 (DDA):根据英雄状态调整 let intensityMultiplier = 1.0; if (heroHpRatio < config.survivalHpThreshold) { // 绝地求生:血量低于阈值时预算缩减 intensityMultiplier = config.survivalBudgetMultiplier; } // 公式: Budget(t) = Base_Budget * (1 + t/60 * Factor) * Intensity_Multiplier return Math.floor(Base_Budget * timeFactor * intensityMultiplier); } /** * 根据预算生成怪物列表 * @param timeInSeconds 游戏时间(秒) * @param heroHpRatio 英雄血量比例 */ export function generateMonstersFromBudget(timeInSeconds: number, heroHpRatio: number = 1.0): IMonsConfig[] { const config = getRogueConfig(); // 15分钟后只生成Boss if (timeInSeconds >= 15 * 60) { return [{ uuid: 5701, type: MonType.BOSS, level: Math.floor(timeInSeconds / 60), position: 2 }]; } const budget = calculateBudget(timeInSeconds, heroHpRatio); const weights = getSpawnWeights(timeInSeconds); const monsters: IMonsConfig[] = []; let currentBudget = budget; // 构建权重池 const pool: number[] = []; weights.forEach(w => { for(let i=0; i MonsterCost[w.uuid] || 1)); // 限制单次生成最大数量 while (currentBudget >= minCost && attempts < 50 && monsters.length < config.maxSpawnPerLogic) { attempts++; const uuid = pool[Math.floor(Math.random() * pool.length)]; const cost = MonsterCost[uuid] || 1; if (currentBudget >= cost) { currentBudget -= cost; let type = MonType.NORMAL; if (uuid === 5701) type = MonType.BOSS; else if (MonsterCost[uuid] >= 10) type = MonType.ELITE; monsters.push({ uuid: uuid, type: type, level: Math.floor(timeInSeconds / 60) + 1, position: Math.floor(Math.random() * 5) }); } } return monsters; } /** * 计算波次因子 * @param stage 当前波次 * @param timeInSeconds 游戏进行时间(秒) * @returns 波次因子 (0-1之间,15分钟时达到最大) */ function calculateWaveFactor(stage: number, timeInSeconds: number = 0): number { const MAX_GAME_TIME = 15 * 60; // 15分钟 = 900秒 const effectiveTime = timeInSeconds || (stage * 30); // 如果没有时间数据,用波次估算(每波30秒) const factor = Math.min(effectiveTime / MAX_GAME_TIME, 1.0); return factor; } /** * 应用成长公式到基础属性 * @param baseStat 基础属性值 * @param waveFactor 波次因子 (0-1) * @param growthType 成长类型 * @returns 成长后的属性值 */ function applyGrowthFormula(baseStat: number, waveFactor: number, growthType: GrowthType): number { // 基础倍率:15分钟成长约 16 倍 (1 + 1.0 * 15) // waveFactor 是 0-1 (基于15分钟) const TIME_SCALING = 15; const growthMultiplier = Math.pow(1 + waveFactor * TIME_SCALING, growthType); return Math.floor(baseStat * growthMultiplier); } /** * 获取怪物动态成长属性 * @param stage 当前波次 * @param uuid 怪物ID * @param monType 怪物类型 * @param timeInSeconds 游戏进行时间(秒) * @returns 怪物属性 */ export function getMonAttr(stage: number, uuid: number, monType: MonType = MonType.NORMAL, timeInSeconds: number = 0): MonAttrs { const baseMonster = HeroInfo[uuid]; if (!baseMonster) { console.warn(`[RogueConfig] 未找到怪物ID: ${uuid}`); return { hp: 100, mp: 100, ap: 10, def: 0, speed: 100 }; } // 计算波次因子 const waveFactor = calculateWaveFactor(stage, timeInSeconds); // 根据怪物类型应用额外的倍率 let typeMultiplier = 1.0; if (monType === MonType.ELITE) { typeMultiplier = 2.0; // 精英怪2倍属性 } else if (monType === MonType.BOSS) { typeMultiplier = 5.0; // Boss 5倍属性 } // 应用不同的成长类型 const hp = applyGrowthFormula(baseMonster.hp, waveFactor, GrowthType.EXPONENTIAL) * typeMultiplier; const ap = applyGrowthFormula(baseMonster.ap, waveFactor, GrowthType.LINEAR) * typeMultiplier; const speed = applyGrowthFormula(baseMonster.speed, waveFactor, GrowthType.LOGARITHMIC); // MP和DEF使用线性成长 const mp = applyGrowthFormula(baseMonster.mp, waveFactor, GrowthType.LINEAR); const def = applyGrowthFormula(baseMonster.def, waveFactor, GrowthType.LINEAR) * typeMultiplier; return { hp: Math.floor(hp), mp: Math.floor(mp), ap: Math.floor(ap), def: Math.floor(def), speed: Math.floor(speed) }; } /** * 根据波次生成怪物配置 * @param stage 当前波次 * @returns IMonsConfig数组 */ export function getStageMonConfigs(stage: number): IMonsConfig[] { const monsterConfigs: IMonsConfig[] = []; // 基础怪物列表(从heroset.ts中获取) const normalMons = [5201, 5301, 5401, 5501, 5601, 5602, 5603, 5604]; const eliteMons = [5701]; // 根据波次生成怪物配置 // 波次越高,怪物数量越多,精英怪物出现概率越高 const baseCount = 5 + Math.floor(stage / 2); // 基础数量每2波增加1 const eliteChance = Math.min(stage * 0.05, 0.3); // 精英怪概率最高30% const bossWave = stage % 10 === 0; // 每10波出Boss if (bossWave && stage > 0) { // Boss波 monsterConfigs.push({ uuid: 5701, type: MonType.BOSS, level: stage }); } else { // 普通波 for (let i = 0; i < baseCount; i++) { // 随机决定是否生成精英怪 const isElite = Math.random() < eliteChance; const monList = isElite ? eliteMons : normalMons; const randomUuid = monList[Math.floor(Math.random() * monList.length)]; monsterConfigs.push({ uuid: randomUuid, type: isElite ? MonType.ELITE : MonType.NORMAL, level: stage, position: i % 5 }); } } return monsterConfigs; } /** * 无限等级经验配置 * @param level 当前等级 * @returns 升级所需经验值 */ export function getLevelExp(level: number): number { // 基础经验 const baseExp = 100; // 增长因子 (每级增加20%) const growthFactor = 1.2; // 公式: Exp = Base * (Factor ^ (Level - 1)) // 1级: 100 // 2级: 120 // 3级: 144 // 10级: ~515 // 20级: ~3194 return Math.floor(baseExp * Math.pow(growthFactor, level - 1)); } /** * 计算怪物掉落金币 * @param uuid 怪物ID * @param level 怪物等级 * @param type 怪物类型 */ export function calculateMonsterGold(uuid: number, level: number, type: MonType): number { const cost = MonsterCost[uuid] || 1; // 危险值系数: cost越大越危险 let danger_ratio = 1 + cost * 0.1; let type_ratio = 1; if(type == MonType.BOSS) type_ratio = 10; else if(type == MonType.ELITE) type_ratio = 3; // 公式: 基础(10) * 类型 * 危险值 + 等级加成 const baseGold = 10; let gold = Math.floor(baseGold * type_ratio * danger_ratio + level); return gold; } // 怪物消耗点数配置 export const MonsterCost: Record = { 5201: 1, // 兽人战士 (Warrior) 5301: 3, // 兽人斥候 (Assassin) 5401: 5, // 兽人卫士 (Tank) 5501: 4, // 兽人射手 (Remote) 5601: 10, // 兽人自爆兵 (Mechanic) 5602: 8, // 兽人召唤师 5603: 6, // 兽人祭司 (Healer) 5604: 6, // 兽人图腾师 5701: 50, // 兽人首领 (Elite/Boss) }; // 刷怪权重接口 interface SpawnWeight { uuid: number; weight: number; } /** * 根据游戏时间获取刷怪权重 * @param timeInSeconds 游戏时间(秒) */ function getSpawnWeights(timeInSeconds: number): SpawnWeight[] { const minutes = timeInSeconds / 60; if (minutes < 3) { // 0-3min: 匀速群落 - 100% 战士 return [{ uuid: 5201, weight: 100 }]; } else if (minutes < 8) { // 3-8min: 快速干扰 - 70% 战士, 30% 刺客 return [ { uuid: 5201, weight: 70 }, { uuid: 5301, weight: 30 } ]; } else if (minutes < 14) { // 8-14min: 阵地博弈 - 40% 战士, 30% 刺客, 20% 攻城/治疗/精英 return [ { uuid: 5201, weight: 40 }, { uuid: 5301, weight: 30 }, { uuid: 5401, weight: 10 }, { uuid: 5603, weight: 10 }, { uuid: 5701, weight: 10 } ]; } else { // 15min: 剧情杀/决战 - 100% Boss return [{ uuid: 5701, weight: 100 }]; } }