Files
bl/logic/service/fight/info/BattleSkillEntity.go
昔念 7ef001f1b9 refactor(fight): 重构战斗逻辑
- 新增 AI_player 结构体和相关方法,用于创建和管理 AI 玩家
- 重构 FightC 结构体,增加 Input 结构体用于封装玩家输入
- 优化战斗流程,包括回合处理、技能使用、伤害计算等
- 改进广播机制,使用函数回调替代直接调用方法
- 优化玩家和 AI 的动作处理逻辑
2025-09-08 01:23:12 +08:00

348 lines
9.8 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 info
import (
element "blazing/common/data/Element"
"blazing/common/data/xmlres"
"blazing/modules/blazing/model"
"math/rand"
"context"
"fmt"
"strconv"
"github.com/gogf/gf/v2/os/glog"
"github.com/shopspring/decimal"
"github.com/tnnmigga/enum"
)
const BattleSkillEntityCtx = "skill"
// EnumSkillType 技能类型枚举基础类型
type EnumCategory int
// SkillType 技能类型枚举实例使用enum包创建
// 与原Java枚举保持相同的数值映射PHYSICAL=1, SPECIAL=2, STATUS=4
var Category = enum.New[struct {
PHYSICAL EnumCategory `enum:"1"` // 物理攻击
SPECIAL EnumCategory `enum:"2"` // 特殊攻击
STATUS EnumCategory `enum:"4"` // 状态技能
Fixed EnumCategory // 固定伤害
Percent EnumCategory // 百分比伤害
True EnumCategory // 真伤
ALL EnumCategory //任何类型
}]()
// BattleSkillEntity 战斗技能实体
// 实现了战斗中技能的所有属性和行为包括PP管理、技能使用、属性获取等
// 战斗中可以修改技能实体值,比如是否暴击,是否必中等
type BattleSkillEntity struct {
xmlres.Move
PP int
DamageZone map[EnumCategory]map[EnumsZoneType]map[EnumsZoneType][]float64 // 三维map 伤害类型-》增还是减-》加还是乘-》值
DamageValue decimal.Decimal // 伤害值
Rand *rand.Rand
Pet *BattlePetEntity
}
// CreateBattleSkillWithInfinity 创建战斗技能实例可指定是否无限PP
func CreateBattleSkillWithInfinity(skill *model.SkillInfo, rand *rand.Rand, pet *BattlePetEntity) *BattleSkillEntity {
//如果PP是-1 ,那就是无限PP
// ID小于10001的视为无效技能
if skill.ID < 10001 {
return nil
}
var ret BattleSkillEntity
ret.Rand = rand
ret.Pet = pet
// 从资源仓库获取技能数据
move, ok := xmlres.SkillMap[int(skill.ID)]
if !ok {
glog.Error(context.Background(), "技能ID无效", "id", skill.ID)
}
ret.Move = move
// // 解析副作用参数
// sideEffectArgs := parseSideEffectArgs(move.SideEffectArg)
// tt := strings.Split(move.SideEffect, " ")
// rf, err := strSliceToIntSlice(tt)
// if err == nil {
// ret.SideEffects = rf
// }
ret.PP = int(skill.PP)
// ret.SideEffectArgs = sideEffectArgs
ret.DamageZone = make(map[EnumCategory]map[EnumsZoneType]map[EnumsZoneType][]float64) //初始化第一层类型
for _, v := range enum.Values[EnumCategory](Category) {
ret.DamageZone[v] = make(map[EnumsZoneType]map[EnumsZoneType][]float64) //初始化第二层是否是加还是减
for _, t := range enum.Values[EnumsZoneType](DamageC) {
ret.DamageZone[v][t] = make(map[EnumsZoneType][]float64) //初始化第三层时乘还是加
for _, s := range enum.Values[EnumsZoneType](DamageC) {
ret.DamageZone[v][t][s] = make([]float64, 0) //初始化第四层 数组
}
}
}
return &ret
}
// 将字符串切片转换为整数切片
func strSliceToIntSlice(strs []string) ([]int, error) {
intSlice := make([]int, 0, len(strs)) // 预分配容量,提高性能
for _, s := range strs {
// 将字符串转换为整数
num, err := strconv.Atoi(s)
if err != nil {
// 转换失败时返回错误(包含具体的错误信息和失败的字符串)
return nil, fmt.Errorf("无法将字符串 '%s' 转换为整数: %v", s, err)
}
intSlice = append(intSlice, num)
}
return intSlice, nil
}
// CanUse 检查技能是否可以使用PP是否充足
func (s *BattleSkillEntity) CanUse() bool {
return s.PP > 0
}
// 获取技能类型
func (s *BattleSkillEntity) Category() EnumCategory {
return EnumCategory(s.Move.Category)
}
// 获取技能属性
func (s *BattleSkillEntity) Type() *element.ElementCombination {
ret, _ := element.NewElementCombination(s.Move.Type)
return ret
}
// // 技能产生effect
// func (u *BattleSkillEntity) NewEffect(ctx context.Context)*node.EffectNode {
// ret := node.EffectNode{}
// ctx = context.WithValue(ctx, BattleSkillEntityCtx, &ret) //添加用户到上下文
// ret.ctx = ctx
// }
// 解析副作用参数字符串为整数列表
// 获取技能名称为空时使用ID
func getSkillName(move *BattleSkillEntity) string {
if move.Name == "" {
return strconv.FormatInt(int64(move.ID), 10)
}
return move.Name
}
// 获取副作用列表,处理空值情况
// func getSideEffects(move *BattleSkillEntity) []int {
// if move.SideEffect == "" {
// return []int{}
// }
// return move.SideEffects
// }
type EnumsZoneType int
var DamageZone = enum.New[struct {
add EnumsZoneType // 加区
nul EnumsZoneType // 乘区
}]()
var DamageC = enum.New[struct {
boost EnumsZoneType //增伤区
reduction EnumsZoneType // 减伤区
}]()
// func (s *BattleSkillEntity) Random() *random.RandomXS128 {
// battle, _ := s.ctx.Value(BattleContainerCtx).(*Battle1V1)
// return battle.Rand
// }
// 获得指定的+-区
func (s *BattleSkillEntity) GetAddValue(e EnumCategory, c EnumsZoneType) decimal.Decimal {
t, ok := s.DamageZone[e][c][DamageZone.add]
if ok {
var ttt decimal.Decimal
for _, v := range t {
t1 := decimal.NewFromFloat(v)
ttt.Add(t1)
}
return ttt
}
return decimal.NewFromFloat(0)
}
// 获得指定的*/区
func (s *BattleSkillEntity) GetMulValue(e EnumCategory, c EnumsZoneType) decimal.Decimal {
t, ok := s.DamageZone[e][c][DamageZone.nul]
if ok {
var ttt decimal.Decimal
for _, v := range t {
t1 := decimal.NewFromFloat(v)
ttt.Mul(t1)
}
return ttt
}
return decimal.NewFromFloat(0)
}
// 设置指定的值
// 三维map 伤害类型-》增还是减-》加还是乘-》值
func (s *BattleSkillEntity) PutDamageZone(e EnumCategory, dtype EnumsZoneType, value float64, ftype EnumsZoneType) {
s.DamageZone[e][dtype][ftype] = append(s.DamageZone[e][dtype][ftype], value)
// switch dtype { //判断伤害节点段
// //case Zone.Power: //特判乘算区的乘运算
// default:
// switch ftype { //判断设置哪个算区
// case true: // 乘算区
// old := s.GetAddValue(e)
// new := decimal.NewFromFloat(value)
// s.DamageZone[dtype] = float64(old.Add(new).IntPart())
// case false: // 加算区
// old := s.GetMulValue(e)
// new := decimal.NewFromFloat(value)
// s.DamageZone[dtype] = float64(old.Add(new).IntPart())
// }
// }
}
// func (s *BattleSkillEntity) Pet() (*BattlePetEntity, bool) {
// pet, ok := s.ctx.Value(Pet_O_Ctx).(*BattlePetEntity)
// return pet, ok
// }
// 暴击伤害 返回暴击率和是否暴击
func (s *BattleSkillEntity) IsCritical() (decimal.Decimal, bool) {
return decimal.NewFromFloat(1), true
}
// 计算是否命中
func (s *BattleSkillEntity) AttackTime() uint32 {
if int64(s.Pet.Accuracy(int64(s.Accuracy))) > s.Rand.Int63n(100) {
return 1
}
return 0
}
func (s *BattleSkillEntity) CriticalsameTypeBonus() decimal.Decimal {
// 6. 同系加成属性相同则乘以同系加成倍率否则1
sameTypeBonus := decimal.NewFromFloat(1.0)
if s.Type() == s.Pet.Type() { //使用本系
sameTypeBonus = decimal.NewFromFloat(1.5)
}
stype := s.Type()
ptype := s.Pet.Type()
if stype.Secondary == nil && ptype.Secondary != nil && (stype.Primary == ptype.Primary || stype.Primary == *ptype.Secondary) { //判断技能属性是否是精灵双属性之一
sameTypeBonus = decimal.NewFromFloat(1.5)
}
return sameTypeBonus
}
func (s *BattleSkillEntity) criticalrandom() decimal.Decimal {
randomnum := s.Rand.Int31n(39) + 217
// 10. 随机倍率随机值除以255
randomFactor := decimal.NewFromInt(int64(randomnum)).Div(decimal.NewFromInt(255))
return randomFactor
}
// 计算技能威力
func (s *BattleSkillEntity) CalculatePower(deftype int) uint32 {
// 1. 计算等级因子 (level * 0.4 + 2)
levelFactor := decimal.NewFromInt(int64(s.Pet.Info.Level)).
Mul(decimal.NewFromFloat(0.4)).Add(decimal.NewFromInt(2))
// 2. 计算威力因子 (基础威力 + 加算) * 乘算
//powerAdd := decimal.NewFromFloat(s.GetAddValue(EnumCategory., true)) //威力加算区
powerAdd_all := s.GetAddValue(Category.ALL, DamageC.boost)
powerMul_all := s.GetMulValue(Category.ALL, DamageC.boost)
var (
powerAdd_p decimal.Decimal //威力加算
powerMul_p decimal.Decimal //威力乘算
attackDec decimal.Decimal //攻击值
defenseDec decimal.Decimal //防御值
//damageReduction decimal.Decimal //伤害百分比减免
)
switch s.Category() { //判断技能类型
case Category.PHYSICAL:
powerAdd_p = powerAdd_all.Add(s.GetAddValue(Category.PHYSICAL, DamageC.boost))
powerMul_p = powerMul_all.Add(s.GetMulValue(Category.PHYSICAL, DamageC.boost))
attackDec = decimal.NewFromInt(int64(s.Pet.Attack()))
defenseDec = decimal.NewFromInt(int64(s.Pet.Defense()))
//damageReduction = decimal.NewFromFloat(s.DamageZone[DamageMultiplierZoneEnum.ATK_RESISTANCE])
case Category.SPECIAL:
powerAdd_p = powerAdd_all.Add(s.GetAddValue(Category.SPECIAL, DamageC.boost))
powerMul_p = powerMul_all.Add(s.GetMulValue(Category.SPECIAL, DamageC.boost))
attackDec = decimal.NewFromInt(int64(s.Pet.SAttack()))
defenseDec = decimal.NewFromInt(int64(s.Pet.SDefense()))
//damageReduction = decimal.NewFromFloat(s.DamageZone[DamageMultiplierZoneEnum.SP_ATK_RESISTANCE])
default:
return 0
}
if powerMul_p.IntPart() == 0 {
powerMul_p = decimal.NewFromInt(1)
}
powerZone := decimal.NewFromInt(int64(s.Power)).Add(powerAdd_p).Mul(powerMul_p)
// 5. 基础伤害公式:等级因子 * 威力因子 * 攻击 / 防御 / 50 + 2
baseDamage := levelFactor.
Mul(powerZone).
Mul(attackDec).
Div(defenseDec).
Div(decimal.NewFromInt(50)).
Add(decimal.NewFromInt(2))
t, _ := element.NewElementCalculator().GetOffensiveMultiplier(s.Type().ID, deftype)
typeRate := decimal.NewFromFloat(t)
damage := baseDamage.
Mul(s.CriticalsameTypeBonus()). // 同属性加成
Mul(typeRate). // 克制系数
Mul(s.criticalrandom()) //随机波动
v, ok := s.IsCritical() //获取暴击
if ok {
damage.Mul(v)
}
return uint32(damage.IntPart())
}