Compare commits
2 Commits
3f73669ba4
...
488b1632ef
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
488b1632ef | ||
|
|
85ab6b0507 |
@@ -194,6 +194,29 @@ export class Monster extends ecs.Entity {
|
||||
// 最终技能等级 = 初始技能等级 + 怪物等级增量,且下限为 0
|
||||
model.skills[skill.uuid] = { ...skill, lv: Math.max(0,skill.lv + mon_lv - 2), ccd: 0 };
|
||||
}
|
||||
// 【测试模式专属】如果有覆盖技能配置则应用
|
||||
const testSkills = (this as any)._testSkills;
|
||||
if (testSkills) {
|
||||
if (testSkills.skill !== undefined) {
|
||||
// 如果是替换普攻,通常是修改 hero.skill 字段或从 model.skills 里清除并注入
|
||||
model.skills = {};
|
||||
if (testSkills.skill) {
|
||||
model.skills[testSkills.skill.s_uuid] = {
|
||||
uuid: testSkills.skill.s_uuid,
|
||||
cd: testSkills.skill.cd ?? 0,
|
||||
lv: 1,
|
||||
ccd: 0,
|
||||
overrides: testSkills.skill.overrides
|
||||
};
|
||||
}
|
||||
}
|
||||
if (testSkills.atking !== undefined) model.atking = testSkills.atking;
|
||||
if (testSkills.atked !== undefined) model.atked = testSkills.atked;
|
||||
if (testSkills.dead !== undefined) model.dead = testSkills.dead;
|
||||
if (testSkills.fstart !== undefined) model.fstart = testSkills.fstart;
|
||||
if (testSkills.fend !== undefined) model.fend = testSkills.fend;
|
||||
}
|
||||
|
||||
// 缓存技能射程等派生数据,减少战斗帧内重复计算
|
||||
model.updateSkillDistanceCache();
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ import { HeroInfo, HType } from "../common/config/heroSet";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import {BoxSet, FacSet } from "../common/config/GameSet";
|
||||
import { spawningEngine, GeneratedMonster, AffixType, MonType, MonList } from "./RogueConfig";
|
||||
import { spawningEngine, GeneratedMonster, AffixType, MonType, MonList, TestModeConfig } from "./RogueConfig";
|
||||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||
import { MonMoveComp } from "../hero/MonMoveComp";
|
||||
const { ccclass, property } = _decorator;
|
||||
@@ -195,6 +195,11 @@ export class MissionMonCompComp extends CCComp {
|
||||
const monsters = spawningEngine.generateWave(this.currentWave);
|
||||
this.setupWaveData(monsters);
|
||||
|
||||
// 如果处于测试模式,英雄也需要限制为只产出一个,这部分通知可以配合使用
|
||||
if (TestModeConfig.enable) {
|
||||
mLogger.log(this.debugMode, 'MissionMonComp', "[MissionMonComp] 测试模式已开启:每波仅生成1只基准怪物");
|
||||
}
|
||||
|
||||
mLogger.log(this.debugMode, 'MissionMonComp', "[MissionMonComp] Starting Wave System");
|
||||
}
|
||||
|
||||
@@ -306,12 +311,16 @@ export class MissionMonCompComp extends CCComp {
|
||||
let scale = -1;
|
||||
|
||||
// 获取硬编码的占位点坐标,不再使用随机偏移
|
||||
const basePos = MissionMonCompComp.MON_POSITIONS[posIndex];
|
||||
const basePos = MissionMonCompComp.MON_POSITIONS[posIndex % MissionMonCompComp.MON_POSITIONS.length];
|
||||
const spawnX = basePos.x;
|
||||
const landingY = basePos.y + (monData.isBoss ? 6 : 0);
|
||||
const spawnPos: Vec3 = v3(spawnX, landingY + MissionMonCompComp.MON_DROP_HEIGHT, 0);
|
||||
this.globalSpawnOrder = (this.globalSpawnOrder + 1) % 999;
|
||||
|
||||
// 如果存在测试技能覆盖,则传递下去(修改 mon.load 逻辑或者通过预存)
|
||||
// 为了避免侵入 Mon.ts 的原有逻辑,我们先预存
|
||||
(mon as any)._testSkills = monData.testSkills;
|
||||
|
||||
mon.load(spawnPos, scale, monData.uuid, monData.isBoss, landingY, monLv, posIndex);
|
||||
|
||||
// 设置渲染排序
|
||||
|
||||
@@ -278,16 +278,26 @@ const BOSS_TIERS = new Set([1, 2, 3, 4, 5])
|
||||
const MAJOR_BOSS_TIERS = new Set([3, 5])
|
||||
|
||||
/**
|
||||
* 5 阶梯配置表
|
||||
* key = 阶梯编号 1-5,value = 该阶梯的完整配置
|
||||
* 主线 15 波映射:wave 1-3 → T1, wave 4-6 → T2, ..., wave 13-15 → T5
|
||||
* 5 阶梯配置表 (基于"第5波单怪=1个英雄"的基准推演)
|
||||
*
|
||||
* 核心设计推演:
|
||||
* 1. 玩家反馈:Tier 2 (第4-6波) 的单只怪物强度,刚好对应 1 个 Lv1 英雄。
|
||||
* 2. 设 Tier 2 的 Multiplier 为 2.0,基准近战怪成本为 22。
|
||||
* 3. 则 1个购卡战力 (1个Lv1英雄) = 22 * 2.0 = 44 难度点。
|
||||
* 4. 推演公式:当前波次总难度 (Budget * Multiplier) ≈ 累计购卡数 * 44。
|
||||
* 5. 约束:为避免触发同屏最大 12 只怪的截断机制,后期 Budget 锁定在 260-280,难度全靠 Multiplier (属性) 拉升。
|
||||
*/
|
||||
export const TierConfigs: Record<number, TierConfig> = {
|
||||
1: { multiplier: 1.0, budget: 60, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long], isBossTier: false },
|
||||
2: { multiplier: 1.5, budget: 120, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support], isBossTier: true },
|
||||
3: { multiplier: 2.2, budget: 180, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support, MonType.Assassin], isBossTier: true },
|
||||
4: { multiplier: 3.2, budget: 240, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support, MonType.Assassin, MonType.Summoner], isBossTier: true },
|
||||
5: { multiplier: 4.5, budget: 300, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support, MonType.Assassin, MonType.Summoner], isBossTier: true },
|
||||
// T1(W1-W3): 预计累计 2.3 卡。目标总难度 101。Budget 80 * 1.1 = 88
|
||||
1: { multiplier: 1.1, budget: 80, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long], isBossTier: false },
|
||||
// T2(W4-W6): 预计累计 8.0 卡。目标总难度 352。Budget 160 * 2.0 = 320
|
||||
2: { multiplier: 2.0, budget: 160, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support], isBossTier: true },
|
||||
// T3(W7-W9): 预计累计 15.3卡。目标总难度 673。Budget 220 * 3.0 = 660
|
||||
3: { multiplier: 3.0, budget: 220, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support, MonType.Assassin], isBossTier: true },
|
||||
// T4(W10-W12):预计累计 23.3卡。目标总难度 1025。Budget 260 * 4.0 = 1040
|
||||
4: { multiplier: 4.0, budget: 260, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support, MonType.Assassin, MonType.Summoner], isBossTier: true },
|
||||
// T5(W13-W15):预计累计 31.3卡。目标总难度 1377。Budget 280 * 5.2 = 1456
|
||||
5: { multiplier: 5.2, budget: 280, availableTypes: [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Support, MonType.Assassin, MonType.Summoner], isBossTier: true },
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -525,6 +535,42 @@ export const InfiniteModeConfig = {
|
||||
megaBossInterval: 3,
|
||||
}
|
||||
|
||||
// ======================== 测试模式配置 ========================
|
||||
|
||||
/**
|
||||
* 单挑测试模式配置
|
||||
* 用于寻找 1v1 环境下单只怪物与单只英雄的战力基准
|
||||
* 开启后每波只生成 1 只怪物,且其属性随波次平滑递增
|
||||
*/
|
||||
export const TestModeConfig = {
|
||||
/** 是否开启单挑测试模式 */
|
||||
enable: true,
|
||||
/** 测试模式中生成怪物的基础生命值 (对应 1级 英雄) */
|
||||
baseHp: 150,
|
||||
/** 测试模式中生成怪物的基础攻击力 (对应 1级 英雄) */
|
||||
baseAp: 12,
|
||||
/** 每波次基础属性增加比例 (例如 0.2 表示每波增加 20%) */
|
||||
growthRatePerWave: 0.2,
|
||||
/** 固定的测试怪物类型 */
|
||||
monType: MonType.Melee,
|
||||
/** 固定的测试怪物 UUID (如 6001 兽人战士) */
|
||||
monUuid: 6001,
|
||||
/** 测试模式中生成怪物是否携带特定词缀(为空则不带) */
|
||||
affixes: [] as AffixType[],
|
||||
/** 每次刷新的怪物数量 */
|
||||
spawnCount: 1,
|
||||
|
||||
// ===== 附加技能测试覆盖配置 =====
|
||||
/** 替换普攻技能(清除旧技能,添加新技能) */
|
||||
skill: undefined as { s_uuid: number; cd?: number; overrides?: any } | undefined,
|
||||
/** 覆盖触发技能(完全替换该类型的触发配置) */
|
||||
atking: undefined as { s_uuid: number; t_num: number; overrides?: any }[] | undefined,
|
||||
atked: undefined as { s_uuid: number; t_num: number; overrides?: any }[] | undefined,
|
||||
dead: undefined as { s_uuid: number; t_num: number; overrides?: any }[] | undefined,
|
||||
fstart: undefined as { s_uuid: number; t_num: number; overrides?: any }[] | undefined,
|
||||
fend: undefined as { s_uuid: number; t_num: number; overrides?: any }[] | undefined,
|
||||
}
|
||||
|
||||
// ======================== 向后兼容接口 ========================
|
||||
|
||||
/**
|
||||
@@ -574,6 +620,15 @@ export interface GeneratedMonster {
|
||||
affixes: AffixType[]
|
||||
isBoss: boolean
|
||||
spawnIndex: number
|
||||
/** 测试模式专属:临时覆盖怪物技能配置 */
|
||||
testSkills?: {
|
||||
skill?: { s_uuid: number; cd?: number; overrides?: any };
|
||||
atking?: { s_uuid: number; t_num: number; overrides?: any }[];
|
||||
atked?: { s_uuid: number; t_num: number; overrides?: any }[];
|
||||
dead?: { s_uuid: number; t_num: number; overrides?: any }[];
|
||||
fstart?: { s_uuid: number; t_num: number; overrides?: any }[];
|
||||
fend?: { s_uuid: number; t_num: number; overrides?: any }[];
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 生成引擎 ========================
|
||||
@@ -635,6 +690,42 @@ export class RogueSpawningEngine {
|
||||
generateWave(waveNumber: number): GeneratedMonster[] {
|
||||
if (waveNumber < 1) return []
|
||||
|
||||
// 测试模式拦截
|
||||
if (TestModeConfig.enable) {
|
||||
const growth = 1 + (waveNumber - 1) * TestModeConfig.growthRatePerWave;
|
||||
|
||||
// 提取词缀加成
|
||||
const affixHpMul = 1.0 + TestModeConfig.affixes.reduce(
|
||||
(sum, a) => sum + (AffixConfigs[a].hpMultiplier - 1.0), 0
|
||||
);
|
||||
const affixApMul = 1.0 + TestModeConfig.affixes.reduce(
|
||||
(sum, a) => sum + (AffixConfigs[a].apMultiplier - 1.0), 0
|
||||
);
|
||||
|
||||
const count = Math.max(1, TestModeConfig.spawnCount || 1);
|
||||
const monsters: GeneratedMonster[] = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
monsters.push({
|
||||
uuid: TestModeConfig.monUuid,
|
||||
type: TestModeConfig.monType,
|
||||
hp: Math.round(TestModeConfig.baseHp * growth * affixHpMul),
|
||||
ap: Math.round(TestModeConfig.baseAp * growth * affixApMul),
|
||||
affixes: [...TestModeConfig.affixes],
|
||||
isBoss: false,
|
||||
spawnIndex: i,
|
||||
testSkills: {
|
||||
skill: TestModeConfig.skill,
|
||||
atking: TestModeConfig.atking,
|
||||
atked: TestModeConfig.atked,
|
||||
dead: TestModeConfig.dead,
|
||||
fstart: TestModeConfig.fstart,
|
||||
fend: TestModeConfig.fend
|
||||
}
|
||||
});
|
||||
}
|
||||
return monsters;
|
||||
}
|
||||
|
||||
const tier = Math.ceil(waveNumber / 3)
|
||||
const waveInTier = ((waveNumber - 1) % 3) + 1 // 1, 2, or 3
|
||||
|
||||
|
||||
Reference in New Issue
Block a user