- 移除 SkillRange 枚举和 SkillDisVal 常量,统一使用 HType 表示攻击距离 - 删除 heroInfo 中的 rangeType 字段,直接使用 type 字段 - 更新英雄配置,将职业类型简化为近战、中程、远程三类 - 移除怪物属性中的 mp 和 def 字段,简化属性计算 - 更新移动和技能距离计算逻辑,直接使用 HType 判断
348 lines
11 KiB
TypeScript
348 lines
11 KiB
TypeScript
/**
|
||
* 肉鸽模式配置脚本 - 增强版 (Wave System)
|
||
*
|
||
* 功能说明:
|
||
* - 采用 15 个小波次(每分钟 1 波)
|
||
* - 整合进 3 个大的节奏阶段:构筑期、磨合期、极限期
|
||
* - 废弃动态预算,使用确定性波次配置
|
||
*
|
||
* @author 游戏开发团队
|
||
* @version 3.0 波次重构版
|
||
* @date 2025-10-19
|
||
*/
|
||
|
||
import { HeroInfo } from "../common/config/heroSet";
|
||
import { mLogger } from "../common/Logger";
|
||
|
||
/**
|
||
* 怪物类型枚举
|
||
*/
|
||
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;
|
||
ap: number;
|
||
speed: number;
|
||
exp?: number;
|
||
gold?: number;
|
||
}
|
||
|
||
/**
|
||
* 成长类型枚举
|
||
*/
|
||
enum GrowthType {
|
||
EXPONENTIAL = 1.15, // 指数级 - HP
|
||
LINEAR = 1.05, // 线性 - AP
|
||
LOGARITHMIC = 0.3 // 对数级 - Speed
|
||
}
|
||
|
||
/**
|
||
* 刷怪权重接口
|
||
*/
|
||
export interface SpawnWeight {
|
||
uuid: number;
|
||
weight: number;
|
||
type?: MonType; // 默认为 NORMAL
|
||
}
|
||
|
||
/**
|
||
* 波次配置接口
|
||
*/
|
||
export interface WaveConfig {
|
||
waveId: number; // 波次ID (1-15)
|
||
name: string; // 波次名称
|
||
duration: number; // 持续时间 (秒),通常为60
|
||
spawnInterval: number; // 刷怪间隔 (秒)
|
||
maxActive: number; // 同屏最大怪物数
|
||
weights: SpawnWeight[]; // 怪物权重池
|
||
}
|
||
|
||
// 怪物ID映射 (方便阅读)
|
||
const MON_IDS = {
|
||
WARRIOR: 5201, // 战士
|
||
ASSASSIN: 5301, // 斥候
|
||
TANK: 5401, // 卫士
|
||
ARCHER: 5501, // 射手
|
||
BOMBER: 5601, // 自爆兵
|
||
SUMMONER: 5602, // 召唤师
|
||
HEALER: 5603, // 祭司
|
||
TOTEM: 5604, // 图腾师
|
||
BOSS: 5701 // 首领
|
||
};
|
||
|
||
/**
|
||
* 全局波次配置表 (15波)
|
||
*/
|
||
export const RogueWaves: WaveConfig[] = [
|
||
// --- 第一阶段:构筑期 (0-5min) ---
|
||
{
|
||
waveId: 1, name: "热身", duration: 60, spawnInterval: 2.0, maxActive: 5,
|
||
weights: [{ uuid: MON_IDS.WARRIOR, weight: 100 }]
|
||
},
|
||
{
|
||
waveId: 2, name: "加速", duration: 60, spawnInterval: 1.8, maxActive: 6,
|
||
weights: [
|
||
{ uuid: MON_IDS.WARRIOR, weight: 80 },
|
||
{ uuid: MON_IDS.ASSASSIN, weight: 20 }
|
||
]
|
||
},
|
||
{
|
||
waveId: 3, name: "堆叠", duration: 60, spawnInterval: 1.6, maxActive: 7,
|
||
weights: [
|
||
{ uuid: MON_IDS.WARRIOR, weight: 60 },
|
||
{ uuid: MON_IDS.ASSASSIN, weight: 40 }
|
||
]
|
||
},
|
||
{
|
||
waveId: 4, name: "硬度测试", duration: 60, spawnInterval: 1.5, maxActive: 8,
|
||
weights: [
|
||
{ uuid: MON_IDS.WARRIOR, weight: 50 },
|
||
{ uuid: MON_IDS.ASSASSIN, weight: 30 },
|
||
{ uuid: MON_IDS.TANK, weight: 20 }
|
||
]
|
||
},
|
||
{
|
||
waveId: 5, name: "精英首秀", duration: 60, spawnInterval: 1.5, maxActive: 8,
|
||
weights: [
|
||
{ uuid: MON_IDS.WARRIOR, weight: 40 },
|
||
{ uuid: MON_IDS.ASSASSIN, weight: 40 },
|
||
{ uuid: MON_IDS.TANK, weight: 20 }
|
||
// 注意:第5分钟会触发固定事件刷精英怪,这里只配普通怪
|
||
]
|
||
},
|
||
|
||
// --- 第二阶段:磨合期 (5-10min) ---
|
||
{
|
||
waveId: 6, name: "远程威胁", duration: 60, spawnInterval: 1.4, maxActive: 10,
|
||
weights: [
|
||
{ uuid: MON_IDS.TANK, weight: 30 },
|
||
{ uuid: MON_IDS.ARCHER, weight: 40 },
|
||
{ uuid: MON_IDS.WARRIOR, weight: 30 }
|
||
]
|
||
},
|
||
{
|
||
waveId: 7, name: "铁桶阵", duration: 60, spawnInterval: 1.3, maxActive: 10,
|
||
weights: [
|
||
{ uuid: MON_IDS.TANK, weight: 50 },
|
||
{ uuid: MON_IDS.ARCHER, weight: 50 }
|
||
]
|
||
},
|
||
{
|
||
waveId: 8, name: "续航干扰", duration: 60, spawnInterval: 1.2, maxActive: 12,
|
||
weights: [
|
||
{ uuid: MON_IDS.WARRIOR, weight: 30 },
|
||
{ uuid: MON_IDS.TANK, weight: 20 },
|
||
{ uuid: MON_IDS.ARCHER, weight: 30 },
|
||
{ uuid: MON_IDS.HEALER, weight: 20 }
|
||
]
|
||
},
|
||
{
|
||
waveId: 9, name: "走位测试", duration: 60, spawnInterval: 1.2, maxActive: 12,
|
||
weights: [
|
||
{ uuid: MON_IDS.WARRIOR, weight: 40 },
|
||
{ uuid: MON_IDS.BOMBER, weight: 30 }, // 自爆兵
|
||
{ uuid: MON_IDS.ARCHER, weight: 30 }
|
||
]
|
||
},
|
||
{
|
||
waveId: 10, name: "中场Boss", duration: 60, spawnInterval: 5.0, maxActive: 3,
|
||
// Boss战期间,只刷少量护卫,Boss由事件触发
|
||
weights: [
|
||
{ uuid: MON_IDS.TANK, weight: 100 }
|
||
]
|
||
},
|
||
|
||
// --- 第三阶段:极限期 (10-15min) ---
|
||
{
|
||
waveId: 11, name: "混乱开端", duration: 60, spawnInterval: 1.0, maxActive: 15,
|
||
weights: [
|
||
{ uuid: MON_IDS.SUMMONER, weight: 20 },
|
||
{ uuid: MON_IDS.TOTEM, weight: 20 },
|
||
{ uuid: MON_IDS.WARRIOR, weight: 30 },
|
||
{ uuid: MON_IDS.ARCHER, weight: 30 }
|
||
]
|
||
},
|
||
{
|
||
waveId: 12, name: "全家桶", duration: 60, spawnInterval: 0.9, maxActive: 18,
|
||
weights: [
|
||
{ uuid: MON_IDS.WARRIOR, weight: 15 },
|
||
{ uuid: MON_IDS.ASSASSIN, weight: 15 },
|
||
{ uuid: MON_IDS.TANK, weight: 15 },
|
||
{ uuid: MON_IDS.ARCHER, weight: 15 },
|
||
{ uuid: MON_IDS.BOMBER, weight: 15 },
|
||
{ uuid: MON_IDS.HEALER, weight: 10 },
|
||
{ uuid: MON_IDS.SUMMONER, weight: 15 }
|
||
]
|
||
},
|
||
{
|
||
waveId: 13, name: "精英小队", duration: 60, spawnInterval: 1.0, maxActive: 15,
|
||
weights: [
|
||
{ uuid: MON_IDS.TANK, weight: 40 },
|
||
{ uuid: MON_IDS.ARCHER, weight: 40 },
|
||
{ uuid: MON_IDS.WARRIOR, weight: 20, type: MonType.ELITE } // 尝试混入精英
|
||
]
|
||
},
|
||
{
|
||
waveId: 14, name: "绝地求生", duration: 60, spawnInterval: 0.6, maxActive: 20,
|
||
weights: [
|
||
{ uuid: MON_IDS.ASSASSIN, weight: 50 },
|
||
{ uuid: MON_IDS.BOMBER, weight: 50 }
|
||
]
|
||
},
|
||
{
|
||
waveId: 15, name: "终局", duration: 60, spawnInterval: 3.0, maxActive: 5,
|
||
// 最终Boss战,只刷少量精英护卫
|
||
weights: [
|
||
{ uuid: MON_IDS.TANK, weight: 100, type: MonType.ELITE }
|
||
]
|
||
}
|
||
];
|
||
|
||
// 精英怪和Boss刷新时间配置 (时间单位: 秒)
|
||
// 注意:这里的时间点应与波次结束/开始对应
|
||
export const SpecialMonsterSchedule = [
|
||
{ time: 4 * 60 + 50, uuid: MON_IDS.WARRIOR, type: MonType.ELITE, level: 5, desc: "5分钟前夕: 精英战士" },
|
||
{ time: 9 * 60 + 55, uuid: MON_IDS.BOSS, type: MonType.BOSS, level: 15, desc: "10分钟: 兽人首领" },
|
||
{ time: 14 * 60 + 55, uuid: MON_IDS.BOSS, type: MonType.BOSS, level: 30, desc: "15分钟: 最终Boss" }
|
||
];
|
||
|
||
/**
|
||
* 获取当前时间的波次配置
|
||
* @param timeInSeconds 游戏时间 (秒)
|
||
*/
|
||
export function getCurrentWave(timeInSeconds: number): WaveConfig {
|
||
const waveIndex = Math.min(Math.floor(timeInSeconds / 60), 14);
|
||
return RogueWaves[waveIndex];
|
||
}
|
||
|
||
/**
|
||
* 怪物消耗点数配置 (用于经验/金币计算)
|
||
*/
|
||
export const MonsterCost: Record<number, number> = {
|
||
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)
|
||
};
|
||
|
||
/**
|
||
* 计算波次因子
|
||
* @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 * 60);
|
||
const factor = Math.min(effectiveTime / MAX_GAME_TIME, 1.0);
|
||
return factor;
|
||
}
|
||
|
||
/**
|
||
* 应用成长公式到基础属性
|
||
*/
|
||
function applyGrowthFormula(baseStat: number, waveFactor: number, growthType: GrowthType): number {
|
||
// 基础倍率:15分钟成长约 21 倍 (1 + 1.0 * 20)
|
||
const TIME_SCALING = 20;
|
||
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) {
|
||
mLogger.warn(true, 'RogueConfig', `[RogueConfig] 未找到怪物ID: ${uuid}`);
|
||
return { hp: 100, ap: 10, speed: 100 };
|
||
}
|
||
|
||
// 计算波次因子
|
||
const waveFactor = calculateWaveFactor(0, timeInSeconds);
|
||
|
||
// 动态质量系数:初始 1.5倍 -> 15分钟 6.0倍
|
||
// 大幅降低初始强度(原固定5.0),随时间线性增强
|
||
const qualityRatio = 1.5 + (4.5 * waveFactor);
|
||
|
||
// 根据怪物类型应用额外的倍率
|
||
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 * qualityRatio;
|
||
const ap = applyGrowthFormula(baseMonster.ap, waveFactor, GrowthType.LINEAR) * typeMultiplier * qualityRatio;
|
||
const speed = applyGrowthFormula(baseMonster.speed, waveFactor, GrowthType.LOGARITHMIC);
|
||
|
||
return {
|
||
hp: Math.floor(hp),
|
||
ap: Math.floor(ap),
|
||
speed: Math.floor(speed)
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 无限等级经验配置
|
||
*/
|
||
export function getLevelExp(level: number): number {
|
||
const baseExp = 100;
|
||
const growthFactor = 1.2;
|
||
return Math.floor(baseExp * Math.pow(growthFactor, level - 1));
|
||
}
|
||
|
||
/**
|
||
* 计算怪物掉落金币
|
||
*/
|
||
export function calculateMonsterGold(uuid: number, level: number, type: MonType): number {
|
||
const cost = MonsterCost[uuid] || 1;
|
||
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;
|
||
|
||
const baseGold = 10;
|
||
let gold = Math.floor((baseGold * type_ratio * danger_ratio + level) * 8);
|
||
return gold;
|
||
}
|
||
|
||
/**
|
||
* 计算怪物经验值
|
||
*/
|
||
export function calculateMonsterExp(uuid: number, level: number): number {
|
||
const cost = MonsterCost[uuid] || 1;
|
||
return Math.max(1, Math.floor(cost * 1.0 * Math.pow(1.15, level - 1) * 8));
|
||
}
|