Files
pixelheros/assets/script/game/hero/BuffManager.ts
pan 5585149b12 feat: 新增麻痹控制机制,优化击晕与技能CD逻辑
1.  新增麻痹控制相关属性、buff配置与逻辑实现
2.  调整击晕时长与CD削减机制,优化技能CD更新逻辑
3.  修正多个技能预制件的参数与动画配置
4.  扩展控制类型检测与游戏配置项
2026-08-19 16:40:10 +08:00

139 lines
5.1 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.
/**
* BuffManager — buff/debuff 的应用、驱散、查询管理器。
*
* 设计说明:
* - 非 ECS 组件,是普通 class 单例(参考 smc 的单例暴露模式)。
* - 对外提供 applyBuff / dispel / getStack / hasControl 四组核心能力。
* - 控制类 buff冰冻/眩晕)统一写入 BuffComp由 BuffSystem 计时到期;
* 旧字段 frost_end_time/stun_end_time 已随 HeroBuffSystem 一并下线。
*/
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { BuffCategory, BuffList } from "../common/config/BuffSet";
import { BuffComp, ActiveBuff } from "./BuffComp";
import { mLogger } from "../common/Logger";
/** Buff 模块调试日志开关 */
const DEBUG = false;
/** applyBuff 的覆盖参数(预留按需覆写持续时间 / 修饰数值) */
export interface BuffApplyOverrides {
duration?: number;
/** 覆写计时 buff 的修饰数值modifiers.value / tick.damage_or_heal由药水卡 buff_value 自定义档位 */
value?: number;
/** 施法者完整属性快照DoT tick 判定暴击/冰冻/击晕用),结构同 DamageEvent.Attrs */
source_attrs?: any;
}
class BuffManagerImpl {
/**
* 对目标施加一个 buff 实例。
*
* 叠层规则:
* - max_stack === 0无限叠加始终 push 新层
* - existing.length < max_stackpush 新层
* - 已满:移除最老层(数组首部)后追加新层,保持 FIFO 刷新语义
*
* @param target 目标实体
* @param buffId BuffList 配置 id
* @param sourceUuid 施法者 uuid0=系统/无主)
* @param sourceAp 施法者攻击力快照(用于 DoT 缩放)
* @param overrides 可选覆写参数
*/
applyBuff(target: ecs.Entity, buffId: number, sourceUuid: number = 0, sourceAp: number = 0, overrides?: BuffApplyOverrides): void {
const cfg = BuffList[buffId];
if (!cfg) {
mLogger.warn(true, "BuffManager", `applyBuff: buffId=${buffId} 配置不存在,跳过`);
return;
}
mLogger.log(DEBUG, "BuffManager", `applyBuff: buff=${cfg.name}(${buffId}) target_eid=${target.eid} duration=${overrides?.duration ?? cfg.duration} value_override=${overrides?.value} source_ap=${sourceAp}`);
const buffComp = this.ensureBuffComp(target);
const duration = overrides?.duration ?? cfg.duration;
let layers = buffComp.buffs.get(buffId);
if (!layers) {
layers = [];
buffComp.buffs.set(buffId, layers);
}
const newLayer = new ActiveBuff(buffId, duration, sourceUuid, sourceAp, overrides?.value, overrides?.source_attrs);
if (cfg.max_stack === 0 || layers.length < cfg.max_stack) {
layers.push(newLayer);
} else {
layers.shift();
layers.push(newLayer);
}
buffComp.dirty_buffs = true;
}
/**
* 驱散目标身上匹配的 buff。
*
* @param target 目标实体
* @param category 仅驱散该类别(不传=所有类别)
* @param excludeIds 排除的 buff id 列表
* @returns 移除的 buff 种类数
*/
dispel(target: ecs.Entity, category?: BuffCategory, excludeIds?: number[]): number {
if (!target.has(BuffComp)) return 0;
const buffComp = target.get(BuffComp);
let removedKinds = 0;
buffComp.buffs.forEach((layers, buffId) => {
const cfg = BuffList[buffId];
if (!cfg) return;
if (excludeIds && excludeIds.includes(buffId)) return;
if (category !== undefined && cfg.category !== category) return;
if (layers.length > 0) removedKinds++;
buffComp.buffs.delete(buffId);
});
buffComp.dirty_buffs = true;
return removedKinds;
}
/**
* 获取目标身上指定 buff 的当前叠层数。
* @returns 层数(未命中返回 0
*/
getStack(target: ecs.Entity, buffId: number): number {
if (!target.has(BuffComp)) return 0;
const buffComp = target.get(BuffComp);
return buffComp.buffs.get(buffId)?.length ?? 0;
}
/**
* 判断目标是否处于指定类型的控制状态下。
* 唯一判定来源BuffComp 中是否存在对应 control_kind 的活跃控制 buff。
*/
hasControl(target: ecs.Entity, kind: 'frost' | 'stun' | 'paralyze'): boolean {
if (!target.has(BuffComp)) return false;
const buffComp = target.get(BuffComp);
for (const [buffId, layers] of buffComp.buffs) {
if (layers.length === 0) continue;
const cfg = BuffList[buffId];
if (cfg?.is_control && cfg.control_kind === kind) return true;
}
return false;
}
// ==================== 私有方法 ====================
/**
* 确保目标实体拥有 BuffComp没有则添加。
*/
private ensureBuffComp(target: ecs.Entity): BuffComp {
if (!target.has(BuffComp)) {
target.add(BuffComp);
}
return target.get(BuffComp);
}
}
/** Buff 管理器单例(全局唯一实例) */
export const buffManager = new BuffManagerImpl();