Files
heros/assets/script/game/map/RogueConfig.ts
2025-07-28 00:14:20 +08:00

686 lines
25 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 肉鸽模式配置脚本
*
* 功能说明:
* - 提供肉鸽模式的波次生成配置
* - 包含词条系统和怪物强化逻辑
* - 供 MissionMonComp.ts 等组件调用
*
* 波次规则固定9波模式
* - 1-3波普通波次
* - 4-6波怪物潮波次大量低级怪物
* - 7-8波精英波次
* - 9波最终Boss波次
*
* @author 游戏开发团队
* @version 2.0
* @date 2025-07-12
*/
// 导入配置
import { HQuality, HeroInfo, MonsterSeriesConfig, getRandomSeries } from "../common/config/heroSet";
import { BuffAttr } from "../common/config/SkillSet";
// ==================== 核心配置 ====================
/**
* 肉鸽模式波次类型枚举
*/
export enum RogueWaveType {
NORMAL = "normal", // 普通波次1-3波
HORDE = "horde", // 怪物潮波次4-6波
ELITE = "elite", // 精英波次7-8波
FINAL_BOSS = "final_boss" // 最终Boss波次9波
}
/**
* 固定数值配置(根据波次固定血量和攻击力)
*/
export const RogueStatsConfig = {
// 血量配置
hp: {
1: 10, // 波次1小怪血量10
2: 15, // 波次2小怪血量15插值
3: 25, // 波次3小怪血量25
4: 35, // 波次4怪物潮血量35插值
5: 60, // 波次5怪物潮血量60
6: 80, // 波次6怪物潮血量80插值
7: 100, // 波次7精英血量100
8: 150, // 波次8精英血量150插值
9: 500 // 波次9boss血量500
},
// 攻击力配置
attack: {
1: 5, // 1-3波攻击力5
2: 5, // 1-3波攻击力5
3: 5, // 1-3波攻击力5
4: 8, // 4-6波攻击力8
5: 8, // 4-6波攻击力8
6: 8, // 4-6波攻击力8
7: 12, // 7-8波攻击力12
8: 12, // 7-8波攻击力12
9: 30 // 9波boss攻击力30
},
/**
* 获取指定波次的血量
*/
getHp(waveNumber: number): number {
return this.hp[waveNumber] || this.hp[9]; // 默认返回boss血量
},
/**
* 获取指定波次的攻击力
*/
getAttack(waveNumber: number): number {
return this.attack[waveNumber] || this.attack[9]; // 默认返回boss攻击力
}
};
/**
* 怪物词条配置直接使用BuffAttr作为词条类型
* 这样可以直接复用Mon.ts中的Buff处理逻辑
*/
export const MonsterAffixConfig = {
[BuffAttr.ATK]: {
name: "狂暴",
description: "攻击力提升50%",
value: 50,
rarity: "common",
applicableQualities: [HQuality.GREEN, HQuality.BLUE, HQuality.PURPLE]
},
[BuffAttr.ATK_CD]: {
name: "迅捷",
description: "攻击速度提升30%",
value: 30, // 正值表示提升Mon.ts中会转换为负值
rarity: "common",
applicableQualities: [HQuality.GREEN, HQuality.BLUE]
},
[BuffAttr.CRITICAL]: {
name: "致命",
description: "暴击率提升25%",
value: 25,
rarity: "uncommon",
applicableQualities: [HQuality.BLUE, HQuality.PURPLE]
},
[BuffAttr.DEF]: {
name: "装甲",
description: "减少受到的伤害30%",
value: 30,
rarity: "common",
applicableQualities: [HQuality.GREEN, HQuality.BLUE, HQuality.PURPLE]
},
[BuffAttr.HP]: {
name: "坚韧",
description: "生命值提升50%",
value: 50,
rarity: "common",
applicableQualities: [HQuality.GREEN, HQuality.BLUE, HQuality.PURPLE]
},
[BuffAttr.CRITICAL_DMG]: {
name: "嗜血",
description: "暴击伤害提升40%",
value: 40,
rarity: "uncommon",
applicableQualities: [HQuality.BLUE, HQuality.PURPLE]
},
[BuffAttr.DODGE]: {
name: "敏捷",
description: "闪避率提升25%",
value: 25,
rarity: "uncommon",
applicableQualities: [HQuality.GREEN, HQuality.BLUE]
},
[BuffAttr.BURN_COUNT]: {
name: "燃烧",
description: "攻击附带易伤效果额外持续3次",
value: 3,
rarity: "uncommon",
applicableQualities: [HQuality.GREEN, HQuality.BLUE, HQuality.PURPLE]
},
[BuffAttr.PUNCTURE]: {
name: "穿刺",
description: "攻击穿透1个敌人",
value: 1,
rarity: "uncommon",
applicableQualities: [HQuality.BLUE, HQuality.PURPLE]
},
[BuffAttr.FROST_RATIO]: {
name: "冰冻",
description: "攻击有20%概率冰冻敌人",
value: 20,
rarity: "rare",
applicableQualities: [HQuality.BLUE, HQuality.PURPLE]
}
};
/**
* 词条数量配置9波固定模式
*/
export const AffixCountConfig = {
currentMode: "normal" as "normal" | "enhanced",
modes: {
normal: {
[RogueWaveType.NORMAL]: 0, // 1-3波无词条
[RogueWaveType.HORDE]: 0, // 4-6波无词条数量取胜
[RogueWaveType.ELITE]: 1, // 7-8波1个词条
[RogueWaveType.FINAL_BOSS]: 2, // 9波2个词条
},
enhanced: {
[RogueWaveType.NORMAL]: 1, // 1-3波1个词条
[RogueWaveType.HORDE]: 1, // 4-6波1个词条
[RogueWaveType.ELITE]: 2, // 7-8波2个词条
[RogueWaveType.FINAL_BOSS]: 3, // 9波3个词条
}
},
setMode(mode: "normal" | "enhanced") {
this.currentMode = mode;
},
getAffixCount(waveType: RogueWaveType): number {
return this.modes[this.currentMode][waveType] || 0;
},
enableNormalMode() {
this.setMode("normal");
},
enableEnhancedMode() {
this.setMode("enhanced");
}
};
/**
* 波次配置固定9波模式
*/
export const RogueWaveConfig = {
// 固定9波模式每波类型固定
getWaveType: (waveNumber: number): RogueWaveType => {
if (waveNumber <= 3) {
return RogueWaveType.NORMAL; // 1-3波普通
} else if (waveNumber <= 6) {
return RogueWaveType.HORDE; // 4-6波怪物潮
} else if (waveNumber <= 8) {
return RogueWaveType.ELITE; // 7-8波精英
} else if (waveNumber === 9) {
return RogueWaveType.FINAL_BOSS; // 9波最终Boss
} else {
// 超过9波的情况如果需要循环
const cycleWave = ((waveNumber - 1) % 9) + 1;
return RogueWaveConfig.getWaveType(cycleWave);
}
},
maxWaves: 9 // 固定最大波数
};
// ==================== 肉鸽配置生成器 ====================
/**
* 肉鸽配置生成器
*/
export class RogueConfig {
/**
* 生成波次配置(主入口)
*/
static generateWaveConfig(waveNumber: number) {
const waveType = RogueWaveConfig.getWaveType(waveNumber);
const fixedHp = RogueStatsConfig.getHp(waveNumber);
const fixedAttack = RogueStatsConfig.getAttack(waveNumber);
console.log(`[RogueConfig]: 第${waveNumber}波 - 类型: ${waveType} - 固定HP: ${fixedHp}, 固定攻击: ${fixedAttack} (固定9波模式)`);
// 根据类型生成配置
switch (waveType) {
case RogueWaveType.NORMAL:
return this.generateNormalWave(waveNumber);
case RogueWaveType.HORDE:
return this.generateHordeWave(waveNumber);
case RogueWaveType.ELITE:
return this.generateEliteWave(waveNumber);
case RogueWaveType.FINAL_BOSS:
return this.generateFinalBossWave(waveNumber);
default:
return this.generateNormalWave(waveNumber);
}
}
/**
* 生成普通波次1-3波
*/
static generateNormalWave(waveNumber: number) {
const series = getRandomSeries();
const seriesConfig = MonsterSeriesConfig[series];
// 普通波次固定数量10个怪物
const baseCount = 10;
const monsters = [];
// 选择怪物类型
const availableTypes = [];
if (seriesConfig.monsters.warrior.length > 0) availableTypes.push("warrior");
if (seriesConfig.monsters.remote.length > 0) availableTypes.push("remote");
if (seriesConfig.monsters.mage.length > 0) availableTypes.push("mage");
if (availableTypes.length > 0) {
const randomType = availableTypes[Math.floor(Math.random() * availableTypes.length)];
const typeMonsters = seriesConfig.monsters[randomType];
const randomMonster = typeMonsters[Math.floor(Math.random() * typeMonsters.length)];
const monsterInfo = HeroInfo[randomMonster];
// 生成词条
const affixes = this.generateMonsterAffixes(
monsterInfo.quality,
waveNumber,
RogueWaveType.NORMAL
);
// 应用强化
const enhanced = this.applyAffixesToMonster(affixes, monsterInfo);
monsters.push({
uuid: randomMonster,
count: baseCount,
type: randomType,
series: series,
affixes: affixes,
enhancedStats: enhanced.stats,
buffData: enhanced.buffData,
// 肉鸽固定数值
rogueHp: RogueStatsConfig.getHp(waveNumber),
rogueAttack: RogueStatsConfig.getAttack(waveNumber)
});
}
return {
waveType: RogueWaveType.NORMAL,
monsters: monsters,
description: `${waveNumber}波 - 普通波次 (10个怪物)`,
waveNumber: waveNumber
};
}
/**
* 生成怪物潮波次4-6波
*/
static generateHordeWave(waveNumber: number) {
const series = getRandomSeries();
const seriesConfig = MonsterSeriesConfig[series];
// 怪物潮固定数量20个怪物
const baseCount = 20;
const monsters = [];
// 怪物潮主要使用绿色品质的小怪
const hordeMonsters = seriesConfig.allMonsters.filter(uuid => {
return HeroInfo[uuid] && HeroInfo[uuid].quality === HQuality.GREEN;
});
if (hordeMonsters.length > 0) {
const hordeMonster = hordeMonsters[Math.floor(Math.random() * hordeMonsters.length)];
const monsterInfo = HeroInfo[hordeMonster];
// 生成词条(怪物潮通常没有词条,靠数量取胜)
const affixes = this.generateMonsterAffixes(
monsterInfo.quality,
waveNumber,
RogueWaveType.HORDE
);
const enhanced = this.applyAffixesToMonster(affixes, monsterInfo);
monsters.push({
uuid: hordeMonster,
count: baseCount,
type: "warrior",
series: series,
isHorde: true,
affixes: affixes,
enhancedStats: enhanced.stats,
buffData: enhanced.buffData,
// 肉鸽固定数值
rogueHp: RogueStatsConfig.getHp(waveNumber),
rogueAttack: RogueStatsConfig.getAttack(waveNumber)
});
} else {
// 如果没有绿色怪物,使用其他怪物
const availableTypes = [];
if (seriesConfig.monsters.warrior.length > 0) availableTypes.push("warrior");
if (seriesConfig.monsters.remote.length > 0) availableTypes.push("remote");
if (seriesConfig.monsters.mage.length > 0) availableTypes.push("mage");
if (availableTypes.length > 0) {
const randomType = availableTypes[Math.floor(Math.random() * availableTypes.length)];
const typeMonsters = seriesConfig.monsters[randomType];
const randomMonster = typeMonsters[Math.floor(Math.random() * typeMonsters.length)];
const monsterInfo = HeroInfo[randomMonster];
const affixes = this.generateMonsterAffixes(
monsterInfo.quality,
waveNumber,
RogueWaveType.HORDE
);
const enhanced = this.applyAffixesToMonster(affixes, monsterInfo);
monsters.push({
uuid: randomMonster,
count: baseCount,
type: randomType,
series: series,
isHorde: true,
affixes: affixes,
enhancedStats: enhanced.stats,
buffData: enhanced.buffData,
// 肉鸽固定数值
rogueHp: RogueStatsConfig.getHp(waveNumber),
rogueAttack: RogueStatsConfig.getAttack(waveNumber)
});
}
}
return {
waveType: RogueWaveType.HORDE,
monsters: monsters,
description: `${waveNumber}波 - 怪物潮 (20个怪物)`,
waveNumber: waveNumber
};
}
/**
* 生成精英波次7-8波
*/
static generateEliteWave(waveNumber: number) {
const series = getRandomSeries();
const seriesConfig = MonsterSeriesConfig[series];
const monsters = [];
// 1. 生成5个精英怪物
const eliteMonsters = seriesConfig.allMonsters.filter(uuid => {
return HeroInfo[uuid] && HeroInfo[uuid].quality === HQuality.BLUE;
});
if (eliteMonsters.length > 0) {
const eliteMonster = eliteMonsters[Math.floor(Math.random() * eliteMonsters.length)];
const monsterInfo = HeroInfo[eliteMonster];
// 生成精英词条
const affixes = this.generateMonsterAffixes(
monsterInfo.quality,
waveNumber,
RogueWaveType.ELITE
);
const enhanced = this.applyAffixesToMonster(affixes, monsterInfo);
monsters.push({
uuid: eliteMonster,
count: 5, // 固定5个精英
type: "elite",
series: series,
affixes: affixes,
enhancedStats: enhanced.stats,
buffData: enhanced.buffData,
// 肉鸽固定数值
rogueHp: RogueStatsConfig.getHp(waveNumber),
rogueAttack: RogueStatsConfig.getAttack(waveNumber)
});
}
// 2. 生成10个普通小怪
const availableTypes = [];
if (seriesConfig.monsters.warrior.length > 0) availableTypes.push("warrior");
if (seriesConfig.monsters.remote.length > 0) availableTypes.push("remote");
if (seriesConfig.monsters.mage.length > 0) availableTypes.push("mage");
if (availableTypes.length > 0) {
const randomType = availableTypes[Math.floor(Math.random() * availableTypes.length)];
const typeMonsters = seriesConfig.monsters[randomType];
const randomMonster = typeMonsters[Math.floor(Math.random() * typeMonsters.length)];
const monsterInfo = HeroInfo[randomMonster];
// 小怪没有词条
const affixes = this.generateMonsterAffixes(
monsterInfo.quality,
waveNumber,
RogueWaveType.NORMAL // 小怪使用普通词条规则
);
const enhanced = this.applyAffixesToMonster(affixes, monsterInfo);
monsters.push({
uuid: randomMonster,
count: 10, // 固定10个小怪
type: "normal",
series: series,
affixes: affixes,
enhancedStats: enhanced.stats,
buffData: enhanced.buffData,
// 肉鸽固定数值
rogueHp: RogueStatsConfig.getHp(waveNumber),
rogueAttack: RogueStatsConfig.getAttack(waveNumber)
});
}
return {
waveType: RogueWaveType.ELITE,
monsters: monsters,
description: `${waveNumber}波 - 精英波次 (5个精英+10个小怪)`,
waveNumber: waveNumber
};
}
/**
* 生成最终Boss波次第9波
*/
static generateFinalBossWave(waveNumber: number) {
const series = getRandomSeries();
const seriesConfig = MonsterSeriesConfig[series];
// 查找Boss怪物
const bossMonsters = seriesConfig.allMonsters.filter(uuid => {
return HeroInfo[uuid] && HeroInfo[uuid].quality === HQuality.PURPLE;
});
const bossMonster = bossMonsters.length > 0 ?
bossMonsters[Math.floor(Math.random() * bossMonsters.length)] :
seriesConfig.allMonsters[Math.floor(Math.random() * seriesConfig.allMonsters.length)];
const bossInfo = HeroInfo[bossMonster];
// 生成最终Boss词条
const bossAffixes = this.generateMonsterAffixes(
bossInfo.quality,
waveNumber,
RogueWaveType.FINAL_BOSS
);
const enhancedBoss = this.applyAffixesToMonster(bossAffixes, bossInfo);
// 1个Boss + 5个小怪
const monsters = [];
// 1. 添加Boss
monsters.push({
uuid: bossMonster,
count: 1,
type: "final_boss",
series: series,
isFinalBoss: true,
affixes: bossAffixes,
enhancedStats: enhancedBoss.stats,
buffData: enhancedBoss.buffData,
// 肉鸽固定数值
rogueHp: RogueStatsConfig.getHp(waveNumber),
rogueAttack: RogueStatsConfig.getAttack(waveNumber)
});
// 2. 添加5个小怪
const availableTypes = [];
if (seriesConfig.monsters.warrior.length > 0) availableTypes.push("warrior");
if (seriesConfig.monsters.remote.length > 0) availableTypes.push("remote");
if (seriesConfig.monsters.mage.length > 0) availableTypes.push("mage");
if (availableTypes.length > 0) {
const randomType = availableTypes[Math.floor(Math.random() * availableTypes.length)];
const typeMonsters = seriesConfig.monsters[randomType];
const randomMonster = typeMonsters[Math.floor(Math.random() * typeMonsters.length)];
const monsterInfo = HeroInfo[randomMonster];
// 小怪没有词条
const affixes = this.generateMonsterAffixes(
monsterInfo.quality,
waveNumber,
RogueWaveType.NORMAL // 小怪使用普通词条规则
);
const enhanced = this.applyAffixesToMonster(affixes, monsterInfo);
monsters.push({
uuid: randomMonster,
count: 5, // 固定5个小怪
type: "normal",
series: series,
affixes: affixes,
enhancedStats: enhanced.stats,
buffData: enhanced.buffData,
// 肉鸽固定数值
rogueHp: RogueStatsConfig.getHp(waveNumber),
rogueAttack: RogueStatsConfig.getAttack(waveNumber)
});
}
return {
waveType: RogueWaveType.FINAL_BOSS,
monsters: monsters,
description: `${waveNumber}波 - 最终Boss战 (1个Boss+5个小怪)`,
waveNumber: waveNumber
};
}
/**
* 生成怪物词条现在直接返回BuffAttr数组
*/
static generateMonsterAffixes(
monsterQuality: number,
waveNumber: number,
waveType: RogueWaveType
): BuffAttr[] {
const affixCount = AffixCountConfig.getAffixCount(waveType);
if (affixCount === 0) return [];
const availableAffixes = Object.keys(MonsterAffixConfig).filter(affixType => {
const buffAttr = parseInt(affixType) as BuffAttr;
const config = MonsterAffixConfig[buffAttr];
return config.applicableQualities.includes(monsterQuality);
}).map(key => parseInt(key) as BuffAttr);
const selectedAffixes: BuffAttr[] = [];
for (let i = 0; i < affixCount && availableAffixes.length > 0; i++) {
const randomIndex = Math.floor(Math.random() * availableAffixes.length);
const selectedAffix = availableAffixes[randomIndex];
selectedAffixes.push(selectedAffix);
availableAffixes.splice(randomIndex, 1);
}
return selectedAffixes;
}
/**
* 应用词条到怪物(简化版本,主要用于日志显示)
*/
static applyAffixesToMonster(affixes: BuffAttr[], baseStats: any) {
const modifiedStats = { ...baseStats };
const buffData = [];
// 怪物能力提升倍数3倍强化
const enhancementMultiplier = 3;
for (const affix of affixes) {
const config = MonsterAffixConfig[affix];
if (config) {
// 应用3倍强化到配置值
const enhancedValue = config.value * enhancementMultiplier;
buffData.push({
buff_type: affix,
value: enhancedValue // 使用强化后的值
});
// 预览属性变化实际应用在Mon.ts中
switch (affix) {
case BuffAttr.ATK:
// 攻击力提升幅度加大每波提升额外增加10%再乘以3倍
modifiedStats.ap = Math.floor(modifiedStats.ap * (1 + enhancedValue / 100 + baseStats.lv * 0.1 * enhancementMultiplier));
break;
case BuffAttr.HP:
// 生命值提升幅度加大每波提升额外增加15%再乘以3倍
modifiedStats.hp = Math.floor(modifiedStats.hp * (1 + enhancedValue / 100 + baseStats.lv * 0.15 * enhancementMultiplier));
break;
case BuffAttr.ATK_CD:
// 攻击速度提升也应用3倍效果
modifiedStats.cd = Math.max(0.1, modifiedStats.cd * (1 - enhancedValue / 100));
break;
case BuffAttr.DEF:
// 防御力提升3倍效果
modifiedStats.def = (modifiedStats.def || 0) + enhancedValue;
break;
case BuffAttr.CRITICAL:
// 暴击率提升3倍效果
modifiedStats.crit = (modifiedStats.crit || 0) + enhancedValue;
break;
case BuffAttr.CRITICAL_DMG:
// 暴击伤害提升3倍效果
modifiedStats.crit_d = (modifiedStats.crit_d || 0) + enhancedValue;
break;
case BuffAttr.DODGE:
// 闪避率提升3倍效果
modifiedStats.dod = (modifiedStats.dod || 0) + enhancedValue;
break;
case BuffAttr.BURN_COUNT:
// 燃烧次数提升3倍效果
modifiedStats.burn_count = (modifiedStats.burn_count || 0) + enhancedValue;
break;
case BuffAttr.PUNCTURE:
// 穿刺数量提升3倍效果
modifiedStats.puncture = (modifiedStats.puncture || 0) + enhancedValue;
break;
case BuffAttr.FROST_RATIO:
// 冰冻概率提升3倍效果
modifiedStats.frost_ratto = (modifiedStats.frost_ratto || 0) + enhancedValue;
break;
}
console.log(`[RogueConfig]: 应用3倍强化词条 ${BuffAttr[affix]} - 原始值: ${config.value}% → 强化值: ${enhancedValue}%`);
}
}
return {
stats: modifiedStats,
buffData: buffData, // 返回Buff数据格式与Mon.ts兼容
affixes: affixes
};
}
/**
* 获取怪物等级
*/
static getMonsterLevel(waveNumber: number): number {
return Math.max(1, Math.floor(waveNumber / 1) + 1);
}
}
// ==================== 导出接口 ====================
/**
* 外部调用接口 - 获取波次配置
*/
export const getRogueWaveConfig = (waveNumber: number) => {
return RogueConfig.generateWaveConfig(waveNumber);
};