feat(英雄属性): 新增暴击伤害属性并支持驻场技能加成

- 在 HeroAttrs 枚举中添加 critical_damage 属性
- 修改 HeroAtkSystem 的暴击伤害计算逻辑,支持基础暴伤和英雄额外暴伤叠加
- 在 Skill 类中设置技能属性时,使用 HeroAttrsComp 的运行时属性获取方法
- 为 FieldSkillSet 添加 HeroFrost、HeroCrit、HeroCritDamage 和 HeroSpeed 驻场技能配置
- 在 HeroAttrsComp 中新增 crit_damage 字段和相关运行时属性计算方法
- 实现驻场技能百分比值统一换算逻辑,支持 0.2 和 20 两种配置写法
- 添加攻速加成机制,通过缩短技能 CD 实现攻击速度提升
This commit is contained in:
walkpan
2026-05-02 23:50:23 +08:00
parent 7a0b3ee74d
commit 2eaf85c6f5
5 changed files with 71 additions and 14 deletions

View File

@@ -23,6 +23,7 @@ export enum Attrs {
// ==================== 暴击与命中属性 ==================== // ==================== 暴击与命中属性 ====================
critical = "critical", // 暴击率 critical = "critical", // 暴击率
critical_damage = "critical_damage", // 暴击伤害
// ==================== 特殊效果属性 ==================== // ==================== 特殊效果属性 ====================
freeze_chance = "freeze_chance", // 冰冻概率 freeze_chance = "freeze_chance", // 冰冻概率

View File

@@ -325,7 +325,7 @@ export const SkillSet: Record<number, SkillConfig> = {
} }
}; };
//***************驻场技能配置***************
export enum FieldSkillType { export enum FieldSkillType {
SummonCount = 1, // 召唤触发技能次数提升 SummonCount = 1, // 召唤触发技能次数提升
DeadCount = 2, // 死亡触发技能次数提升 DeadCount = 2, // 死亡触发技能次数提升
@@ -338,7 +338,7 @@ export enum FieldSkillType {
HeroFrost = 9, // 英雄冰冻加成 HeroFrost = 9, // 英雄冰冻加成
HeroCrit = 10, // 英雄暴击加成 HeroCrit = 10, // 英雄暴击加成
HeroCritDamage = 11, // 英雄暴击伤害加成 HeroCritDamage = 11, // 英雄暴击伤害加成
HeroSpeed = 12, // 英雄移动速度加成 HeroSpeed = 12, // 英雄攻击速度加成
} }
export interface FieldSkillConfig { export interface FieldSkillConfig {
@@ -358,5 +358,8 @@ export const FieldSkillSet: Record<number, FieldSkillConfig> = {
7006: { uuid: 7006, name: t("fskill_name_7006"), type: FieldSkillType.SellGold, value: 5, info: t("fskill_info_7006", 5) }, 7006: { uuid: 7006, name: t("fskill_name_7006"), type: FieldSkillType.SellGold, value: 5, info: t("fskill_info_7006", 5) },
7007: { uuid: 7007, name: t("fskill_name_7007"), type: FieldSkillType.WaveHeal, value: 0.3, info: t("fskill_info_7007", 30) }, 7007: { uuid: 7007, name: t("fskill_name_7007"), type: FieldSkillType.WaveHeal, value: 0.3, info: t("fskill_info_7007", 30) },
7008: { uuid: 7008, name: t("fskill_name_7008"), type: FieldSkillType.HeroAtk, value: 0.2, info: t("fskill_info_7008", 20) }, 7008: { uuid: 7008, name: t("fskill_name_7008"), type: FieldSkillType.HeroAtk, value: 0.2, info: t("fskill_info_7008", 20) },
7009: { uuid: 7009, name: t("fskill_name_7009"), type: FieldSkillType.HeroFrost, value: 0.1, info: t("fskill_info_7009", 10) },
7010: { uuid: 7010, name: t("fskill_name_7010"), type: FieldSkillType.HeroCrit, value: 0.1, info: t("fskill_info_7010", 10) },
7011: { uuid: 7011, name: t("fskill_name_7011"), type: FieldSkillType.HeroCritDamage, value: 0.5, info: t("fskill_info_7011", 50) },
7012: { uuid: 7012, name: t("fskill_name_7012"), type: FieldSkillType.HeroSpeed, value: 0.2, info: t("fskill_info_7012", 20) },
}; };

View File

@@ -142,7 +142,8 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
mLogger.log(this.debugMode, 'HeroAtkSystem', " dmgCount",damage) mLogger.log(this.debugMode, 'HeroAtkSystem', " dmgCount",damage)
if (isCrit) { if (isCrit) {
damage = Math.floor(damage * (1 + FightSet.CRIT_DAMAGE / 100)); const critDamageBonus = damageEvent.Attrs[Attrs.critical_damage] || 0;
damage = Math.floor(damage * (1 + (FightSet.CRIT_DAMAGE + critDamageBonus) / 100));
reDate.isCrit=true; reDate.isCrit=true;
if (damageEvent.Attrs.fac === FacSet.HERO) { if (damageEvent.Attrs.fac === FacSet.HERO) {
// 【评分系统 - 输出分】统计暴击次数与暴击造成的总伤害 // 【评分系统 - 输出分】统计暴击次数与暴击造成的总伤害

View File

@@ -9,6 +9,8 @@ import { TalentConfig, TalentType } from "../common/config/TalentSet";
@ecs.register('HeroAttrs') @ecs.register('HeroAttrs')
export class HeroAttrsComp extends ecs.Comp { export class HeroAttrsComp extends ecs.Comp {
public debugMode: boolean = false; public debugMode: boolean = false;
private static readonly percentRateThreshold = 1;
private static readonly minAttackCd = 0.05;
Ebus:any=null! Ebus:any=null!
// ==================== 角色基础信息 ==================== // ==================== 角色基础信息 ====================
@@ -41,6 +43,7 @@ export class HeroAttrsComp extends ecs.Comp {
// ==================== 特殊属性 ==================== // ==================== 特殊属性 ====================
critical: number = 0; // 暴击率 critical: number = 0; // 暴击率
freeze_chance: number = 0; // 冰冻概率 freeze_chance: number = 0; // 冰冻概率
crit_damage: number = 0; // 额外暴击伤害
puncture: number = 0; // 穿刺次数 puncture: number = 0; // 穿刺次数
wfuny: number = 0; // 风怒 wfuny: number = 0; // 风怒
@@ -137,15 +140,16 @@ export class HeroAttrsComp extends ecs.Comp {
for (const key in this.skills) { for (const key in this.skills) {
const skill = this.skills[key]; const skill = this.skills[key];
if (!skill) continue; if (!skill) continue;
if (skill.cd <= 0) { const actualCd = this.getEffectiveSkillCd(skill.uuid);
if (actualCd <= 0) {
skill.ccd = 0; skill.ccd = 0;
continue; continue;
} }
if (skill.ccd >= skill.cd) { if (skill.ccd >= actualCd) {
skill.ccd = skill.cd; skill.ccd = actualCd;
continue; continue;
} }
skill.ccd = Math.min(skill.cd, skill.ccd + dt); skill.ccd = Math.min(actualCd, skill.ccd + dt);
} }
} }
isFrost(): boolean { isFrost(): boolean {
@@ -164,8 +168,9 @@ export class HeroAttrsComp extends ecs.Comp {
if (!skillId) return false; if (!skillId) return false;
const skill = this.skills[skillId]; const skill = this.skills[skillId];
if (!skill) return false; if (!skill) return false;
if (skill.cd <= 0) return true; const actualCd = this.getEffectiveSkillCd(skillId);
return skill.ccd >= skill.cd; if (actualCd <= 0) return true;
return skill.ccd >= actualCd;
} }
triggerSkillCD(skillId: number) { triggerSkillCD(skillId: number) {
@@ -178,8 +183,9 @@ export class HeroAttrsComp extends ecs.Comp {
getSkillCdProgress(skillId: number): number { getSkillCdProgress(skillId: number): number {
if (!skillId) return 1; if (!skillId) return 1;
const skill = this.skills[skillId]; const skill = this.skills[skillId];
if (!skill || skill.cd <= 0) return 1; const actualCd = this.getEffectiveSkillCd(skillId);
return Math.max(0, Math.min(1, skill.ccd / skill.cd)); if (!skill || actualCd <= 0) return 1;
return Math.max(0, Math.min(1, skill.ccd / actualCd));
} }
getDisplaySkillCdProgress(): number { getDisplaySkillCdProgress(): number {
@@ -188,6 +194,50 @@ export class HeroAttrsComp extends ecs.Comp {
return this.getSkillCdProgress(displaySkillId); return this.getSkillCdProgress(displaySkillId);
} }
/** 将驻场配置值统一换算成百分比数值,兼容 0.2 和 20 两种写法。 */
private getFieldPercentValue(type: FieldSkillType): number {
const rawValue = HeroAttrsComp.getFieldSkillTotalValue(type);
if (Math.abs(rawValue) <= HeroAttrsComp.percentRateThreshold) {
return rawValue * 100;
}
return rawValue;
}
/** 英雄实时暴击率 = 基础暴击率 + 驻场暴击率。 */
public getRuntimeCritical(): number {
if (this.fac !== FacSet.HERO) return this.critical;
return this.critical + this.getFieldPercentValue(FieldSkillType.HeroCrit);
}
/** 英雄实时冰冻率 = 基础冰冻率 + 驻场冰冻率。 */
public getRuntimeFreezeChance(): number {
if (this.fac !== FacSet.HERO) return this.freeze_chance;
return this.freeze_chance + this.getFieldPercentValue(FieldSkillType.HeroFrost);
}
/** 英雄实时暴击伤害 = 基础额外暴伤 + 驻场暴伤。 */
public getRuntimeCritDamageBonus(): number {
if (this.fac !== FacSet.HERO) return this.crit_damage;
return this.crit_damage + this.getFieldPercentValue(FieldSkillType.HeroCritDamage);
}
/** 攻速加成通过缩短普通攻击技能 CD 生效,正值越高,攻击越快。 */
public getRuntimeAttackSpeedBonus(): number {
if (this.fac !== FacSet.HERO) return 0;
return this.getFieldPercentValue(FieldSkillType.HeroSpeed);
}
/** 根据攻速加成换算实际攻击间隔,避免直接改写配置里的基础 CD。 */
public getEffectiveSkillCd(skillId: number): number {
const skill = this.skills[skillId];
if (!skill) return 0;
if (skill.cd <= 0) return 0;
const speedBonus = this.getRuntimeAttackSpeedBonus();
if (speedBonus <= 0) return skill.cd;
const speedRate = 1 + speedBonus / 100;
return Math.max(HeroAttrsComp.minAttackCd, skill.cd / speedRate);
}
// ==================== 技能距离缓存管理 ==================== // ==================== 技能距离缓存管理 ====================
@@ -245,6 +295,7 @@ export class HeroAttrsComp extends ecs.Comp {
this.revive = undefined; this.revive = undefined;
this.critical = 0; this.critical = 0;
this.freeze_chance = 0; this.freeze_chance = 0;
this.crit_damage = 0;
this.revived_count = 0; this.revived_count = 0;
this.invincible_time = 0; this.invincible_time = 0;
this.puncture = 0; this.puncture = 0;

View File

@@ -213,8 +213,9 @@ export class Skill extends ecs.Entity {
const sAp =config.ap+(SUp.ap*skill_lv); const sAp =config.ap+(SUp.ap*skill_lv);
const sHit=config.hit_count+(SUp.hit_count*skill_lv) + cAttrsComp.puncture const sHit=config.hit_count+(SUp.hit_count*skill_lv) + cAttrsComp.puncture
sDataCom.Attrs[Attrs.ap] = Math.floor(cAttrsComp.ap*sAp/100); //技能的ap是百分值 需要/100 而且需要再最终计算总ap时再/100不然会出现ap为90%变0 sDataCom.Attrs[Attrs.ap] = Math.floor(cAttrsComp.ap*sAp/100); //技能的ap是百分值 需要/100 而且需要再最终计算总ap时再/100不然会出现ap为90%变0
sDataCom.Attrs[Attrs.critical] = cAttrsComp.critical + sCrt; sDataCom.Attrs[Attrs.critical] = cAttrsComp.getRuntimeCritical() + sCrt;
sDataCom.Attrs[Attrs.freeze_chance] = cAttrsComp.freeze_chance + sFrz; sDataCom.Attrs[Attrs.critical_damage] = cAttrsComp.getRuntimeCritDamageBonus();
sDataCom.Attrs[Attrs.freeze_chance] = cAttrsComp.getRuntimeFreezeChance() + sFrz;
sDataCom.s_uuid=s_uuid sDataCom.s_uuid=s_uuid
sDataCom.skill_lv = Math.max(0, skill_lv); sDataCom.skill_lv = Math.max(0, skill_lv);
sDataCom.fac=cAttrsComp.fac sDataCom.fac=cAttrsComp.fac