/* * @Author: dgflash * @Date: 2021-11-18 15:56:01 * @LastEditors: dgflash * @LastEditTime: 2022-08-17 13:43:25 */ import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { Attrs, AttrsType, BType, NeAttrs } from "../common/config/HeroAttrs"; import { BuffConf } from "../common/config/SkillSet"; import { HeroInfo, AttrSet } from "../common/config/heroSet"; /** * 怪物属性数据模型 - 存储纯数据,不含表现逻辑 * 简化版本:只保留临时buff系统,移除持久型buff * * 注意:HeroModelComp 中有详细的 ECS 架构分析,迁移方案见那个文件 */ @ecs.register('MonModel') export class MonModelComp extends ecs.Comp { // ==================== 角色基础信息 ==================== hero_uuid: number = 1001; hero_name: string = "monster"; lv: number = 1; type: number = 0; // 0近战 1远程 2辅助 fac: number = 1; // 0:hero 1:monster(默认为怪物) // ==================== 动态属性值 ==================== hp: number = 100; // 当前血量 mp: number = 100; // 当前魔法值 shield: number = 0; // 当前护盾 Attrs: any = []; // 最终属性数组(经过Buff计算后) NeAttrs: any = []; // 负面状态数组 // ==================== Buff/Debuff 系统 ==================== /** 临时型buff数组 - 按时间自动过期(怪物只使用临时buff) */ BUFFS_TEMP: Record> = {}; // ==================== 标记状态 ==================== is_dead: boolean = false; is_count_dead: boolean = false; is_boss: boolean = false; is_big_boss: boolean = false; is_master: boolean = false; is_friend: boolean = false; is_kalami: boolean = false; // ==================== 计数统计 ==================== atk_count: number = 0; // 攻击次数 atked_count: number = 0; // 被攻击次数 // ==================== 技能配置 ==================== skills: any = []; addBuff(buffConf: BuffConf) { // 怪物只使用临时buff const attrIndex = buffConf.buff; if (!this.BUFFS_TEMP[attrIndex]) this.BUFFS_TEMP[attrIndex] = []; this.BUFFS_TEMP[attrIndex].push({ value: buffConf.value, BType: buffConf.BType, remainTime: buffConf.time }); this.recalculateSingleAttr(attrIndex); } recalculateSingleAttr(attrIndex: number) { const baseValues: Record = { [Attrs.HP_MAX]: this.base_hp, [Attrs.MP_MAX]: this.base_mp, [Attrs.DEF]: this.base_def, [Attrs.AP]: this.base_ap, [Attrs.MAP]: this.base_map, [Attrs.SPEED]: this.base_speed, [Attrs.SHIELD_MAX]: 0 }; const baseVal = baseValues[attrIndex] !== undefined ? baseValues[attrIndex] : 0; let totalValue = baseVal, totalRatio = 0; // 怪物只计算临时buff if (this.BUFFS_TEMP[attrIndex]) { for (const buff of this.BUFFS_TEMP[attrIndex]) { if (buff.BType === BType.VALUE) totalValue += buff.value; else totalRatio += buff.value; } } const attrType = AttrsType[attrIndex]; this.Attrs[attrIndex] = attrType === BType.RATIO ? totalValue + totalRatio : Math.floor(totalValue * (1 + totalRatio / 100)); this.clampSingleAttr(attrIndex); } private clampSingleAttr(attrIndex: number) { switch(attrIndex) { case Attrs.HP_MAX: case Attrs.MP_MAX: case Attrs.DEF: case Attrs.AP: case Attrs.MAP: this.Attrs[attrIndex] = Math.max(1, this.Attrs[attrIndex]); break; case Attrs.CRITICAL: case Attrs.DODGE: case Attrs.HIT: this.Attrs[attrIndex] = Math.max(0, Math.min(AttrSet.ATTR_MAX, this.Attrs[attrIndex])); break; } } updateTemporaryBuffsDebuffs(dt: number) { const affectedAttrs = new Set(); for (const attrIndex in this.BUFFS_TEMP) { const buffs = this.BUFFS_TEMP[attrIndex]; buffs.forEach(buff => { buff.remainTime -= dt; if (buff.remainTime <= 0) buffs.splice(buffs.indexOf(buff), 1); }); if (buffs.length === 0) { delete this.BUFFS_TEMP[attrIndex]; affectedAttrs.add(parseInt(attrIndex)); } } for (const key in this.NeAttrs) { this.NeAttrs[key].remainTime -= dt; if (this.NeAttrs[key].remainTime <= 0) this.NeAttrs[key].remainTime = 0; } affectedAttrs.forEach(attrIndex => this.recalculateSingleAttr(attrIndex)); } clearBuffs(attrIndex?: number, isBuff: boolean = true): void { if (attrIndex === undefined) { for (const idx in this.BUFFS_TEMP) this.clearBuffsForAttr(parseInt(idx), isBuff); } else { this.clearBuffsForAttr(attrIndex, isBuff); } } private clearBuffsForAttr(attrIndex: number, isBuff: boolean): void { if (!this.BUFFS_TEMP[attrIndex]) return; this.BUFFS_TEMP[attrIndex] = this.BUFFS_TEMP[attrIndex].filter(buff => { const shouldClear = isBuff ? buff.value > 0 : buff.value < 0; return !shouldClear; }); if (this.BUFFS_TEMP[attrIndex].length === 0) delete this.BUFFS_TEMP[attrIndex]; this.recalculateSingleAttr(attrIndex); } clearNeAttr(neAttrIndex: number): void { if (this.NeAttrs[neAttrIndex]) { this.NeAttrs[neAttrIndex].value = 0; this.NeAttrs[neAttrIndex].time = 0; } } clearAllNeAttrs(): void { for (const key in this.NeAttrs) { this.NeAttrs[key].value = 0; this.NeAttrs[key].time = 0; } } public isStun(): boolean { return this.NeAttrs[NeAttrs.IN_STUN]?.time > 0; } public isFrost(): boolean { return this.NeAttrs[NeAttrs.IN_FROST]?.time > 0; } reset() { this.hero_uuid = 1001; this.hero_name = "monster"; this.lv = 1; this.type = 0; this.fac = 1; this.hp = 100; this.mp = 100; this.shield = 0; this.Attrs = []; this.NeAttrs = []; this.BUFFS_TEMP = {}; // 只重置临时buff this.is_dead = false; this.is_count_dead = false; this.is_boss = false; this.is_big_boss = false; this.is_master = false; this.is_friend = false; this.is_kalami = false; this.atk_count = 0; this.atked_count = 0; this.skills = []; } } /** * ==================== 怪物属性更新系统 ==================== * * 与 HeroAttrSystem 类似,但针对怪物 * 可以复用相同逻辑,也可以定制不同规则 */ export class MonAttrSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate { filter(): ecs.IMatcher { return ecs.allOf(MonModelComp); } update(e: ecs.Entity): void { const model = e.get(MonModelComp); if (!model || model.is_dead) return; // 怪物的属性更新逻辑(可以与英雄不同) model.updateTemporaryBuffsDebuffs(this.dt); // 怪物可能没有自然回复,或者回复速度不同 // model.mp += MonUpSet.MP * this.dt; // model.hp += MonUpSet.HP * this.dt; } }