Files
bl/logic/service/fight/info/BattleSkillEntity.go
昔念 a86782b1ea ```text
refactor(fight): 重构战斗准备逻辑并优化战斗启动流程

将 ReadyFight 方法拆分为多个职责清晰的子方法:
- buildFightStartInfo: 构建战斗初始信息
- checkBothPlayersReady: 检查PVP双方是否就绪
- handleNPCFightSpecial: 处理NPC战斗特殊逻辑(如可捕捉标记)
- startBattle: 统一启动战斗流程

同时修复部分逻辑顺序问题,增强代码可读性和扩展性。

feat(fight): 新增精灵王挑战协议支持

增加 StartPetWarInboundInfo 结构体用于接收精灵王挑战请求,
为后续实现相关功能提供基础。

fix(effect): 修正多个技能效果数值引用错误

- effect_37: 技能威力计算使用正确参数索引
- effect_50: 固定减伤比例调整为除以2
- effect_65: 正确比较技能分类类型
- effect_68: 致死保护改为锁定剩余1点生命值
- effect_77: 回复目标由敌方改为己方
- effect_93: 固定伤害值直接取参数

refactor(effect): 移除冗余效果类文件

删除 effect_133.go 和 effect_90.go 文件,其功能已被统一条件伤害和倍率系统取代;
移除 effect_74.go、effect_75.go 中重复的状态随机施加逻辑。

refactor(effect): 更新能力操作枚举命名一致性

重命名 AbilityOpType 枚举项名称,去除前缀,提升语义清晰度:
- AbilityOpStealStrengthen → StealStrengthen
- AbilityOpReverse → Reverse
- AbilityOpBounceWeaken → BounceWeaken

chore(fight): 完善 BattlePetEntity 属性初始化逻辑

在创建 BattlePetEntity 时即设置 PType,避免后续多次查询 PetMAP;
移除 Type() 方法中的冗余配置查找逻辑。

fix(skill): 确保必中技能不参与命中率计算

在 AttackTimeC 方法中添加 return 防止必中技能继续执行命中率公式计算。

refactor(fight): 调整战斗回合结束逻辑

进入新回合时允许玩家更换精灵,并提前跳出循环防止多余处理。

style(effect): 更正拼写及变量命名风格

修改 BaseSataus.Switch 方法签名中的参数命名;
更正 Effect58 中 can 字段首字母大写;
2025-11-14 23:09:16 +08:00

239 lines
5.7 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"
"fmt"
"strconv"
"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"` // 状态技能
//ALL EnumCategory //任何类型
}]()
type EnumDamageType int
var DamageType = enum.New[struct {
Red EnumDamageType `enum:"0"`
Fixed EnumDamageType // 固定伤害
Percent EnumDamageType // 百分比伤害
True EnumDamageType // 真伤
}]()
type DamageZone struct {
Type EnumDamageType
Damage decimal.Decimal
}
// SkillEntity 战斗技能实体
// 实现了战斗中技能的所有属性和行为包括PP管理、技能使用、属性获取等
// 战斗中可以修改技能实体值,比如是否暴击,是否必中等
type SkillEntity struct {
xmlres.Move
Info *model.SkillInfo
// DamageValue decimal.Decimal // 伤害值
Rand *rand.Rand
Pet *BattlePetEntity
//MaxValue func(ahp, bhp uint32) decimal.Decimal
Crit uint32
AttackTime uint32
}
// CreateSkill 创建战斗技能实例可指定是否无限PP
func CreateSkill(skill *model.SkillInfo, rand *rand.Rand, pet *BattlePetEntity) *SkillEntity {
var ret SkillEntity
ret.Rand = rand
ret.Pet = pet
// 从资源仓库获取技能数据
move, ok := xmlres.SkillMap[int(skill.ID)]
if ok {
ret.Move = move
}
ret.Info = skill
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 *SkillEntity) CanUse() bool {
return s.Info.PP > 0
}
// 获取技能类型
func (s *SkillEntity) Category() EnumCategory {
return EnumCategory(s.Move.Category)
}
// 获取技能属性
func (s *SkillEntity) Type() *element.ElementCombination {
ret, _ := element.Calculator.GetCombination(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 *SkillEntity) 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
// }
// func (s *BattleSkillEntity) Random() *random.RandomXS128 {
// battle, _ := s.ctx.Value(BattleContainerCtx).(*Battle1V1)
// return battle.Rand
// }
// func (s *BattleSkillEntity) Pet() (*BattlePetEntity, bool) {
// pet, ok := s.ctx.Value(Pet_O_Ctx).(*BattlePetEntity)
// return pet, ok
// }
// 计算是否命中
func (s *SkillEntity) AttackTimeC(level int) {
s.AttackTime = 0 //先重置上一次的
if s.MustHit != 0 {
s.AttackTime = 2
return
}
a := int64(s.GetAccuracy(level))
r := s.Rand.Int63n(100)
if a >= r {
s.AttackTime = 1
}
}
func (s *SkillEntity) CriticalsameTypeBonus() decimal.Decimal {
// 同系加成默认倍率为1.0
sameTypeBonus := decimal.NewFromFloat(1.0)
skillType := s.Type()
petType := s.Pet.Type()
// 收集技能的所有属性主属性必存在次属性可能为nil
skillAttrs := []element.ElementType{skillType.Primary}
if skillType.Secondary != nil {
skillAttrs = append(skillAttrs, *skillType.Secondary)
}
// 收集宠物的所有属性主属性必存在次属性可能为nil
petAttrs := []element.ElementType{petType.Primary}
if petType.Secondary != nil {
petAttrs = append(petAttrs, *petType.Secondary)
}
// 检查技能属性与宠物属性是否有任一匹配
for _, sa := range skillAttrs {
for _, pa := range petAttrs {
if sa == pa {
// 存在匹配属性触发1.5倍加成
sameTypeBonus = decimal.NewFromFloat(1.5)
return sameTypeBonus // 一旦匹配,直接返回,避免多余循环
}
}
}
return sameTypeBonus
}
func (s *SkillEntity) Criticalrandom() decimal.Decimal {
randomnum := s.Rand.Int31n(39) + 217
// 10. 随机倍率随机值除以255
randomFactor := decimal.NewFromInt(int64(randomnum)).Div(decimal.NewFromInt(255))
return randomFactor
}
// Accuracy 优化版命中率计算(用绝对值和正负判断处理等级)
func (a *SkillEntity) GetAccuracy(level int) uint32 {
// 基础参数校验
if level >= 0 { //强化等级
return uint32(CalculateRealValue((a.Accuracy), level))
}
var temp float64
switch level {
case -1:
temp = 0.85
case -2:
temp = 0.7
case -3:
temp = 0.55
case -4:
temp = 0.45
case -5:
temp = 0.35
case -6:
temp = 0.25
}
return uint32(
decimal.NewFromInt(int64(a.Accuracy)). // 将b转为decimal类型
Mul(decimal.NewFromFloat(temp)). // 精确乘以0.85
//Round(0). // 四舍五入到整数
IntPart(), // 转为int64
)
}