refactor(fight): 重构战斗模块
- 优化了数据结构和类型定义,提高了代码的可读性和可维护性 - 移除了未使用的代码和冗余的结构体字段 - 重新组织了代码文件,提高了模块化程度 - 为后续的战斗逻辑实现和优化奠定了坚实的基础
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 速度相同时 ,发起方优先
|
||||
}
|
||||
@@ -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 //不同阵营
|
||||
}
|
||||
@@ -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)
|
||||
// }
|
||||
@@ -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)
|
||||
|
||||
65
logic/service/fight/info/BattleAction.go
Normal file
65
logic/service/fight/info/BattleAction.go
Normal 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 速度相同时 ,发起方优先
|
||||
}
|
||||
@@ -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 ` `
|
||||
}
|
||||
|
||||
@@ -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
|
||||
// }
|
||||
|
||||
@@ -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()
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
13
logic/service/fight/info/battle.go
Normal file
13
logic/service/fight/info/battle.go
Normal 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 //不同阵营
|
||||
}
|
||||
45
logic/service/fight/info/battle_1v1.go
Normal file
45
logic/service/fight/info/battle_1v1.go
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user