Files
pixelheros/assets/script/game/hero/BuffManager.ts
panFD 2876108970 refactor(hero): 移除旧版控制buff计时系统,统一用buff管理
完成全量buff系统迁移,删除HeroBuffSystem和旧的计时字段,
所有冰冻/眩晕控制效果改为通过BuffManager管理,
简化了控制状态判定逻辑,移除了新旧系统兼容代码
2026-07-23 21:07:38 +08:00

127 lines
4.4 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";
/** applyBuff 的覆盖参数(预留按需覆写持续时间) */
export interface BuffApplyOverrides {
duration?: number;
}
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) return;
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);
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'): 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();