diff --git a/assets/script/game/hero/HeroAtkSystem.ts b/assets/script/game/hero/HeroAtkSystem.ts index 0b81ef6f..155a37a4 100644 --- a/assets/script/game/hero/HeroAtkSystem.ts +++ b/assets/script/game/hero/HeroAtkSystem.ts @@ -203,48 +203,123 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd return reDate; } /** - * 基础伤害计算 - * 根据技能配置和施法者属性计算基础伤害值 + * 详细伤害计算核心方法 * - * @param CAttrs 施法者属性快照(包含攻击力等关键属性) - * @param s_uuid 技能ID,用于获取技能配置 - * @returns 基础伤害值(未考虑暴击、抗性等因素) + * 这是整个战斗系统中最核心的伤害计算方法,负责根据施法者属性、目标属性和技能配置 + * 计算最终的基础伤害值。该方法采用多阶段的伤害计算公式,综合考虑了物理和魔法伤害 + * 以及各种属性加成和抗性减免。 * - * @todo 后续可以扩展更多伤害计算公式: - * - 技能倍率加成 - * - 元素伤害计算 - * - 真实伤害/魔法伤害/物理伤害区分 + * 计算流程: + * 1. 获取技能配置 + * 2. 计算原始物理伤害和魔法伤害 + * 3. 应用防御减免 + * 4. 应用物理/魔法攻击力和抗性修正 + * 5. 应用元素属性加成和抗性修正 + * 6. 应用最终伤害减免 + * 7. 确保伤害值非负 + * + * @param CAttrs 施法者属性快照对象,包含所有攻击力、属性加成等战斗属性 + * @param TAttrs 目标属性对象,包含所有防御力、抗性等防御属性 + * @param s_uuid 技能ID,用于获取技能配置信息和伤害类型 + * @returns 经过完整计算后的最终伤害值(未考虑暴击) + * + * @important 注意事项: + * - 此方法计算的是基础伤害,暴击计算在外部处理 + * - 所有除法和乘法计算后都进行取整操作,确保游戏中的伤害值为整数 + * - 元素伤害只应用于魔法伤害部分 */ private dmgCount(CAttrs:any,TAttrs:any,s_uuid:number){ + // 1. 获取技能配置 - 如果技能不存在,直接返回0伤害 let sConf = SkillSet[s_uuid]; if (!sConf) return 0; + + // 2. 计算原始物理伤害和魔法伤害 + // 物理伤害基础值 = 技能物理倍率 * 施法者物理攻击力 / 100 let apBase = (sConf.ap||0)*CAttrs[Attrs.AP]/100; + // 魔法伤害基础值 = 技能魔法倍率 * 施法者魔法攻击力 / 100 let mapBase = (sConf.map||0)*CAttrs[Attrs.MAP]/100; - const def = (TAttrs[Attrs.DEF]||0); - const mdef = (TAttrs[Attrs.MDEF]||0); - const apRed = def / (def + FightSet.DEF_C); - const mapRed = mdef / (mdef + FightSet.MDEF_C); - let apAfter = Math.floor(apBase * (1 - apRed)); - let mapAfter = Math.floor(mapBase * (1 - mapRed)); + + // 3. 获取目标防御属性 + const def = (TAttrs[Attrs.DEF]||0); // 目标物理防御 + const mdef = (TAttrs[Attrs.MDEF]||0); // 目标魔法防御 + + // 4. 计算防御减免系数(采用公式:防御/(防御+常数),确保防御值不会导致伤害减到0) + const apRed = def / (def + FightSet.DEF_C); // 物理防御减免系数 + const mapRed = mdef / (mdef + FightSet.MDEF_C); // 魔法防御减免系数 + + // 5. 应用防御减免到基础伤害,向下取整 + let apAfter = Math.floor(apBase * (1 - apRed)); // 物理伤害 - 防御减免 + let mapAfter = Math.floor(mapBase * (1 - mapRed)); // 魔法伤害 - 防御减免 + + // 6. 应用物理/魔法攻击力和抗性修正 + // 物理伤害修正:基础伤害 * (1 + 物理攻击力加成%) * (1 - 目标物理抗性%) apAfter = this.applyPR(apAfter, CAttrs[Attrs.PHYS_POWER]||0, TAttrs[Attrs.PHYS_RES]||0); + // 魔法伤害修正:基础伤害 * (1 + 魔法攻击力加成%) * (1 - 目标魔法抗性%) mapAfter = this.applyPR(mapAfter, CAttrs[Attrs.MAGIC_POWER]||0, TAttrs[Attrs.MAGIC_RES]||0); + + // 7. 根据技能元素类型,应用元素属性加成和抗性修正 switch (sConf.DType) { case DType.ICE: + // 冰系伤害修正:魔法伤害 * (1 + 冰系攻击力加成%) * (1 - 目标冰系抗性%) mapAfter = this.applyPR(mapAfter, CAttrs[Attrs.ICE_POWER]||0, TAttrs[Attrs.ICE_RES]||0); break; case DType.FIRE: + // 火系伤害修正:魔法伤害 * (1 + 火系攻击力加成%) * (1 - 目标火系抗性%) mapAfter = this.applyPR(mapAfter, CAttrs[Attrs.FIRE_POWER]||0, TAttrs[Attrs.FIRE_RES]||0); break; case DType.WIND: + // 风系伤害修正:魔法伤害 * (1 + 风系攻击力加成%) * (1 - 目标风系抗性%) mapAfter = this.applyPR(mapAfter, CAttrs[Attrs.WIND_POWER]||0, TAttrs[Attrs.WIND_RES]||0); break; } + + // 8. 计算最终总伤害(物理伤害 + 魔法伤害) let total = apAfter + mapAfter; + + // 9. 应用最终伤害减免效果(如特殊天赋、buff等提供的减免) total = Math.floor(total * (1 - ((TAttrs[Attrs.DAMAGE_REDUCTION]||0)/100))); + + // 10. 确保伤害值非负,返回最终伤害 return Math.max(0,total); } +/** + * 应用攻击力加成和抗性减免的通用计算方法 + * + * 这是一个核心的伤害修正计算方法,用于处理各种类型的攻击力加成和抗性减免。 + * 该方法采用乘法叠加的方式,分别应用攻击者的加成属性和目标的抗性属性。 + * + * 计算公式: + * 最终值 = 基础值 × (1 + 攻击力加成% / 100) × (1 - 抗性% / 100) + * + * 适用场景: + * - 物理攻击力加成和物理抗性减免 + * - 魔法攻击力加成和魔法抗性减免 + * - 元素攻击力加成和元素抗性减免 + * - 其他需要同时考虑加成和减免的属性修正 + * + * 计算逻辑说明: + * 1. 首先将百分比转换为小数形式(除以100) + * 2. 应用攻击者的加成:基础值 × (1 + 加成系数) + * 3. 应用目标的抗性:上一步结果 × (1 - 抗性系数) + * 4. 向下取整,确保结果为整数 + * + * @param base 基础值(通常是经过防御减免后的伤害值) + * @param power 攻击者的攻击力加成值(百分比形式,如50表示50%) + * @param res 目标的抗性值(百分比形式,如30表示30%) + * @returns 经过攻击力加成和抗性减免后的最终值(向下取整) + * + * @important 注意事项: + * - 当抗性值大于100时,可能导致最终值为负数或零 + * - 所有计算结果会向下取整,确保游戏中的数值为整数 + * - 此方法可以被多次调用,以叠加不同类型的加成和减免 + */ private applyPR(base: number, power: number, res: number): number { + // 计算公式:基础值 × (1 + 攻击力加成%) × (1 - 抗性%) + // 1. 将百分比转换为小数:power/100 和 res/100 + // 2. 应用攻击力加成:1 + (power/100) + // 3. 应用抗性减免:1 - (res/100) + // 4. 最终计算并向下取整 return Math.floor(base * (1 + (power/100)) * (1 - (res/100))); } /**