Files
bl/logic/service/fight/damage.go
昔念 2ebec8ed05 refactor(fight): 重构伤害计算逻辑
- 优化了 DamageContext 结构体,增加了更多注释说明
- 添加了 initOtherRates、GetOtherRate、PutOtherRate 等方法,提高代码可读性和易用性
- 重写了 Calculate 函数,详细注释了伤害计算的每一步骤
- 增加了对随机值、同系加成、属性克制等逻辑的处理
- 优化了代码结构,提高了
2025-08-11 21:40:53 +08:00

278 lines
9.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package damage
import (
"fmt"
"math/rand"
"github.com/shopspring/decimal"
"github.com/tnnmigga/enum"
)
// SkillType 技能类型枚举,区分物理和特殊技能
type SkillType int
const (
PHYSICAL SkillType = iota + 1 // 物理技能
SPECIAL // 特殊技能
)
// DamageMultiplierZone 伤害乘算区枚举使用enum包定义
type DamageMultiplierZone int
var DamageMultiplierZoneEnum = enum.New[struct {
POWER_ADDITION_ZONE DamageMultiplierZone // 威力加算区,直接加成威力值
POWER_MULTIPLIER_ZONE DamageMultiplierZone // 威力乘算区,倍率调整(如威力倍数)
ATK_RESISTANCE_ZONE DamageMultiplierZone // 物理伤害减免乘区默认1减伤50%对应0.5
SP_ATK_RESISTANCE_ZONE DamageMultiplierZone // 特殊伤害减免乘区默认1减伤50%对应0.5
SPECIAL_EFFECT_MULTIPLIER_ZONE DamageMultiplierZone // 特殊效果乘算区如Boss减伤等
ATTACK_COUNT_ZONE DamageMultiplierZone // 攻击次数乘算区如攻击2次对应2
FIX_DAMAGE_RESISTANCE_ZONE DamageMultiplierZone // 固定伤害减免区,直接减固定值
}]()
// Code 返回枚举对应整数值
func (z DamageMultiplierZone) Code() int {
return int(z)
}
// String 返回枚举名称字符串,方便调试打印
func (z DamageMultiplierZone) String() string {
switch z {
case DamageMultiplierZoneEnum.POWER_ADDITION_ZONE:
return "POWER_ADDITION_ZONE"
case DamageMultiplierZoneEnum.POWER_MULTIPLIER_ZONE:
return "POWER_MULTIPLIER_ZONE"
case DamageMultiplierZoneEnum.ATK_RESISTANCE_ZONE:
return "ATK_RESISTANCE_ZONE"
case DamageMultiplierZoneEnum.SP_ATK_RESISTANCE_ZONE:
return "SP_ATK_RESISTANCE_ZONE"
case DamageMultiplierZoneEnum.SPECIAL_EFFECT_MULTIPLIER_ZONE:
return "SPECIAL_EFFECT_MULTIPLIER_ZONE"
case DamageMultiplierZoneEnum.ATTACK_COUNT_ZONE:
return "ATTACK_COUNT_ZONE"
case DamageMultiplierZoneEnum.FIX_DAMAGE_RESISTANCE_ZONE:
return "FIX_DAMAGE_RESISTANCE_ZONE"
default:
return fmt.Sprintf("Unknown(DamageMultiplierZone=%d)", z)
}
}
// FromCode 根据整数值获取枚举
func FromCode(code int) (DamageMultiplierZone, error) {
switch code {
case 1:
return DamageMultiplierZoneEnum.POWER_ADDITION_ZONE, nil
case 2:
return DamageMultiplierZoneEnum.POWER_MULTIPLIER_ZONE, nil
case 3:
return DamageMultiplierZoneEnum.ATK_RESISTANCE_ZONE, nil
case 4:
return DamageMultiplierZoneEnum.SP_ATK_RESISTANCE_ZONE, nil
case 5:
return DamageMultiplierZoneEnum.SPECIAL_EFFECT_MULTIPLIER_ZONE, nil
case 6:
return DamageMultiplierZoneEnum.ATTACK_COUNT_ZONE, nil
case 7:
return DamageMultiplierZoneEnum.FIX_DAMAGE_RESISTANCE_ZONE, nil
default:
return 0, fmt.Errorf("未知的DamageMultiplierZone代码: %d", code)
}
}
// Pet 接口,表示战斗中的宠物实体,包含等级、类型和名称等
type Pet interface {
Level() int64
Type() SkillType
Name() string
}
// SkillInterface 接口,表示技能实体,包含技能类型和名称
type SkillInterface interface {
SkillType() SkillType
Name() string
}
// DamageContext 伤害计算上下文,包含攻击方、防御方宠物,技能信息,以及各种计算参数
type DamageContext struct {
attackerPet Pet // 攻击宠物
defenderPet Pet // 防御宠物
skill SkillInterface // 技能
Type SkillType // 技能属性类型(物理或特殊)
BasePower int64 // 基础威力值
Attack int64 // 攻击力
Defense int64 // 防御力
CriticalRate float64 // 暴击倍率默认2.0倍
SameTypeRate float64 // 同系加成倍率默认1.5倍
Random int // 随机值,默认-1表示未设置
otherRates map[DamageMultiplierZone]decimal.Decimal // 各伤害乘算区倍率使用高精度decimal
extraRates map[string]decimal.Decimal // 额外倍率支持自定义key
}
// NewDamageContext 构造函数,初始化默认值
func NewDamageContext(attackerPet, defenderPet Pet, skill SkillInterface) *DamageContext {
ctx := &DamageContext{
attackerPet: attackerPet,
defenderPet: defenderPet,
skill: skill,
CriticalRate: 2.0,
SameTypeRate: 1.5,
Random: -1,
otherRates: make(map[DamageMultiplierZone]decimal.Decimal),
extraRates: make(map[string]decimal.Decimal),
}
ctx.initOtherRates()
return ctx
}
// initOtherRates 初始化伤害乘算区的默认倍率值
func (c *DamageContext) initOtherRates() {
c.otherRates[DamageMultiplierZoneEnum.POWER_ADDITION_ZONE] = decimal.Zero // 威力加成默认0
c.otherRates[DamageMultiplierZoneEnum.POWER_MULTIPLIER_ZONE] = decimal.NewFromInt(1) // 威力倍率默认1
c.otherRates[DamageMultiplierZoneEnum.ATK_RESISTANCE_ZONE] = decimal.NewFromInt(1) // 物理减伤默认1
c.otherRates[DamageMultiplierZoneEnum.SP_ATK_RESISTANCE_ZONE] = decimal.NewFromInt(1) // 特殊减伤默认1
c.otherRates[DamageMultiplierZoneEnum.SPECIAL_EFFECT_MULTIPLIER_ZONE] = decimal.NewFromInt(1) // 特殊效果倍率默认1
c.otherRates[DamageMultiplierZoneEnum.ATTACK_COUNT_ZONE] = decimal.NewFromInt(1) // 攻击次数默认1
c.otherRates[DamageMultiplierZoneEnum.FIX_DAMAGE_RESISTANCE_ZONE] = decimal.Zero // 固定减伤默认0
}
// GetOtherRate 获取指定伤害乘算区的倍率
func (c *DamageContext) GetOtherRate(zone DamageMultiplierZone) decimal.Decimal {
if val, ok := c.otherRates[zone]; ok {
return val
}
return decimal.NewFromInt(1)
}
// PutOtherRate 设置指定伤害乘算区的倍率,支持链式调用
func (c *DamageContext) PutOtherRate(zone DamageMultiplierZone, value decimal.Decimal) *DamageContext {
switch zone {
case DamageMultiplierZoneEnum.FIX_DAMAGE_RESISTANCE_ZONE:
// 固定伤害减免区,累加
c.otherRates[zone] = c.GetOtherRate(zone).Add(value)
case DamageMultiplierZoneEnum.ATTACK_COUNT_ZONE:
// 攻击次数区,直接覆盖
c.otherRates[zone] = value
case DamageMultiplierZoneEnum.ATK_RESISTANCE_ZONE, DamageMultiplierZoneEnum.SP_ATK_RESISTANCE_ZONE:
// 减伤乘算区乘法叠加只当value>0时
if value.GreaterThan(decimal.Zero) {
c.otherRates[zone] = c.GetOtherRate(zone).Mul(value)
}
default:
// 其他乘算区加法叠加且不小于0.1
r := c.GetOtherRate(zone).Add(value)
if r.LessThan(decimal.NewFromFloat(0.1)) {
r = decimal.NewFromFloat(0.1)
}
c.otherRates[zone] = r
}
return c
}
// RandomValue 获取当前随机值,-1表示未设置
func (c *DamageContext) RandomValue() int {
return c.Random
}
// SetRandomValue 设置随机值,支持链式调用
func (c *DamageContext) SetRandomValue(r int) *DamageContext {
c.Random = r
return c
}
// PutExtraRate 设置自定义额外倍率
func (c *DamageContext) PutExtraRate(key string, value decimal.Decimal) {
c.extraRates[key] = value
}
// GetExtraRate 获取自定义额外倍率,返回倍率和是否存在
func (c *DamageContext) GetExtraRate(key string) (decimal.Decimal, bool) {
val, ok := c.extraRates[key]
return val, ok
}
// Calculate 伤害计算函数,返回最终伤害整数值
func Calculate(random *rand.Rand, context *DamageContext, isCritical bool) int64 {
// 初始化随机值范围217~255
if context.RandomValue() == -1 {
context.SetRandomValue(random.Intn(39) + 217)
}
// 1. 计算等级因子 (level * 0.4 + 2)
levelFactor := decimal.NewFromInt(context.attackerPet.Level()).Mul(decimal.NewFromFloat(0.4)).Add(decimal.NewFromInt(2))
// 2. 计算威力因子 (基础威力 + 加算) * 乘算
powerAdd := context.GetOtherRate(DamageMultiplierZoneEnum.POWER_ADDITION_ZONE)
powerMul := context.GetOtherRate(DamageMultiplierZoneEnum.POWER_MULTIPLIER_ZONE)
powerZone := decimal.NewFromInt(context.BasePower).Add(powerAdd).Mul(powerMul)
// 3. 根据技能类型获取对应减伤乘算
damageReduction := decimal.NewFromFloat(1)
switch context.skill.SkillType() {
case PHYSICAL:
damageReduction = context.GetOtherRate(DamageMultiplierZoneEnum.ATK_RESISTANCE_ZONE)
case SPECIAL:
damageReduction = context.GetOtherRate(DamageMultiplierZoneEnum.SP_ATK_RESISTANCE_ZONE)
}
// 4. 攻击次数倍率
attackCount := context.GetOtherRate(DamageMultiplierZoneEnum.ATTACK_COUNT_ZONE)
attackDec := decimal.NewFromInt(context.Attack)
defenseDec := decimal.NewFromInt(context.Defense)
// 5. 基础伤害公式:等级因子 * 威力因子 * 攻击 / 防御 / 50 + 2然后乘以攻击次数
baseDamage := levelFactor.
Mul(powerZone).
Mul(attackDec).
Div(defenseDec).
Div(decimal.NewFromInt(50)).
Add(decimal.NewFromInt(2)).
Mul(attackCount)
// 6. 同系加成属性相同则乘以同系加成倍率否则1
sameTypeBonus := decimal.NewFromFloat(1.0)
if context.Type == context.attackerPet.Type() {
sameTypeBonus = decimal.NewFromFloat(context.SameTypeRate)
}
// 7. 属性克制倍率示例写死1.2,实际业务中请替换成具体逻辑)
typeRate := decimal.NewFromFloat(1.2)
// 8. 暴击倍率暴击时使用暴击倍率否则1
criticalRate := decimal.NewFromFloat(1.0)
if isCritical {
criticalRate = decimal.NewFromFloat(context.CriticalRate)
}
// 9. 技能特殊效果倍率
specialEffect := context.GetOtherRate(DamageMultiplierZoneEnum.SPECIAL_EFFECT_MULTIPLIER_ZONE)
// 10. 随机倍率随机值除以255
randomFactor := decimal.NewFromInt(int64(context.Random)).Div(decimal.NewFromInt(255))
// 11. 计算总伤害
damage := baseDamage.
Mul(sameTypeBonus).
Mul(typeRate).
Mul(criticalRate).
Mul(damageReduction).
Mul(specialEffect).
Mul(randomFactor)
// 12. 存储真实伤害到额外倍率,方便后续查询
context.PutExtraRate("REAL_DAMAGE", damage)
// 13. 应用固定伤害减免伤害不能低于0
fixReduction := context.GetOtherRate(DamageMultiplierZoneEnum.FIX_DAMAGE_RESISTANCE_ZONE)
if fixReduction.GreaterThan(decimal.Zero) {
damage = damage.Sub(fixReduction)
if damage.LessThan(decimal.Zero) {
damage = decimal.Zero
}
}
// 返回最终伤害(整数部分)
return damage.IntPart()
}