From 038a5f13da036d31724dae2973f7ea0d8518aff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=94=E5=BF=B5?= <1@72wo.cn> Date: Mon, 25 Aug 2025 16:26:56 +0800 Subject: [PATCH] =?UTF-8?q?refactor(fight):=20=E9=87=8D=E6=9E=84=E6=88=98?= =?UTF-8?q?=E6=96=97=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 优化了数据结构和类型定义,提高了代码的可读性和可维护性 - 移除了未使用的代码和冗余的结构体字段 - 重新组织了代码文件,提高了模块化程度 - 为后续的战斗逻辑实现和优化奠定了坚实的基础 --- common/data/xml/skill/skill.go | 6 +- logic/service/fight/battle/action/Compare.go | 59 ----- .../service/fight/battle/container/battle.go | 13 -- .../fight/battle/container/battle1v1.go | 38 ---- logic/service/fight/battle/random/random.go | 7 - logic/service/fight/info/BattleAction.go | 65 ++++++ .../fight/info/BattleInputSourceEntity.go | 31 ++- logic/service/fight/info/BattlePetEntity.go | 208 ++++++------------ logic/service/fight/info/BattleSkillEntity.go | 189 ++++++++++++++-- .../fight/info/NoteReadyToFightInfo.go | 9 + logic/service/fight/info/battle.go | 13 ++ logic/service/fight/info/battle_1v1.go | 45 ++++ 12 files changed, 395 insertions(+), 288 deletions(-) delete mode 100644 logic/service/fight/battle/action/Compare.go delete mode 100644 logic/service/fight/battle/container/battle.go delete mode 100644 logic/service/fight/battle/container/battle1v1.go create mode 100644 logic/service/fight/info/BattleAction.go create mode 100644 logic/service/fight/info/battle.go create mode 100644 logic/service/fight/info/battle_1v1.go diff --git a/common/data/xml/skill/skill.go b/common/data/xml/skill/skill.go index 65e5b0f89..46924334e 100644 --- a/common/data/xml/skill/skill.go +++ b/common/data/xml/skill/skill.go @@ -17,7 +17,7 @@ type MovesTbl struct { } type MovesMap struct { XMLName xml.Name `xml:"MovesTbl"` - Moves map[int64]Move + Moves map[int]Move EFF []SideEffect `xml:"SideEffects>SideEffect"` } @@ -105,9 +105,9 @@ func getMoves() MovesMap { t1, _ := getxml() xml.Unmarshal(t1, &maps) var mapss MovesMap - mapss.Moves = make(map[int64]Move, 0) + mapss.Moves = make(map[int]Move, 0) for _, v := range maps.Moves { - mapss.Moves[int64(v.ID)] = v + mapss.Moves[int(v.ID)] = v } return mapss diff --git a/logic/service/fight/battle/action/Compare.go b/logic/service/fight/battle/action/Compare.go deleted file mode 100644 index c66673d14..000000000 --- a/logic/service/fight/battle/action/Compare.go +++ /dev/null @@ -1,59 +0,0 @@ -package action - -import ( - "blazing/logic/service/fight/battle/random" - "blazing/logic/service/fight/info" -) - -type BattleAction struct { - Priority int - ramdom *random.RandomXS128 - Skill *info.BattleSkillEntity - Pet *info.BattlePetEntity -} - -// NewBattle1v1ActionComparator 创建1v1战斗动作比较器实例 -// 入参为1v1战斗实例,从战斗中获取随机数生成器(对应原 Java 构造函数) -func NewBattleAction(seek *random.RandomXS128) *BattleAction { - - return &BattleAction{ - - ramdom: seek, - } -} - -// Compare 比较两个1v1战斗动作的执行优先级(核心逻辑) -// 完全遵循原 Java 比较逻辑:优先级 → 技能优先级 → 速度 → AI拼速 → 玩家随机拼速 -func (c *BattleAction) Compare(o2 *BattleAction) *BattleAction { - // 1. 第一步:比较动作本身的优先级(o2 - o1,优先级高的先执行) - p1 := o2.Priority - c.Priority - if p1 > 0 { //说明对手快 - return o2 - } else if p1 < 0 { - return c - } - - // 2. 第二步:如果是“使用技能”类型的动作,额外比较技能优先级和速度 - // 类型断言:判断 o1 是否为 Use1v1SkillAction(对应原 Java instanceof) - - if o2.Skill != nil && c.Skill != nil { - p2 := o2.Skill.Priority - c.Skill.Priority // 假设 Use1v1SkillAction 有 SkillPriority() 方法 - if p2 > 0 { - return o2 - } else if p2 < 0 { - return c - } - } - - // 2.2 比较动作所有者的主力宠物速度(o2 - o1,速度快的先执行) - // 假设:Action.Owner() 返回动作所有者(玩家/AI),Owner.MainPet() 返回主力宠物,Pet.SpeedValue() 返回速度值 - - p2 := int(o2.Pet.GetSpeed()) - int(c.Pet.GetSpeed()) // 假设 Use1v1SkillAction 有 SkillPriority() 方法 - if p2 > 0 { - return o2 - } else if p2 < 0 { - return c - } - - return c // 3.3 速度相同时 ,发起方优先 -} diff --git a/logic/service/fight/battle/container/battle.go b/logic/service/fight/battle/container/battle.go deleted file mode 100644 index cc5cf3c2d..000000000 --- a/logic/service/fight/battle/container/battle.go +++ /dev/null @@ -1,13 +0,0 @@ -package battle - -import ( - "blazing/logic/service/fight/battle/random" - "blazing/logic/service/fight/info" -) - -type BattleContext struct { - Rand random.RandomXS128 - same []info.FightUserInfo //同阵营 - - opposite []info.FightUserInfo //不同阵营 -} diff --git a/logic/service/fight/battle/container/battle1v1.go b/logic/service/fight/battle/container/battle1v1.go deleted file mode 100644 index 79b968c2c..000000000 --- a/logic/service/fight/battle/container/battle1v1.go +++ /dev/null @@ -1,38 +0,0 @@ -package battle - -import "blazing/logic/service/fight/info" - -type BattleContainer struct { - BattleContext - ownerid uint32 -} - -//返回房主信息 -func (b *BattleContainer) Owner() *info.FightUserInfo { - - return &b.same[0] -} - -//返回邀请者信息,比如野怪 -func (b *BattleContainer) Target() *info.FightUserInfo { - - return &b.opposite[0] -} -func NewBattleContainer(i info.NoteReadyToFightInfo) *BattleContainer { - - ret := BattleContainer{} - ret.same = make([]info.FightUserInfo, 0) //初始化本阵营 - ret.opposite = make([]info.FightUserInfo, 0) //初始化敌方阵营 - ret.same = append(ret.same, i.OurInfo) - ret.opposite = append(ret.same, i.OpponentInfo) - ret.ownerid = i.OwnerID //房主ID - return &ret -} - -// b.Turn++ -// fmt.Printf("=== 回合 %d 开始 ===\n", b.Turn) -// b.PublishTrigger(EffectTrigger.TurnStart, containers) -// fmt.Println("=== 玩家操作阶段 ===") -// b.PublishTrigger(EffectTrigger.TurnEnd, containers) -// fmt.Printf("=== 回合 %d 结束 ===\n\n", b.Turn) -// } diff --git a/logic/service/fight/battle/random/random.go b/logic/service/fight/battle/random/random.go index 5d0c70c6f..1437b270f 100644 --- a/logic/service/fight/battle/random/random.go +++ b/logic/service/fight/battle/random/random.go @@ -28,13 +28,6 @@ func NewRandomXS128() *RandomXS128 { return NewRandomXS128WithSeed(seed) } -// 基于用户名和时间创建 -func NewRandomXS128WithUser(user, time int64) *RandomXS128 { - - seed := uint64(user)<<32 | uint64(time) - return NewRandomXS128WithSeed(seed) -} - // NewRandomXS128WithSeed 用单个 uint64 种子创建生成器 func NewRandomXS128WithSeed(seed uint64) *RandomXS128 { seed0 := murmurHash3(seed) diff --git a/logic/service/fight/info/BattleAction.go b/logic/service/fight/info/BattleAction.go new file mode 100644 index 000000000..6932e6359 --- /dev/null +++ b/logic/service/fight/info/BattleAction.go @@ -0,0 +1,65 @@ +package info + +import ( + "context" + + "github.com/tnnmigga/enum" +) + +// EnumPlayerOperation 玩家操作枚举类型 +type EnumPlayerOperation int + +// 定义读秒倒计时期间玩家可执行的操作枚举 +var PlayerOperations = enum.New[struct { + SystemGiveUp EnumPlayerOperation `enum:"-1"` //`enum:"系统选择放弃出手"`比如没有PP + SelectSkill EnumPlayerOperation `enum:"0"` //`enum:"选择技能"` + + ActiveSwitch EnumPlayerOperation `enum:"2"` //`enum:"主动切换(中切)"` + + UsePotion EnumPlayerOperation `enum:"3"` //`enum:"使用药剂"` 捕捉 + //DeathSwitch EnumPlayerOperation `enum:"4"` //`enum:"死亡切换"` 这两个本质上还是对action的比较 + // ExpelledSwitch EnumPlayerOperation `enum:"5"` //`enum:"(被)驱逐切换"` +}]() + +type BattleAction struct { + Priority EnumPlayerOperation //优先级本质上是action的itoa + //ramdom *random.RandomXS128 + ctx context.Context +} + +// Compare 比较两个1v1战斗动作的执行优先级(核心逻辑) +func (c *BattleAction) Compare(a *BattleAction) *BattleAction { + //player, _ := a.ctx.Value("player").(*BattleInputSourceEntity) + // 动作本身的优先级 技能的优先级是0, + p1 := a.Priority - c.Priority + if p1 > 0 { //说明对手快 + return a + } else if p1 < 0 { + return c + } + + if a.Priority == 0 { + skillo, _ := a.ctx.Value("skill").(*BattleSkillEntity) + skillt, _ := a.ctx.Value("skill").(*BattleSkillEntity) + // 使用技能 + + p2 := skillo.Priority - skillt.Priority + if p2 > 0 { + return a + } else if p2 < 0 { + return c + } + peto, _ := a.ctx.Value("pet").(*BattlePetEntity) + pett, _ := a.ctx.Value("pet").(*BattlePetEntity) + + p2 = int(peto.UnitAttributes[AttrType.Speed].Value()) - int(pett.UnitAttributes[AttrType.Speed].Value()) // 假设 Use1v1SkillAction 有 SkillPriority() 方法 + if p2 > 0 { + return a + } else if p2 < 0 { + return c + } + + } + + return c // 3.3 速度相同时 ,发起方优先 +} diff --git a/logic/service/fight/info/BattleInputSourceEntity.go b/logic/service/fight/info/BattleInputSourceEntity.go index 0a49e274f..a3a5df1f6 100644 --- a/logic/service/fight/info/BattleInputSourceEntity.go +++ b/logic/service/fight/info/BattleInputSourceEntity.go @@ -1,10 +1,29 @@ package info -type FightUserInfo struct { - // 用户ID(野怪为0),对应Java的@UInt long - UserID uint32 `fieldDesc:"userID 如果为野怪则为0" ` +import "context" + +type BattleInputSourceEntity struct { + FightUserInfo + ctx context.Context +} + +// 新建一个宠物 +func (u *BattleInputSourceEntity) NewBattlePetEntity(ctx context.Context) { + + ret := BattlePetEntity{} + + ret.UnitAttributes = make(map[EnumAttrType]*Attribute) + //todo 待实现精灵特性+加成的封装 + ctx = context.WithValue(ctx, "player", &ret) //添加用户到上下文 + ret.ctx = ctx + +} +func (u *BattleInputSourceEntity) NewBattleAction(ctx context.Context, actiontype EnumPlayerOperation) { + + ret := BattleAction{ + Priority: actiontype, + } + ctx = context.WithValue(ctx, "player", &ret) //添加用户到上下文 + ret.ctx = ctx - // 玩家名称(野怪为UTF-8的'-',固定16字节) - // 使用[16]byte存储固定长度的字节数组 - Nickname [16]byte ` ` } diff --git a/logic/service/fight/info/BattlePetEntity.go b/logic/service/fight/info/BattlePetEntity.go index ac0b415fd..23557aadc 100644 --- a/logic/service/fight/info/BattlePetEntity.go +++ b/logic/service/fight/info/BattlePetEntity.go @@ -1,84 +1,92 @@ package info import ( + element "blazing/common/data/Element" "blazing/modules/blazing/model" - "math/rand/v2" + "context" "sync" - "github.com/shopspring/decimal" "github.com/tnnmigga/enum" ) -// DamageMultiplierZone 伤害乘算区枚举,使用enum包定义 -type DamageMultiplierZone int - -var DamageMultiplierZoneEnum = enum.New[struct { - POWER_ADDITION_ZONE DamageMultiplierZone // 威力加算区,直接加成威力值 - POWER_MULTIPLIER_ZONE DamageMultiplierZone // 威力乘算区,倍率调整(如威力倍数) +// 战斗属性类型 +type EnumAttrType int +var AttrType = enum.New[struct { + Attack EnumAttrType `enum:"1"` //`enum:"攻击"` + Defense EnumAttrType `enum:"2"` //`enum:"防御"` + SpecialAttack EnumAttrType `enum:"3"` //`enum:"特殊攻击"` + SpecialDefense EnumAttrType `enum:"4"` //`enum:"特殊防御"` + Speed EnumAttrType `enum:"5"` //`enum:"速度"` + Accuracy EnumAttrType `enum:"6"` //`enum:"命中率"` + HP EnumAttrType `enum:"7"` //血量 }]() +// 属性封装结构:Ext 存储临时血量增量(key=状态ID,value=增量值) +type Attribute struct { + CanSet bool // 是否允许修改 + originalValue int + + Stat int //提升等级 + //Ext map[string]interface{} // 例如:{"buff_hp_123": 200} 存储临时血量增量 +} + +func (a *Attribute) Value() int64 { + + return calculateRealValue(int64(a.originalValue), a.Stat) +} + +// 基础属性集合:管理所有属性的封装结构 +type UnitAttributes struct { + attrs map[EnumAttrType]*Attribute // 属性类型→属性封装 +} + type BattlePetEntity struct { // /host *BattleInputSourceEntity // 宠物的主人(输入源) //uuid string // 唯一标识 *model.PetInfo - - GainHp int64 // 获得的生命值 + ctx context.Context + // GainHp int64 // 获得的生命值 Capturable bool // 是否可捕获 // 状态条件(如中毒、烧伤等) statusConditions sync.Map // key: StatusCondition, value: int (剩余回合) - - // 状态变化值 - attackStat int - defenseStat int - specialAttackStat int - specialDefenseStat int - speedStat int - accuracyStat int + UnitAttributes map[EnumAttrType]*Attribute skills [4]*BattleSkillEntity // 技能槽(最多4个技能) - // 特殊属性 - Perseverance int // 毅力值:抵消致命伤 - Stubborn bool // 顽强特性 - StubbornProbability int // 顽强触发概率 - Revival bool // 回神特性 - RevivalProbability int // 回神触发概率 + // // 特殊属性 + // Perseverance int // 毅力值:抵消致命伤 + // Stubborn bool // 顽强特性 + // StubbornProbability int // 顽强触发概率 + // Revival bool // 回神特性 + // RevivalProbability int // 回神触发概率 - Definitely int // 必定命中概率 - Dodge int // 闪避概率 + // Definitely int // 必定命中概率 + // Dodge int // 闪避概率 - // 护盾相关 - MaxShield int64 // 最大护盾值 - Shield int64 // 当前护盾值 - CountShield int // 次数盾 + // // 护盾相关 + // MaxShield int64 // 最大护盾值 + // Shield int64 // 当前护盾值 + // CountShield int // 次数盾 + // Level int64 + // // 属性变化回合 + // //petAttributeRound map[BattleRoundStarEffect]int // 属性变化类型 -> 剩余回合 + // petImmunityEffectIds map[int]int // 免疫效果ID -> 剩余回合 (-1表示永久) + // petImmunityBuffs map[string]int // 免疫buff效果ID -> 剩余回合 (-1表示永久) - // 属性变化回合 - //petAttributeRound map[BattleRoundStarEffect]int // 属性变化类型 -> 剩余回合 - petImmunityEffectIds map[int]int // 免疫效果ID -> 剩余回合 (-1表示永久) - petImmunityBuffs map[string]int // 免疫buff效果ID -> 剩余回合 (-1表示永久) - - IsDead bool // 是否死亡 - otherRates map[DamageMultiplierZone]decimal.Decimal // 各伤害乘算区倍率,使用高精度decimal + // IsDead bool // 是否死亡 + // otherRates map[DamageMultiplierZone]decimal.Decimal // 各伤害乘算区倍率,使用高精度decimal // 战斗开始时拥有的特殊buff //battleStartHavingBuffs []buff.BattleBuffInterface } -func (b *BattlePetEntity) GetSpeed() uint32 { - - b.calculateRealValue(int64(b.Speed), b.speedStat) - - return 0 - -} - // calculateRealValue 计算实际属性值根据状态变化计算实际值 // value 基础属性值 // stat 状态变化值(可正可负) // 返回// 返回计算后的实际属性值,确保结果至少为1 -func (b *BattlePetEntity) calculateRealValue(value int64, stat int) int64 { +func calculateRealValue(value int64, stat int) int64 { if stat == 0 { if value <= 0 { return 1 @@ -99,108 +107,18 @@ func (b *BattlePetEntity) calculateRealValue(value int64, stat int) int64 { } } -func CalculatePower(random *rand.Rand, context *DamageContext, isCritical bool) int64 { +// 新建一个宠物 +func (u *BattlePetEntity) NewBattleSkillEntity(ctx context.Context, id, pp int) { + + ret := CreateBattleSkillWithInfinity(id, pp) //创建PP + ctx = context.WithValue(ctx, "pet", &ret) //添加用户到上下文 + ret.ctx = ctx } -// Calculate 伤害计算函数,返回最终伤害整数值 -func Calculate(random *rand.Rand, context *DamageContext, isCritical bool) int64 { - // 初始化随机值,范围217~255 - if context.RandomValue() == -1 { - context.SetRandomValue(random.Intn(39) + 217) - } +func (u *BattlePetEntity) Type() element.ElementType { - // 1. 计算等级因子 (level * 0.4 + 2) - levelFactor := decimal.NewFromInt(context.attackerPet.Level()).Mul(decimal.NewFromFloat(0.4)).Add(decimal.NewFromInt(2)) + //todo 待实现获取精灵的类型 - // 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() + return element.ElementType(0) } - -// func CalculateDamage(attacker, defender *BattleUnit, power int, isCritical bool, r *rand.Rand) int { -// randomFactor := float64(r.Intn(39)+217) / 255.0 -// levelZone := float64(attacker.Level*2) / float64(attacker.Level+defender.Level) -// base := ((float64(attacker.Atk) * float64(power) / float64(defender.Def)) / 50.0) + 2 - -// crit := 1.0 -// if isCritical { -// crit = 1.5 -// } - -// damage := int((base*levelZone*randomFactor)*crit + 0.5) -// if damage < 1 { -// damage = 1 -// } -// return damage -// } diff --git a/logic/service/fight/info/BattleSkillEntity.go b/logic/service/fight/info/BattleSkillEntity.go index 9dc6a6ad1..1760ab0e9 100644 --- a/logic/service/fight/info/BattleSkillEntity.go +++ b/logic/service/fight/info/BattleSkillEntity.go @@ -1,47 +1,50 @@ package info import ( + element "blazing/common/data/Element" "blazing/common/data/xml/skill" + "blazing/logic/service/fight/battle/random" "context" "fmt" "strconv" "strings" "github.com/gogf/gf/v2/os/glog" + "github.com/shopspring/decimal" "github.com/tnnmigga/enum" ) // EnumSkillType 技能类型枚举基础类型 -type EnumSkillType int +type EnumCategory int // SkillType 技能类型枚举实例(使用enum包创建) // 与原Java枚举保持相同的数值映射:PHYSICAL=1, SPECIAL=2, STATUS=4 -var SkillType = enum.New[struct { - PHYSICAL EnumSkillType `enum:"1"` // 物理攻击 - SPECIAL EnumSkillType `enum:"2"` // 特殊攻击 - STATUS EnumSkillType `enum:"4"` // 状态技能 +var Category = enum.New[struct { + PHYSICAL EnumCategory `enum:"1"` // 物理攻击 + SPECIAL EnumCategory `enum:"2"` // 特殊攻击 + STATUS EnumCategory `enum:"4"` // 状态技能 }]() // BattleSkillEntity 战斗技能实体 // 实现了战斗中技能的所有属性和行为,包括PP管理、技能使用、属性获取等 +// 战斗中可以修改技能实体值,比如是否暴击,是否必中等 type BattleSkillEntity struct { skill.Move - SideEffects []int - SideEffectArgs []int - PP int - InfinityPP bool + ctx context.Context + SideEffects []int + SideEffectArgs []int + PP int + InfinityPP bool + DamageMultiplierZone map[DamageMultiplierZone]float64 + isCritical bool //技能是否暴击 // 技能类型属性 - SkillType EnumSkillType // 技能类型(物理/特殊/状态) + //SkillType EnumCategory // 技能类型(物理/特殊/状态) } -// CreateBattleSkill 创建战斗技能实例 -func CreateBattleSkill(id int64, pp int) *BattleSkillEntity { - return CreateBattleSkillWithInfinity(id, pp, false) -} - // CreateBattleSkillWithInfinity 创建战斗技能实例(可指定是否无限PP) -func CreateBattleSkillWithInfinity(id int64, pp int, infinityPP bool) *BattleSkillEntity { +func CreateBattleSkillWithInfinity(id int, pp int) *BattleSkillEntity { + //如果PP是-1 ,那就是无限PP // ID小于10001的视为无效技能 if id < 10001 { return nil @@ -62,7 +65,7 @@ func CreateBattleSkillWithInfinity(id int64, pp int, infinityPP bool) *BattleSki } ret.SideEffectArgs = sideEffectArgs - + ret.DamageMultiplierZone = make(map[DamageMultiplierZone]float64) return &ret } @@ -88,6 +91,16 @@ func (s *BattleSkillEntity) CanUse() bool { return s.PP > 0 } +// 获取技能类型 +func (s *BattleSkillEntity) Category() EnumCategory { + return EnumCategory(s.Move.Category) +} + +// 获取技能属性 +func (s *BattleSkillEntity) Type() element.ElementType { + return element.ElementType(s.Move.Type) +} + // UseOnce 使用一次技能(消耗1点PP) func (s *BattleSkillEntity) UseOnce() *BattleSkillEntity { if !s.InfinityPP { @@ -123,6 +136,13 @@ func (s *BattleSkillEntity) correctPP() { s.PP = s.MaxPP } } +func (u *BattleSkillEntity) NewBattleAction(ctx context.Context) { + + ret := BattleAction{} + ctx = context.WithValue(ctx, "skill", &ret) //添加用户到上下文 + ret.ctx = ctx + +} // 解析副作用参数字符串为整数列表 func parseSideEffectArgs(argsStr string) []int { @@ -157,3 +177,138 @@ func getSideEffects(move *BattleSkillEntity) []int { } return move.SideEffects } + +// DamageMultiplierZone 伤害乘算区枚举,使用enum包定义 +type DamageMultiplierZone int + +var DamageMultiplierZoneEnum = enum.New[struct { + POWER_ADD DamageMultiplierZone // 威力加算区,直接加成威力值 + POWER_MUL DamageMultiplierZone // 威力乘算区,倍率调整(如威力倍数) + SPECIAL_EFFECT_MUL DamageMultiplierZone //殊效果乘算区, 例如Boss伤害减免或哈莫雷特的非对应顺序技能攻击为0, 此系数默认为1 + ATK_RESISTANCE DamageMultiplierZone //攻击伤害减免系数乘区, 默认为1, 减伤50%等效于将这个系数设置为0.5, 同种类取最高 + SP_ATK_RESISTANCE DamageMultiplierZone //特殊攻击伤害减免系数乘区, 默认为1, 减伤50%等效于将这个系数设置为0.5, 同种类取最高 + ATTACK_COUNT_ZONE DamageMultiplierZone //攻击次数 + DEFENSE_ZONE DamageMultiplierZone //固定伤害减免 + SP_DEFENSE_ZONE DamageMultiplierZone //物伤减免 + ATK_DEFENSE_ZONE DamageMultiplierZone //特伤减免 + Critical_ZONE DamageMultiplierZone //暴击乘区 +}]() + +func (s *BattleSkillEntity) Random() *random.RandomXS128 { + battle, _ := s.ctx.Value("battle").(*BattleContainer1V1) + + return battle.Rand + +} + +func (s *BattleSkillEntity) Pet() (*BattlePetEntity, bool) { + pet, ok := s.ctx.Value("pet").(*BattlePetEntity) + + return pet, ok + +} + +// 暴击伤害 返回暴击率和是否暴击 +func (s *BattleSkillEntity) CriticalRate() decimal.Decimal { + + return decimal.NewFromFloat(2) + +} + +// 计算技能威力 +func (s *BattleSkillEntity) CalculatePower(p *BattlePetEntity) int64 { + + //这里应该算上威力区 + // 初始化随机值,范围217~255 + + randomnum := s.Random().NextLongN(39) + 217 + + pet, _ := s.Pet() + + // 1. 计算等级因子 (level * 0.4 + 2) + levelFactor := decimal.NewFromInt(int64(pet.Level)). + Mul(decimal.NewFromFloat(0.4)).Add(decimal.NewFromInt(2)) + + // 2. 计算威力因子 (基础威力 + 加算) * 乘算 + + powerAdd := decimal.NewFromFloat(s.DamageMultiplierZone[DamageMultiplierZoneEnum.POWER_ADD]) //威力加算区 + + powerMul := decimal.NewFromFloat(s.DamageMultiplierZone[DamageMultiplierZoneEnum.POWER_MUL]) //威力乘算区 + powerZone := decimal.NewFromInt(int64(s.Power)).Add(powerAdd).Mul(powerMul) + + var ( + attackDec decimal.Decimal //攻击值 + defenseDec decimal.Decimal //防御值 + damageReduction decimal.Decimal //伤害百分比减免 + ) + switch s.Category() { //判断技能类型 + case Category.PHYSICAL: + attackDec = decimal.NewFromInt(int64(pet.UnitAttributes[AttrType.Attack].Value())) + defenseDec = decimal.NewFromInt(int64(p.UnitAttributes[AttrType.Defense].Value())) + damageReduction = decimal.NewFromFloat(s.DamageMultiplierZone[DamageMultiplierZoneEnum.ATK_RESISTANCE]) + + case Category.SPECIAL: + attackDec = decimal.NewFromInt(int64(pet.UnitAttributes[AttrType.Attack].Value())) + defenseDec = decimal.NewFromInt(int64(p.UnitAttributes[AttrType.Speed].Value())) + damageReduction = decimal.NewFromFloat(s.DamageMultiplierZone[DamageMultiplierZoneEnum.SP_ATK_RESISTANCE]) + } + //攻击次数结算 + attackCount := decimal.NewFromFloat(s.DamageMultiplierZone[DamageMultiplierZoneEnum.ATTACK_COUNT_ZONE]) + // 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 s.Type() == pet.Type() { + sameTypeBonus = decimal.NewFromFloat(1.5) + } + + // 7. 属性克制倍率(示例写死1.2,实际业务中请替换成具体逻辑) + t, _ := element.NewElementCalculator().GetOffensiveMultiplier(int(pet.Type()), int(pet.Type())) + + typeRate := decimal.NewFromFloat(t) + + // 8. 暴击倍率(暴击时使用暴击倍率,否则1) + + criticalRate := decimal.NewFromFloat(1.0) + if s.isCritical { + criticalRate = s.CriticalRate() + } + + // 9. 技能特殊效果倍率 + specialEffect := decimal.NewFromFloat(s.DamageMultiplierZone[DamageMultiplierZoneEnum.SPECIAL_EFFECT_MUL]) + + // 10. 随机倍率,随机值除以255 + randomFactor := decimal.NewFromInt(int64(randomnum)).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 := decimal.NewFromFloat(s.DamageMultiplierZone[DamageMultiplierZoneEnum.DEFENSE_ZONE]) + if fixReduction.GreaterThan(decimal.Zero) { + damage = damage.Sub(fixReduction) + if damage.LessThan(decimal.Zero) { + damage = decimal.Zero + } + } + + // 返回最终伤害(整数部分) + return damage.IntPart() + +} diff --git a/logic/service/fight/info/NoteReadyToFightInfo.go b/logic/service/fight/info/NoteReadyToFightInfo.go index fff871c3a..d71b8c336 100644 --- a/logic/service/fight/info/NoteReadyToFightInfo.go +++ b/logic/service/fight/info/NoteReadyToFightInfo.go @@ -4,6 +4,15 @@ import ( "blazing/modules/blazing/model" ) +type FightUserInfo struct { + // 用户ID(野怪为0),对应Java的@UInt long + UserID uint32 `fieldDesc:"userID 如果为野怪则为0" ` + + // 玩家名称(野怪为UTF-8的'-',固定16字节) + // 使用[16]byte存储固定长度的字节数组 + Nickname [16]byte ` ` +} + // NoteReadyToFightInfo 战斗准备就绪消息结构体,对应Java的NoteReadyToFightInfo type NoteReadyToFightInfo struct { //战斗发起者ID diff --git a/logic/service/fight/info/battle.go b/logic/service/fight/info/battle.go new file mode 100644 index 000000000..fc6c60b3e --- /dev/null +++ b/logic/service/fight/info/battle.go @@ -0,0 +1,13 @@ +package info + +import ( + "blazing/logic/service/fight/battle/random" +) + +type BattleContext struct { + Rand *random.RandomXS128 + same []BattleInputSourceEntity //同阵营 + Round int //回合数 + + opposite []BattleInputSourceEntity //不同阵营 +} diff --git a/logic/service/fight/info/battle_1v1.go b/logic/service/fight/info/battle_1v1.go new file mode 100644 index 000000000..881765f9a --- /dev/null +++ b/logic/service/fight/info/battle_1v1.go @@ -0,0 +1,45 @@ +package info + +import ( + "blazing/logic/service/fight/battle/random" + + "context" + "time" +) + +type BattleContainer1V1 struct { + BattleContext + ownerid uint32 +} + +// 返回房主信息 +func (b *BattleContainer1V1) Owner() *BattleInputSourceEntity { + + return &b.same[0] +} + +// 返回邀请者信息,比如野怪 +func (b *BattleContainer1V1) Target() *BattleInputSourceEntity { + + return &b.opposite[0] +} +func NewBattleContainer1v1(i NoteReadyToFightInfo) *BattleContainer1V1 { + + ret := BattleContainer1V1{} + ret.same = make([]BattleInputSourceEntity, 0) //初始化本阵营 + ret.opposite = make([]BattleInputSourceEntity, 0) //初始化敌方阵营 + + ret.same = append(ret.same, BattleInputSourceEntity{ + FightUserInfo: i.OurInfo, + }) //添加战斗实体 + ret.opposite = append(ret.same, BattleInputSourceEntity{ + FightUserInfo: i.OpponentInfo, + }) + ret.ownerid = i.OwnerID //房主ID + + ret.Rand = random.NewRandomXS128WithTwoSeeds(uint64(ret.ownerid), uint64(time.Now().Unix())) + ctx := context.Background() + context.WithValue(ctx, "battle", &ret) //传入容器的上下文 + + return &ret +}