204 lines
7.3 KiB
TypeScript
204 lines
7.3 KiB
TypeScript
/*
|
||
* @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
|
||
*
|
||
* 注意:HeroAttrsComp 中有详细的 ECS 架构分析,迁移方案见那个文件
|
||
*/
|
||
@ecs.register('MonAttrsComp')
|
||
export class MonAttrsComp 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<number, Array<{value: number, BType: BType, remainTime: number}>> = {};
|
||
|
||
// ==================== 标记状态 ====================
|
||
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<number, number> = {
|
||
[Attrs.HP_MAX]: this.hp, [Attrs.MP_MAX]: this.mp, [Attrs.DEF]: this.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<number>();
|
||
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(MonAttrsComp);
|
||
}
|
||
|
||
update(e: ecs.Entity): void {
|
||
const model = e.get(MonAttrsComp);
|
||
if (!model || model.is_dead) return;
|
||
|
||
// 怪物的属性更新逻辑(可以与英雄不同)
|
||
model.updateTemporaryBuffsDebuffs(this.dt);
|
||
|
||
// 怪物可能没有自然回复,或者回复速度不同
|
||
// model.mp += MonUpSet.MP * this.dt;
|
||
// model.hp += MonUpSet.HP * this.dt;
|
||
}
|
||
} |