完成全量buff系统迁移,删除HeroBuffSystem和旧的计时字段, 所有冰冻/眩晕控制效果改为通过BuffManager管理, 简化了控制状态判定逻辑,移除了新旧系统兼容代码
127 lines
4.4 KiB
TypeScript
127 lines
4.4 KiB
TypeScript
/**
|
||
* 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_stack:push 新层
|
||
* - 已满:移除最老层(数组首部)后追加新层,保持 FIFO 刷新语义
|
||
*
|
||
* @param target 目标实体
|
||
* @param buffId BuffList 配置 id
|
||
* @param sourceUuid 施法者 uuid(0=系统/无主)
|
||
* @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();
|