feat(attr): add vulnerable resist attribute and damage calculation
1. 新增易伤抗性属性vulnerable_res,支持百分比减免易伤附加伤害 2. 实现易伤伤害计算逻辑,支持叠加层数与值覆盖 3. 更新技能与Buff配置,修正灼烧技能描述为易伤效果 4. 新增中毒、减攻Debuff配置与易伤Buff常量定义
This commit is contained in:
@@ -51,11 +51,16 @@ export enum DebuffIcon {
|
|||||||
* 新增 debuff 时:1) BuffList 加配置 2) 此处加一行映射。
|
* 新增 debuff 时:1) BuffList 加配置 2) 此处加一行映射。
|
||||||
*/
|
*/
|
||||||
export const DEBUFF_ICON_MAP: Record<number, DebuffIcon> = {
|
export const DEBUFF_ICON_MAP: Record<number, DebuffIcon> = {
|
||||||
7002: DebuffIcon.FireDamage, // 灼烧
|
7002: DebuffIcon.FireDamage, // 易伤(灼热火球附加)
|
||||||
7003: DebuffIcon.IceDamage, // 冰冻
|
7003: DebuffIcon.IceDamage, // 冰冻
|
||||||
7004: DebuffIcon.Stun, // 击晕
|
7004: DebuffIcon.Stun, // 击晕
|
||||||
|
7005: DebuffIcon.Poison, // 中毒
|
||||||
|
7006: DebuffIcon.AttackDebuff, // 减攻
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 易伤 buff 的 id(HeroAtkSystem 结算时按此 id 汇总易伤值) */
|
||||||
|
export const VULNERABLE_BUFF_ID = 7002;
|
||||||
|
|
||||||
/** Buff 静态定义 */
|
/** Buff 静态定义 */
|
||||||
export interface BuffConfig {
|
export interface BuffConfig {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -80,12 +85,13 @@ export const BuffList: Record<number, BuffConfig> = {
|
|||||||
modifiers: [{ attr: Attrs.ap, op: ModOp.Flat, value: 5 }],
|
modifiers: [{ attr: Attrs.ap, op: ModOp.Flat, value: 5 }],
|
||||||
info: "攻击力 +5,持续 10 秒",
|
info: "攻击力 +5,持续 10 秒",
|
||||||
},
|
},
|
||||||
// 灼烧(DoT,可叠层)
|
// 易伤(灼热火球附加;受到伤害时附加固定值,可被易伤抗性百分比减免)
|
||||||
|
// 注:modifiers.attr 用 hp 仅为占位以通过 aggregateTimedMods 结构校验,实际易伤值由 HeroAtkSystem 按 VULNERABLE_BUFF_ID 直接汇总
|
||||||
7002: {
|
7002: {
|
||||||
id: 7002, name: "灼烧", icon: "Stat_Burn",
|
id: 7002, name: "易伤", icon: "Stat_Burn",
|
||||||
category: BuffCategory.Debuff, duration: 5, max_stack: 5,
|
category: BuffCategory.Debuff, duration: 5, max_stack: 5,
|
||||||
tick: { interval: 0.5, damage_or_heal: -10, scale_by_ap_pct: 30 },
|
modifiers: [{ attr: Attrs.hp, op: ModOp.Flat, value: 10 }],
|
||||||
info: "每 0.5 秒受到 10 伤害,可叠加",
|
info: "受到的伤害附加 10 点易伤,可叠加,持续 5 秒",
|
||||||
},
|
},
|
||||||
// 冰冻(控制,走统一框架,双写兼容)
|
// 冰冻(控制,走统一框架,双写兼容)
|
||||||
7003: {
|
7003: {
|
||||||
@@ -101,6 +107,20 @@ export const BuffList: Record<number, BuffConfig> = {
|
|||||||
is_control: true, control_kind: 'stun',
|
is_control: true, control_kind: 'stun',
|
||||||
info: "击晕目标,无法行动",
|
info: "击晕目标,无法行动",
|
||||||
},
|
},
|
||||||
|
// 中毒(纯伤害 DoT,可叠层)
|
||||||
|
7005: {
|
||||||
|
id: 7005, name: "中毒", icon: "Stat_PoisonChanceIncrease",
|
||||||
|
category: BuffCategory.Debuff, duration: 5, max_stack: 5,
|
||||||
|
tick: { interval: 0.5, damage_or_heal: -10, scale_by_ap_pct: 30 },
|
||||||
|
info: "每 0.5 秒受到 10 点中毒伤害,可叠加,持续 5 秒",
|
||||||
|
},
|
||||||
|
// 减攻(降低目标攻击力)
|
||||||
|
7006: {
|
||||||
|
id: 7006, name: "减攻", icon: "Stat_Attack_01",
|
||||||
|
category: BuffCategory.Debuff, duration: 5, max_stack: 1,
|
||||||
|
modifiers: [{ attr: Attrs.ap, op: ModOp.Flat, value: -10 }],
|
||||||
|
info: "攻击力降低 10 点,持续 5 秒",
|
||||||
|
},
|
||||||
// 占卜师战前攻击强化(基础档:+30/5s;高阶通过 buff_value/buff_duration 覆写成长)
|
// 占卜师战前攻击强化(基础档:+30/5s;高阶通过 buff_value/buff_duration 覆写成长)
|
||||||
7111: {
|
7111: {
|
||||||
id: 7111, name: "战前强攻", icon: "Stat_Attack_03",
|
id: 7111, name: "战前强攻", icon: "Stat_Attack_03",
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export enum Attrs {
|
|||||||
puncture_chance = "puncture_chance", // 穿透概率
|
puncture_chance = "puncture_chance", // 穿透概率
|
||||||
puncture_dmg_bonus = "puncture_dmg_bonus", // 穿透后伤害增量(百分点;最终穿透系数 = PUNCTURE_DMG_RATIO * (1 + bonus/100))
|
puncture_dmg_bonus = "puncture_dmg_bonus", // 穿透后伤害增量(百分点;最终穿透系数 = PUNCTURE_DMG_RATIO * (1 + bonus/100))
|
||||||
wfuny = "wfuny", // 风怒
|
wfuny = "wfuny", // 风怒
|
||||||
|
vulnerable_res = "vulnerable_res", // 易伤抗性(百分比减免易伤附加伤害)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// ========== 从 HeroAttrs.ts 导入属性相关定义 ==========
|
// ========== 从 HeroAttrs.ts 导入属性相关定义 ==========
|
||||||
import { Attrs } from "./HeroAttrs";
|
import { Attrs } from "./HeroAttrs";
|
||||||
|
|
||||||
export enum HSSet {
|
export enum HSSet {
|
||||||
@@ -311,11 +311,11 @@ export const SkillSet: Record<number, SkillConfig> = {
|
|||||||
DTType: DTType.single, ap: 100, hit_count: 2, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
|
DTType: DTType.single, ap: 100, hit_count: 2, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
|
||||||
RType: RType.linear, EType: EType.collision, info: "造成攻击力100%的伤害, 高阶技能",
|
RType: RType.linear, EType: EType.collision, info: "造成攻击力100%的伤害, 高阶技能",
|
||||||
},
|
},
|
||||||
// DoT 技能:命中附加灼烧(7002,BuffList 的 Debuff DoT 底座),tick 伤害受施法者 ap 缩放
|
// DoT 技能:命中附加易伤(7002,受到伤害附加固定值,可被易伤抗性减免)
|
||||||
6104: {
|
6104: {
|
||||||
uuid: 6104, name: "灼热火球", sp_name: "fb-1", icon: "Stat_FireDamage", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "atk",
|
uuid: 6104, name: "灼热火球", sp_name: "fb-1", icon: "Stat_FireDamage", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "atk",
|
||||||
DTType: DTType.single, ap: 80, hit_count: 2, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
|
DTType: DTType.single, ap: 80, hit_count: 2, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
|
||||||
RType: RType.bezier, EType: EType.collision, timed_buff_id: 7002, info: "造成攻击力80%的伤害, 命中附加灼烧(5秒内持续掉血)",
|
RType: RType.bezier, EType: EType.collision, timed_buff_id: 7002, info: "造成攻击力80%的伤害, 命中附加易伤(5秒内受到伤害附加固定值)",
|
||||||
},
|
},
|
||||||
6201: {
|
6201: {
|
||||||
uuid: 6201, name: "陨石术", sp_name: "fb-3", icon: "Stat_Tripleshot", TGroup: TGroup.Enemy, readyAnm: "blues", endAnm: "", act: "max",
|
uuid: 6201, name: "陨石术", sp_name: "fb-3", icon: "Stat_Tripleshot", TGroup: TGroup.Enemy, readyAnm: "blues", endAnm: "", act: "max",
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ import { getMonsterGoldDrop } from "../map/RogueConfig";
|
|||||||
import { MissionEconomy } from "../map/MissionEconomy";
|
import { MissionEconomy } from "../map/MissionEconomy";
|
||||||
import { MoveComp } from "./MoveComp";
|
import { MoveComp } from "./MoveComp";
|
||||||
import { buffManager, BuffApplyOverrides } from "./BuffManager";
|
import { buffManager, BuffApplyOverrides } from "./BuffManager";
|
||||||
import { DEBUFF_ICON_MAP } from "../common/config/BuffSet";
|
import { DEBUFF_ICON_MAP, VULNERABLE_BUFF_ID, BuffList } from "../common/config/BuffSet";
|
||||||
|
import { BuffComp } from "./BuffComp";
|
||||||
|
|
||||||
/** 最终伤害数据接口
|
/** 最终伤害数据接口
|
||||||
* 用于封装一次攻击计算的所有结果数据
|
* 用于封装一次攻击计算的所有结果数据
|
||||||
@@ -153,6 +154,9 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mLogger.log(this.debugMode, 'HeroAtkSystem', " after crit", damage)
|
mLogger.log(this.debugMode, 'HeroAtkSystem', " after crit", damage)
|
||||||
|
// 易伤附加:目标每层易伤 buff 附加固定伤害,被易伤抗性百分比减免;普攻与 DoT 均生效
|
||||||
|
damage += this.calcVulnerableBonus(target, TAttrsComp);
|
||||||
|
mLogger.log(this.debugMode, 'HeroAtkSystem', " after vulnerable", damage)
|
||||||
// 护盾数值减免(1 点护盾吸收 1 点伤害,扣完为止,溢出部分继续扣血)
|
// 护盾数值减免(1 点护盾吸收 1 点伤害,扣完为止,溢出部分继续扣血)
|
||||||
const shieldResult = this.absorbShield(TAttrsComp, damage);
|
const shieldResult = this.absorbShield(TAttrsComp, damage);
|
||||||
damage = shieldResult.remainingDamage;
|
damage = shieldResult.remainingDamage;
|
||||||
@@ -458,6 +462,26 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
|
|||||||
* @param damage 原始伤害值
|
* @param damage 原始伤害值
|
||||||
* @returns {remainingDamage, absorbedDamage} 剩余伤害值和被护盾减免的伤害值
|
* @returns {remainingDamage, absorbedDamage} 剩余伤害值和被护盾减免的伤害值
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* 计算易伤附加伤害:汇总目标每层易伤 buff 的数值(value_override 优先),再被易伤抗性百分比减免。
|
||||||
|
* @returns 附加伤害值(向下取整,非负)
|
||||||
|
*/
|
||||||
|
private calcVulnerableBonus(target: ecs.Entity, TAttrsComp: HeroAttrsComp): number {
|
||||||
|
if (!target.has(BuffComp)) return 0;
|
||||||
|
const layers = target.get(BuffComp).buffs.get(VULNERABLE_BUFF_ID);
|
||||||
|
if (!layers || layers.length === 0) return 0;
|
||||||
|
const cfg = BuffList[VULNERABLE_BUFF_ID];
|
||||||
|
const baseVal = cfg?.modifiers?.[0]?.value ?? 0;
|
||||||
|
let sum = 0;
|
||||||
|
for (const layer of layers) {
|
||||||
|
sum += layer.value_override !== undefined ? layer.value_override : baseVal;
|
||||||
|
}
|
||||||
|
if (sum <= 0) return 0;
|
||||||
|
// 易伤抗性:百分比减免(vulnerable_res=30 即减免 30%)
|
||||||
|
const res = TAttrsComp.getFinalVulnerableRes();
|
||||||
|
return Math.max(0, Math.floor(sum * (1 - res / 100)));
|
||||||
|
}
|
||||||
|
|
||||||
private absorbShield(TAttrsComp: HeroAttrsComp, damage: number): { remainingDamage: number, absorbedDamage: number } {
|
private absorbShield(TAttrsComp: HeroAttrsComp, damage: number): { remainingDamage: number, absorbedDamage: number } {
|
||||||
if (TAttrsComp.shield <= 0) {
|
if (TAttrsComp.shield <= 0) {
|
||||||
mLogger.log(this.debugMode, 'HeroAtkSystem', " 护盾值小于等于0,无法吸收伤害");
|
mLogger.log(this.debugMode, 'HeroAtkSystem', " 护盾值小于等于0,无法吸收伤害");
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ export class HeroAttrsComp extends ecs.Comp {
|
|||||||
puncture_chance: number = 0; // 穿透概率
|
puncture_chance: number = 0; // 穿透概率
|
||||||
puncture_dmg_bonus: number = 0; // 穿透后伤害增量(百分点,乘算加成)
|
puncture_dmg_bonus: number = 0; // 穿透后伤害增量(百分点,乘算加成)
|
||||||
wfuny: number = 0; // 风怒
|
wfuny: number = 0; // 风怒
|
||||||
|
vulnerable_res: number = 0; // 易伤抗性(百分比减免易伤附加伤害)
|
||||||
|
|
||||||
revived_count: number = 0; // 已复活次数
|
revived_count: number = 0; // 已复活次数
|
||||||
invincible_time: number = 0;// 无敌时间
|
invincible_time: number = 0;// 无敌时间
|
||||||
@@ -510,6 +511,12 @@ export class HeroAttrsComp extends ecs.Comp {
|
|||||||
return this.knockback_res + mods.flatSum + mods.pctSum;
|
return this.knockback_res + mods.flatSum + mods.pctSum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 最终易伤抗性 = 基础 + 限时修饰(加法模型),百分比减免易伤附加伤害 */
|
||||||
|
public getFinalVulnerableRes(): number {
|
||||||
|
const mods = this.aggregateTimedMods(Attrs.vulnerable_res);
|
||||||
|
return this.vulnerable_res + mods.flatSum + mods.pctSum;
|
||||||
|
}
|
||||||
|
|
||||||
/** 根据攻速加成换算实际攻击间隔,避免直接改写配置里的基础 CD。 */
|
/** 根据攻速加成换算实际攻击间隔,避免直接改写配置里的基础 CD。 */
|
||||||
public getEffectiveSkillCd(skillId: number): number {
|
public getEffectiveSkillCd(skillId: number): number {
|
||||||
const skill = this.skills[skillId];
|
const skill = this.skills[skillId];
|
||||||
@@ -605,6 +612,7 @@ export class HeroAttrsComp extends ecs.Comp {
|
|||||||
this.puncture_chance = 0;
|
this.puncture_chance = 0;
|
||||||
this.puncture_dmg_bonus = 0;
|
this.puncture_dmg_bonus = 0;
|
||||||
this.wfuny = 0;
|
this.wfuny = 0;
|
||||||
|
this.vulnerable_res = 0;
|
||||||
this.boom = false;
|
this.boom = false;
|
||||||
|
|
||||||
// 重置技能距离缓存
|
// 重置技能距离缓存
|
||||||
|
|||||||
Reference in New Issue
Block a user