2025-08-25 04:23:32 +08:00
|
|
|
|
package info
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2025-08-25 16:26:56 +08:00
|
|
|
|
element "blazing/common/data/Element"
|
2025-08-30 00:36:08 +08:00
|
|
|
|
"blazing/common/data/xmlres"
|
2025-09-07 00:23:28 +08:00
|
|
|
|
"blazing/modules/blazing/model"
|
|
|
|
|
|
"math/rand"
|
2025-08-25 16:44:50 +00:00
|
|
|
|
|
2025-08-25 04:23:32 +08:00
|
|
|
|
"fmt"
|
|
|
|
|
|
"strconv"
|
|
|
|
|
|
|
2025-12-05 00:24:02 +08:00
|
|
|
|
"github.com/alpacahq/alpacadecimal"
|
|
|
|
|
|
"github.com/shopspring/decimal"
|
|
|
|
|
|
|
2025-08-25 04:23:32 +08:00
|
|
|
|
"github.com/tnnmigga/enum"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2025-08-25 18:30:48 +08:00
|
|
|
|
const BattleSkillEntityCtx = "skill"
|
|
|
|
|
|
|
2025-08-25 04:23:32 +08:00
|
|
|
|
// EnumSkillType 技能类型枚举基础类型
|
2025-08-25 16:26:56 +08:00
|
|
|
|
type EnumCategory int
|
2025-08-25 04:23:32 +08:00
|
|
|
|
|
|
|
|
|
|
// SkillType 技能类型枚举实例(使用enum包创建)
|
|
|
|
|
|
// 与原Java枚举保持相同的数值映射:PHYSICAL=1, SPECIAL=2, STATUS=4
|
2025-08-25 16:26:56 +08:00
|
|
|
|
var Category = enum.New[struct {
|
|
|
|
|
|
PHYSICAL EnumCategory `enum:"1"` // 物理攻击
|
|
|
|
|
|
SPECIAL EnumCategory `enum:"2"` // 特殊攻击
|
|
|
|
|
|
STATUS EnumCategory `enum:"4"` // 状态技能
|
2025-09-26 13:33:55 +08:00
|
|
|
|
|
|
|
|
|
|
//ALL EnumCategory //任何类型
|
|
|
|
|
|
}]()
|
|
|
|
|
|
|
|
|
|
|
|
type EnumDamageType int
|
|
|
|
|
|
|
|
|
|
|
|
var DamageType = enum.New[struct {
|
2025-11-11 05:54:24 +00:00
|
|
|
|
Red EnumDamageType `enum:"0"`
|
2025-09-26 13:33:55 +08:00
|
|
|
|
Fixed EnumDamageType // 固定伤害
|
|
|
|
|
|
Percent EnumDamageType // 百分比伤害
|
|
|
|
|
|
True EnumDamageType // 真伤
|
2025-08-25 04:23:32 +08:00
|
|
|
|
}]()
|
|
|
|
|
|
|
2025-09-26 13:33:55 +08:00
|
|
|
|
type DamageZone struct {
|
|
|
|
|
|
Type EnumDamageType
|
2025-12-05 00:24:02 +08:00
|
|
|
|
Damage alpacadecimal.Decimal
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (d *DamageZone) Mul(n int) {
|
|
|
|
|
|
d.Damage = d.Damage.Mul(alpacadecimal.NewFromInt(int64(n)))
|
|
|
|
|
|
|
2025-09-26 13:33:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-15 00:40:19 +08:00
|
|
|
|
// SkillEntity 战斗技能实体
|
2025-08-25 04:23:32 +08:00
|
|
|
|
// 实现了战斗中技能的所有属性和行为,包括PP管理、技能使用、属性获取等
|
2025-08-25 16:26:56 +08:00
|
|
|
|
// 战斗中可以修改技能实体值,比如是否暴击,是否必中等
|
2025-09-15 00:40:19 +08:00
|
|
|
|
type SkillEntity struct {
|
2025-08-30 00:36:08 +08:00
|
|
|
|
xmlres.Move
|
2025-12-11 13:31:20 +08:00
|
|
|
|
Info *model.SkillInfo
|
2025-09-10 04:17:06 +00:00
|
|
|
|
|
2025-09-29 02:40:35 +08:00
|
|
|
|
// DamageValue decimal.Decimal // 伤害值
|
|
|
|
|
|
Rand *rand.Rand
|
|
|
|
|
|
Pet *BattlePetEntity
|
2025-09-15 00:40:19 +08:00
|
|
|
|
//MaxValue func(ahp, bhp uint32) decimal.Decimal
|
|
|
|
|
|
Crit uint32
|
|
|
|
|
|
AttackTime uint32
|
2025-11-30 10:21:57 +00:00
|
|
|
|
Side bool
|
2025-08-25 04:23:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-15 00:40:19 +08:00
|
|
|
|
// CreateSkill 创建战斗技能实例(可指定是否无限PP)
|
2025-12-11 13:31:20 +08:00
|
|
|
|
func CreateSkill(skill *model.SkillInfo, rand *rand.Rand, pet *BattlePetEntity) *SkillEntity {
|
2025-09-07 05:58:47 +08:00
|
|
|
|
|
2025-09-15 00:40:19 +08:00
|
|
|
|
var ret SkillEntity
|
2025-09-07 05:58:47 +08:00
|
|
|
|
ret.Rand = rand
|
|
|
|
|
|
ret.Pet = pet
|
2025-08-25 04:23:32 +08:00
|
|
|
|
// 从资源仓库获取技能数据
|
2025-09-07 00:23:28 +08:00
|
|
|
|
move, ok := xmlres.SkillMap[int(skill.ID)]
|
2025-09-04 23:57:22 +08:00
|
|
|
|
|
2025-10-10 00:40:32 +08:00
|
|
|
|
if ok {
|
2025-10-05 23:51:37 +08:00
|
|
|
|
ret.Move = move
|
2025-08-25 04:23:32 +08:00
|
|
|
|
}
|
2025-10-05 23:51:37 +08:00
|
|
|
|
|
2025-09-10 22:59:10 +08:00
|
|
|
|
ret.Info = skill
|
2025-10-28 07:39:11 +00:00
|
|
|
|
|
2025-08-25 04:23:32 +08:00
|
|
|
|
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是否充足)
|
2025-09-15 00:40:19 +08:00
|
|
|
|
func (s *SkillEntity) CanUse() bool {
|
2025-09-10 22:59:10 +08:00
|
|
|
|
return s.Info.PP > 0
|
2025-08-25 04:23:32 +08:00
|
|
|
|
}
|
2025-11-30 10:21:57 +00:00
|
|
|
|
func (s *SkillEntity) SetMiss() bool {
|
|
|
|
|
|
if s.AttackTime == 1 {
|
|
|
|
|
|
s.SetNoSide()
|
|
|
|
|
|
s.AttackTime = 0
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 无效掉附带属性
|
|
|
|
|
|
func (s *SkillEntity) SetNoSide() bool {
|
|
|
|
|
|
s.Side = false
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
2025-08-25 04:23:32 +08:00
|
|
|
|
|
2025-08-25 16:26:56 +08:00
|
|
|
|
// 获取技能类型
|
2025-09-15 00:40:19 +08:00
|
|
|
|
func (s *SkillEntity) Category() EnumCategory {
|
2025-08-25 16:26:56 +08:00
|
|
|
|
return EnumCategory(s.Move.Category)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取技能属性
|
2025-11-25 18:25:52 +08:00
|
|
|
|
func (s *SkillEntity) GetType() *element.ElementCombination {
|
2025-11-06 17:25:16 +00:00
|
|
|
|
ret, _ := element.Calculator.GetCombination(s.Move.Type)
|
2025-09-07 05:58:47 +08:00
|
|
|
|
return ret
|
2025-08-25 16:26:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-26 22:26:21 +00:00
|
|
|
|
// // 技能产生effect
|
|
|
|
|
|
// func (u *BattleSkillEntity) NewEffect(ctx context.Context)*node.EffectNode {
|
2025-08-25 04:23:32 +08:00
|
|
|
|
|
2025-08-26 22:26:21 +00:00
|
|
|
|
// ret := node.EffectNode{}
|
|
|
|
|
|
// ctx = context.WithValue(ctx, BattleSkillEntityCtx, &ret) //添加用户到上下文
|
|
|
|
|
|
// ret.ctx = ctx
|
|
|
|
|
|
|
|
|
|
|
|
// }
|
2025-08-25 04:23:32 +08:00
|
|
|
|
// 解析副作用参数字符串为整数列表
|
|
|
|
|
|
|
|
|
|
|
|
// 获取技能名称,为空时使用ID
|
2025-09-15 00:40:19 +08:00
|
|
|
|
func getSkillName(move *SkillEntity) string {
|
2025-08-25 04:23:32 +08:00
|
|
|
|
if move.Name == "" {
|
|
|
|
|
|
return strconv.FormatInt(int64(move.ID), 10)
|
|
|
|
|
|
}
|
|
|
|
|
|
return move.Name
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取副作用列表,处理空值情况
|
2025-09-04 23:57:22 +08:00
|
|
|
|
// func getSideEffects(move *BattleSkillEntity) []int {
|
|
|
|
|
|
// if move.SideEffect == "" {
|
|
|
|
|
|
// return []int{}
|
|
|
|
|
|
// }
|
|
|
|
|
|
// return move.SideEffects
|
|
|
|
|
|
// }
|
2025-08-25 16:26:56 +08:00
|
|
|
|
|
2025-09-04 23:57:22 +08:00
|
|
|
|
// func (s *BattleSkillEntity) Random() *random.RandomXS128 {
|
|
|
|
|
|
// battle, _ := s.ctx.Value(BattleContainerCtx).(*Battle1V1)
|
2025-08-25 16:26:56 +08:00
|
|
|
|
|
2025-09-04 23:57:22 +08:00
|
|
|
|
// return battle.Rand
|
2025-08-25 16:26:56 +08:00
|
|
|
|
|
2025-09-04 23:57:22 +08:00
|
|
|
|
// }
|
2025-08-25 16:26:56 +08:00
|
|
|
|
|
2025-09-04 23:57:22 +08:00
|
|
|
|
// func (s *BattleSkillEntity) Pet() (*BattlePetEntity, bool) {
|
|
|
|
|
|
// pet, ok := s.ctx.Value(Pet_O_Ctx).(*BattlePetEntity)
|
2025-08-25 16:26:56 +08:00
|
|
|
|
|
2025-09-04 23:57:22 +08:00
|
|
|
|
// return pet, ok
|
|
|
|
|
|
|
|
|
|
|
|
// }
|
2025-08-25 16:26:56 +08:00
|
|
|
|
|
2025-09-07 05:58:47 +08:00
|
|
|
|
// 计算是否命中
|
2025-11-30 10:21:57 +00:00
|
|
|
|
func (s *SkillEntity) AttackTimeC(level int) uint32 {
|
2025-11-08 16:38:41 +08:00
|
|
|
|
s.AttackTime = 0 //先重置上一次的
|
2025-11-11 01:10:26 +08:00
|
|
|
|
|
2025-09-12 00:27:49 +08:00
|
|
|
|
if s.MustHit != 0 {
|
2025-09-14 16:56:31 +08:00
|
|
|
|
s.AttackTime = 2
|
2025-11-30 10:21:57 +00:00
|
|
|
|
s.Side = true
|
|
|
|
|
|
return s.AttackTime
|
2025-09-12 00:27:49 +08:00
|
|
|
|
}
|
2025-08-26 23:18:55 +00:00
|
|
|
|
|
2025-11-08 16:38:41 +08:00
|
|
|
|
a := int64(s.GetAccuracy(level))
|
|
|
|
|
|
r := s.Rand.Int63n(100)
|
|
|
|
|
|
if a >= r {
|
2025-11-30 10:21:57 +00:00
|
|
|
|
s.Side = true
|
2025-09-14 16:56:31 +08:00
|
|
|
|
s.AttackTime = 1
|
2025-09-07 05:58:47 +08:00
|
|
|
|
}
|
2025-11-30 10:21:57 +00:00
|
|
|
|
return s.AttackTime
|
2025-09-07 05:58:47 +08:00
|
|
|
|
}
|
2025-12-05 00:24:02 +08:00
|
|
|
|
func (s *SkillEntity) CriticalsameTypeBonus() alpacadecimal.Decimal {
|
2025-11-02 23:52:06 +08:00
|
|
|
|
// 同系加成默认倍率为1.0
|
2025-12-05 00:24:02 +08:00
|
|
|
|
sameTypeBonus := alpacadecimal.NewFromFloat(1.0)
|
2025-11-02 23:52:06 +08:00
|
|
|
|
|
2025-11-25 18:25:52 +08:00
|
|
|
|
skillType := s.GetType()
|
|
|
|
|
|
petType := s.Pet.GetType()
|
2025-11-02 23:52:06 +08:00
|
|
|
|
|
|
|
|
|
|
// 收集技能的所有属性(主属性必存在,次属性可能为nil)
|
|
|
|
|
|
skillAttrs := []element.ElementType{skillType.Primary}
|
|
|
|
|
|
if skillType.Secondary != nil {
|
|
|
|
|
|
skillAttrs = append(skillAttrs, *skillType.Secondary)
|
2025-09-07 05:58:47 +08:00
|
|
|
|
}
|
2025-08-26 23:18:55 +00:00
|
|
|
|
|
2025-11-02 23:52:06 +08:00
|
|
|
|
// 收集宠物的所有属性(主属性必存在,次属性可能为nil)
|
|
|
|
|
|
petAttrs := []element.ElementType{petType.Primary}
|
|
|
|
|
|
if petType.Secondary != nil {
|
|
|
|
|
|
petAttrs = append(petAttrs, *petType.Secondary)
|
|
|
|
|
|
}
|
2025-08-26 23:18:55 +00:00
|
|
|
|
|
2025-11-02 23:52:06 +08:00
|
|
|
|
// 检查技能属性与宠物属性是否有任一匹配
|
|
|
|
|
|
for _, sa := range skillAttrs {
|
|
|
|
|
|
for _, pa := range petAttrs {
|
|
|
|
|
|
if sa == pa {
|
|
|
|
|
|
// 存在匹配属性,触发1.5倍加成
|
2025-12-05 00:24:02 +08:00
|
|
|
|
sameTypeBonus = alpacadecimal.NewFromFloat(1.5)
|
2025-11-02 23:52:06 +08:00
|
|
|
|
return sameTypeBonus // 一旦匹配,直接返回,避免多余循环
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-07 05:58:47 +08:00
|
|
|
|
}
|
2025-11-02 23:52:06 +08:00
|
|
|
|
|
2025-09-07 05:58:47 +08:00
|
|
|
|
return sameTypeBonus
|
|
|
|
|
|
}
|
2025-08-26 23:18:55 +00:00
|
|
|
|
|
2025-12-05 00:24:02 +08:00
|
|
|
|
func (s *SkillEntity) Criticalrandom() alpacadecimal.Decimal {
|
2025-08-26 23:18:55 +00:00
|
|
|
|
|
2025-09-07 05:58:47 +08:00
|
|
|
|
randomnum := s.Rand.Int31n(39) + 217
|
|
|
|
|
|
// 10. 随机倍率,随机值除以255
|
2025-12-05 00:24:02 +08:00
|
|
|
|
randomFactor := alpacadecimal.NewFromInt(int64(randomnum)).Div(alpacadecimal.NewFromInt(255))
|
2025-09-07 05:58:47 +08:00
|
|
|
|
return randomFactor
|
2025-08-26 23:18:55 +00:00
|
|
|
|
|
2025-09-07 05:58:47 +08:00
|
|
|
|
}
|
2025-08-26 23:18:55 +00:00
|
|
|
|
|
2025-09-17 00:38:15 +08:00
|
|
|
|
// Accuracy 优化版命中率计算(用绝对值和正负判断处理等级)
|
|
|
|
|
|
func (a *SkillEntity) GetAccuracy(level int) uint32 {
|
|
|
|
|
|
// 基础参数校验
|
|
|
|
|
|
|
2025-10-23 04:26:01 +00:00
|
|
|
|
if level >= 0 { //强化等级
|
2025-09-17 00:50:37 +08:00
|
|
|
|
return uint32(CalculateRealValue((a.Accuracy), level))
|
2025-09-17 00:38:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
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
|
2025-11-06 17:25:16 +00:00
|
|
|
|
//Round(0). // 四舍五入到整数
|
|
|
|
|
|
IntPart(), // 转为int64
|
2025-09-17 00:38:15 +08:00
|
|
|
|
)
|
|
|
|
|
|
}
|