import type { EntityId } from 'db://assets/mx/module/ecs'; import { TableNames } from '../../game/ConfigTableData'; import { getTowerLoadoutService } from '../combat/TowerLoadoutService'; import { getMonsterStatusText } from '../view/MonsterStatusText'; import { SkillPresentationEnv } from './SkillPresentationEnv'; /** 大招名飘字后、实际释放大招的通用延迟(秒) */ export const ULT_SKILL_RELEASE_DELAY_SEC = 0.5; /** 技能名飘字字号 */ const SKILL_NAME_FONT_SIZE = 28; /** * 神将主动技能名飘字:读 Skill 表 name,在组合中心用 battleText 播放。 */ export class SkillNameFloater { /** * 播放技能名飘字。 * @param caster 施法实体 * @param abilityId 可选;用于解析 Skill 表 id */ static play(caster: EntityId, abilityId?: string): void { const skillName = SkillNameFloater.resolveDisplayName(caster, abilityId); if (!skillName) return; const worldCenter = SkillPresentationEnv.getCompositionWorldCenter(caster); if (!worldCenter) { console.log('[SkillNameFloater] 无组合中心', caster); return; } getMonsterStatusText().playAtWorld(worldCenter, skillName, SKILL_NAME_FONT_SIZE); } /** * 从 Skill 表解析展示名(lang)。 * @param caster 施法实体 * @param abilityId 主动技能 Ability id */ private static resolveDisplayName(caster: EntityId, abilityId?: string): string | null { let skillId = SkillNameFloater.parseSkillId(abilityId); if (!(skillId > 0)) { skillId = getTowerLoadoutService().getLoadout(caster)?.activeSkillBaseAtkId ?? 0; } if (!(skillId > 0)) { console.log('[SkillNameFloater] 无主动技能 id', caster, abilityId); return null; } const row = gg.data.table.getTableData(TableNames.Skill, skillId); if (!row) { console.log('[SkillNameFloater] Skill 缺失', skillId); return null; } const name = String(gg.lang.get(row.name) ?? '').trim(); if (!name) { console.log('[SkillNameFloater] Skill.name 为空', skillId); return null; } return name; } /** * 从 ability_hero_/ability_ult_/ability_weapon_ id 解析 Skill 表 id。 * @param abilityId Ability id */ private static parseSkillId(abilityId?: string): number { if (!abilityId) return 0; const m = /^ability_(?:ult|hero|weapon)_(\d+)(?:_e\d+)?$/.exec(abilityId); return m ? Number(m[1]) : 0; } }