import { oops } from "db://oops-framework/core/Oops"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { HeroViewComp } from "../hero/HeroViewComp"; import { DamageRequest, DamageResult } from "./DamageComp"; @ecs.register('DamageSystem') export class DamageSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate { private _timers: { [key: string]: number } = {}; filter(): ecs.IMatcher { return ecs.allOf(DamageRequest); } update(e: ecs.Entity) { const req = e.get(DamageRequest); const result = this.calculateDamage(req); this.applyDamage(req.target, result); e.remove(DamageRequest); } private calculateDamage(req: DamageRequest): DamageResult { const targetView = req.target.get(HeroViewComp); const sourceView = req.source.get(HeroViewComp); let final = req.baseValue; // 伤害浮动(±10%) const damageFloat = 0.9 + Math.random() * 0.2; // 0.9~1.1 final *= damageFloat; final = Math.round(final); // 闪避判定 if (Math.random()*100 < targetView.dodge) { const result = new DamageResult(); result.isDodged = true; return result; } // 护甲减伤 if (!req.ignoreDefense) { const effectiveArmor = Math.min(targetView.def, 300); // 最大减伤75% const damageReduction = effectiveArmor / (effectiveArmor + 100); final *= (1 - damageReduction); final = Math.round(final); // 四舍五入取整 } // 暴击判定 let isCrit = false; if (req.canCrit) { const critRate = sourceView.crit; if (Math.random() * 100 < critRate) { final *= 1.5; isCrit = true; } } const result = new DamageResult(); result.value = Math.max(1, final); // 确保最小伤害为1 result.isCrit = isCrit; result.position = req.target.get(HeroViewComp).node.position; result.delay = req.delay; return result; } private applyDamage(target: ecs.Entity, result: DamageResult) { const view = target.get(HeroViewComp); if (!view.ent.has(HeroViewComp)) return; this.scheduleOnce(()=>{ // 护盾优先吸收伤害 let remainingDamage = result.value; if(result.isDodged){ view.BUFFCOMP.tooltip(5,"*闪避*"); return; } if (view.shield > 0) { const shieldAbsorb = Math.min(view.shield, remainingDamage); view.shield -= shieldAbsorb; remainingDamage -= shieldAbsorb; if (view.shield <= 0) { view.BUFFCOMP.show_shield(false); } } // 剩余伤害扣除血量 if (remainingDamage > 0) { view.hp -= remainingDamage; view.showDamage(result.value, result.isCrit); }else{ view.BUFFCOMP.tooltip(5,"*吸收*"); } }, result.delay) // 直接触发事件 oops.message.dispatchEvent("OnDamage", { target, damage: result.value, isCrit: result.isCrit }); } private scheduleOnce(callback: () => void, delay: number) { const timer = setTimeout(() => { callback(); delete this._timers[timer]; }, delay * 1000); this._timers[timer] = timer; } onDestroy() { Object.values(this._timers).forEach(clearTimeout); } }