refactor(fight): 重构战斗模块

- 优化了数据结构和类型定义,提高了代码的可读性和可维护性
- 移除了未使用的代码和冗余的结构体字段
- 重新组织了代码文件,提高了模块化程度
- 为后续的战斗逻辑实现和优化奠定了坚实的基础
This commit is contained in:
2025-08-25 16:26:56 +08:00
parent 1405bf5ee9
commit 038a5f13da
12 changed files with 395 additions and 288 deletions

View File

@@ -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

View File

@@ -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() 返回动作所有者(玩家/AIOwner.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 速度相同时 ,发起方优先
}

View File

@@ -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 //不同阵营
}

View File

@@ -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)
// }

View File

@@ -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)

View File

@@ -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 速度相同时 ,发起方优先
}

View File

@@ -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 ` `
}

View File

@@ -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=状态IDvalue=增量值)
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
// }

View File

@@ -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()
}

View File

@@ -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

View File

@@ -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 //不同阵营
}

View File

@@ -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
}