import { BattlePhase } from 'db://assets/mx/module/battle'; import { LevelWaveParser, NO_BOSS } from '../../battle/config/LevelWaveParser'; import { parseMonsterUnitDefId } from '../../battle/config/MonsterHpCalculator'; import { TableBattleConfigProvider } from '../../battle/config/TableBattleConfigProvider'; import type { ProjectBattleHandle } from '../../battle/runtime/BattleRuntime'; import { TableNames } from '../../game/ConfigTableData'; import { MonsterDataManager, MonsterType } from '../../manager/MonsterDataManager'; /** 万神幡:从己方出怪口额外召唤关卡 Boss */ export class BattleGameExtraBossSkill { /** * 万神幡动画播完后:从当前关卡 boss 池随机 1 个 Boss,经己方出怪口额外出兵。 * @param battle 战斗 * @param ownerPlayerId 施放方;省略则用 battle.player * @returns 是否已成功创建实体 */ static trySummon(battle: ProjectBattleHandle, ownerPlayerId?: number): boolean { if (NO_BOSS) { console.log('[BattleGameExtraBossSkill] 调试屏蔽 Boss'); return false; } if (battle.session.phase !== BattlePhase.COMBAT) { console.log('[BattleGameExtraBossSkill] 仅战斗阶段可召唤 Boss'); return false; } const levelRow = gg.data.table.getTableData(TableNames.Level, battle.LevelConfigId); if (!levelRow) { console.log('[BattleGameExtraBossSkill] Level 缺失', battle.LevelConfigId); return false; } const bossIds = LevelWaveParser.collectUniqueBossMonsterIds(levelRow.boss); if (bossIds.length <= 0) { console.log('[BattleGameExtraBossSkill] 关卡无 Boss 配置', battle.LevelConfigId); return false; } const pickIdx = battle.session.rng.int(0, bossIds.length - 1); const monsterId = bossIds[pickIdx]; const row = MonsterDataManager.getMonsterDataById(monsterId); if (!row) { console.log('[BattleGameExtraBossSkill] Monster 缺失', monsterId); return false; } if (row.type !== MonsterType.Boss) { console.log('[BattleGameExtraBossSkill] 非 Boss 类型,仍尝试召唤', monsterId, row.type); } const ownerId = ownerPlayerId != null ? Math.max(0, Math.floor(Number(ownerPlayerId) || 0)) : (battle.player?.playerId ?? 0); const route = BattleGameExtraBossSkill._resolveSpawnRoute(ownerId); const difficultyRow = BattleGameExtraBossSkill._resolveCurrentWaveDifficultyRow(battle, route.spawnPort); const config = gg.battle.config as TableBattleConfigProvider; const unitDefId = config.ensureSpawnMonsterDef(monsterId, route.spawnPort, difficultyRow); // 本项目怪物不设皮肤,不传 spineSkinOverride const entity = battle.session.spawner.spawnExtraEnemy( unitDefId, route.spawnPort, route.targetPlayerId, ); if (entity == null) return false; console.log( `[BattleGameExtraBossSkill] 召唤 Boss id=${monsterId} port=${route.spawnPort}` + ` target=${route.targetPlayerId} unitDef=${unitDefId}`, ); return true; } /** 本机从 spawnPoint_2 攻 AI;AI 从 spawnPoint_1 攻本机 */ private static _resolveSpawnRoute(ownerPlayerId: number): { spawnPort: number; targetPlayerId: number; enemyCamp: boolean; } { if (ownerPlayerId === 0) { return { spawnPort: 2, targetPlayerId: 1, enemyCamp: false }; } return { spawnPort: 1, targetPlayerId: 0, enemyCamp: true }; } /** 当前波次对应难度行(与技能召唤一致,取本出口首段) */ private static _resolveCurrentWaveDifficultyRow(battle: ProjectBattleHandle, spawnPort: number): number { const waves = battle.session.levelDef?.waves; if (!waves?.length) { console.log('[BattleGameExtraBossSkill] 无波次配置,难度行兜底 1'); return 1; } let wi = battle.session.spawner.waveIndex; if (wi < 0) wi = 0; if (wi >= waves.length) wi = waves.length - 1; const wave = waves[wi]; let portPlan: (typeof waves)[number]['ports'][number] | null = null; for (let i = 0; i < (wave.ports?.length ?? 0); i++) { if (wave.ports[i].port === spawnPort) { portPlan = wave.ports[i]; break; } } if (!portPlan?.segments?.length) { portPlan = wave.ports?.[0] ?? null; } const seg = portPlan?.segments?.[0]; if (!seg) { console.log('[BattleGameExtraBossSkill] 波次无出怪段,难度行兜底', wi + 1); return wi + 1; } const fromSeg = Math.max(1, Math.floor(Number(seg.difficultyRow) || 0)); if (fromSeg > 0) return fromSeg; const parsed = parseMonsterUnitDefId(seg.unitDefId); if (parsed?.difficultyRow) return Math.max(1, parsed.difficultyRow); return wi + 1; } }