import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { Attrs } from "../common/config/HeroAttrs"; import { HeroInfo } from "../common/config/heroSet"; import { SkillSet } from "../common/config/SkillSet"; import { HeroAttrsComp } from "./HeroAttrsComp"; /** * ==================== 技能槽位数据 ==================== * 单个技能的运行时数据 */ export interface SkillSlot { s_uuid: number; // 技能配置ID cd: number; // 当前CD时间(递减) cd_max: number; // 最大CD时间 cost: number; // MP消耗 level: number; // 技能等级(预留) } /** * ==================== 英雄技能数据组件 ==================== * * 职责: * 1. 存储角色拥有的技能列表 * 2. 管理技能CD状态 * 3. 提供技能查询接口 * * 设计理念: * - 只存数据,不含施法逻辑 * - CD 更新由 HSkillSystem 负责 * - 施法判定由 HSkillSystem 负责 */ @ecs.register('HeroSkills') export class HeroSkillsComp extends ecs.Comp { // ==================== 技能槽位列表 ==================== /** 技能槽位数组(最多4个技能) */ skills: Record = {}; // ==================== 辅助方法 ==================== /** * 初始化技能列表 * @param sUuids 技能配置ID数组 */ initSkills(sUuids: number[], uuid: number) { this.skills = []; for (let i = 0; i < sUuids.length; i++) { const s_uuid = sUuids[i]; const config = SkillSet[s_uuid]; if (!config) { console.warn(`[HeroSkills] 技能配置不存在: ${s_uuid}`); continue; } // 第0个技能的 cd_max 取 herosinfo[uuid].as const cdMax = i === 0 ? HeroInfo[uuid].as : config.cd; this.skills[s_uuid] = { s_uuid: config.uuid, cd: 0, cd_max: cdMax, cost: config.cost, level: 1, }; } } /** * 添加单个技能 */ addSkill(s_uuid: number) { const config = SkillSet[s_uuid]; if (!config) { console.warn(`[HeroSkills] 技能配置不存在: ${s_uuid}`); return; } this.skills[s_uuid] = { s_uuid: config.uuid, cd: 0, cd_max: config.cd, cost: config.cost, level: 1 }; } /** * 获取指定s_uuid的技能 */ getSkill(s_uuid: number): SkillSlot | null { return this.skills[s_uuid] ?? null; } /** * 检查技能是否可施放(通过s_uuid) * @param s_uuid 技能配置ID * @param currentMp 当前MP值 */ canCast(s_uuid: number, currentMp: number): boolean { const skill = this.getSkill(s_uuid); if (!skill) return false; // 检查CD和MP return skill.cd <= 0 && currentMp >= skill.cost; } /** * 重置技能CD(开始冷却,通过索引) */ resetCD(s_uuid: number) { let attrsCom = this.ent.get(HeroAttrsComp); if (!attrsCom) return; const skill = this.getSkill(s_uuid); if (!skill) return; // 普通攻击(skills[0])受 AS 影响,其余技能受 SS 影响 const isNormalAttack = s_uuid === this.skills[0]?.s_uuid; const speedAttr = isNormalAttack ? Attrs.AS : Attrs.SS; const speedBonus = attrsCom.Attrs[speedAttr] / 100; // 100 表示 100% 提速 const speedMultiplier = 1 / (1 + speedBonus); // 提速 100% => cd 减半 skill.cd = skill.cd_max * speedMultiplier; if (skill) { skill.cd = skill.cd_max; } } /** * 更新所有技能CD(每帧调用) * @param dt 时间增量 */ updateCDs(dt: number) { for (const s_uuid in this.skills) { const skill = this.skills[Number(s_uuid)]; if (skill.cd > 0) { skill.cd -= dt; if (skill.cd < 0) { skill.cd = 0; } } } } /** * 获取所有可施放的技能索引 */ getReadySkills(currentMp: number): number[] { const ready: number[] = []; for (const s_uuid in this.skills) { if (this.canCast(Number(s_uuid), currentMp)) { ready.push(Number(s_uuid)); } } return ready; } reset() { this.skills = {}; } }