/** * 肉鸽模式配置脚本 - 增强版 * * 功能说明: * - 提供基础的刷怪配置:刷什么怪,刷多少怪 * - 支持程序化关卡生成逻辑,每一关的怪物组合、数量和强度应随关卡进度递增而变化 * - 支持随机事件系统 * * * 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 const EliteMons = [ 5201, 5202, 5203, 5213 ]; // Boss怪物配置表 export const BossMons = [ 5201, 5202, ]; export enum IMons{ ORC=1, HUMAN=2, ELF=3,} export const Mons={ [IMons.ORC]:[5201,5202], [IMons.HUMAN]:[5201,5202], [IMons.ELF]:[5201,5202] } /** * 怪物类型枚举 */ 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.2, // 指数级 - HP LINEAR = 1.0, // 线性 - AP LOGARITHMIC = 0.5 // 对数级 - Speed } /** * 计算波次因子 * @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 { // 公式: Current_Stat = Base_Stat * (1 + waveFactor * 0.15) ^ Growth_Type const growthMultiplier = Math.pow(1 + waveFactor * 0.15, 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; } // ========================================== // 新增:基于威胁点数(Threat Budget)的刷怪系统 // ========================================== // 怪物消耗点数配置 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 < 2) { // 0-2min: 匀速群落 - 100% 战士 return [{ uuid: 5201, weight: 100 }]; } else if (minutes < 5) { // 2-5min: 快速干扰 - 70% 战士, 30% 刺客 return [ { uuid: 5201, weight: 70 }, { uuid: 5301, weight: 30 } ]; } else if (minutes < 10) { // 5-10min: 阵地博弈 - 50% 战士, 40% 刺客, 10% 攻城/治疗 return [ { uuid: 5201, weight: 50 }, { uuid: 5301, weight: 40 }, { uuid: 5401, weight: 5 }, // 攻城 { uuid: 5603, weight: 5 } // 治疗 ]; } else if (minutes < 14) { // 10-14min: 极限生存 - 30% 战士, 50% 刺客, 20% 机制/精英 return [ { uuid: 5201, weight: 30 }, { uuid: 5301, weight: 50 }, { uuid: 5601, weight: 10 }, // 机制怪 { uuid: 5701, weight: 10 } // 精英 ]; } else { // 15min: 剧情杀/决战 - 100% Boss return [{ uuid: 5701, weight: 100 }]; } } /** * 计算当前威胁点数预算 * @param timeInSeconds 游戏时间(秒) * @param heroHpRatio 英雄血量比例 (0-1) */ export function calculateBudget(timeInSeconds: number, heroHpRatio: number = 1.0): number { // 基础预算:每秒产生的点数 // 假设1分钟时为20点,公式: Budget = Base * (1 + 60/60 * 0.2) = Base * 1.2 = 20 => Base ≈ 16 // 修改:降低基础预算,避免队列积压。每秒 1.5 点左右(减半)。 const Base_Budget = 1.5; // 时间因子:随时间增加难度 const timeFactor = 1 + (timeInSeconds / 60) * 0.2; // 强度乘数 (DDA):根据英雄状态调整 let intensityMultiplier = 1.0; if (heroHpRatio < 0.4) { // 绝地求生:血量低于40%时,预算缩减30% intensityMultiplier = 0.7; } // 公式: Budget(t) = Base_Budget * (1 + t/60 * 0.2) * Intensity_Multiplier return Math.floor(Base_Budget * timeFactor * intensityMultiplier); } /** * 根据预算生成怪物列表 * @param timeInSeconds 游戏时间(秒) * @param heroHpRatio 英雄血量比例 */ export function generateMonstersFromBudget(timeInSeconds: number, heroHpRatio: number = 1.0): IMonsConfig[] { // 15分钟后只生成Boss,且如果已经有Boss可能需要控制(这里简化为每次调用都尝试生成,由外部控制频率或唯一性) // 但根据"清除所有杂兵,锁定刷出最终BOSS",这里只返回Boss配置 if (timeInSeconds >= 15 * 60) { // 可以在这里做特殊处理,比如只返回一个Boss,或者返回空如果Boss已存在 // 假设外部每秒调用,这里返回Boss,外部队列会堆积。 // 建议:Boss波次由特殊逻辑控制,或者这里返回Boss但消耗巨大预算 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) { 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, // 简单等级计算,实际属性由getMonAttr处理 position: Math.floor(Math.random() * 5) // 随机位置 0-4 }); } } return monsters; }