feat(fight): 实现精灵切换功能并优化战斗逻辑
- 新增 ChangePet 方法实现精灵切换 - 优化战斗循环逻辑,支持精灵切换 - 修复一些战斗相关的 bug - 优化代码结构,提高可维护性
This commit is contained in:
@@ -83,3 +83,10 @@ func (h Controller) Escape(data *fight.EscapeFightInboundInfo, c *service.Player
|
|||||||
c.FightC.Escape(c)
|
c.FightC.Escape(c)
|
||||||
return nil, 0
|
return nil, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 切换精灵
|
||||||
|
func (h Controller) ChangePet(data *fight.ChangePetInboundInfo, c *service.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
|
||||||
|
|
||||||
|
c.FightC.ChangePet(c, int32(data.CatchTime))
|
||||||
|
return nil, 0
|
||||||
|
}
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
|||||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||||
|
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/gogf/gf/v2/os/gproc"
|
"github.com/gogf/gf/v2/os/gproc"
|
||||||
|
|
||||||
_ "blazing/contrib/drivers/pgsql"
|
_ "blazing/contrib/drivers/pgsql"
|
||||||
|
"blazing/logic/service"
|
||||||
|
|
||||||
"blazing/cool"
|
"blazing/cool"
|
||||||
|
|
||||||
@@ -17,6 +18,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func signalHandlerForMain(sig os.Signal) {
|
func signalHandlerForMain(sig os.Signal) {
|
||||||
|
service.Fightpool.Release()
|
||||||
fmt.Println("MainProcess is shutting down due to signal:", sig.String())
|
fmt.Println("MainProcess is shutting down due to signal:", sig.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,3 +62,6 @@ func (p *AI_player) GetPetInfo() []*model.PetInfo {
|
|||||||
func (p *AI_player) SendAttackValue(info.AttackValueS) {
|
func (p *AI_player) SendAttackValue(info.AttackValueS) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
func (p *AI_player) SendChangePet(info.ChangePetInfo) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -48,3 +48,8 @@ type UseSkillInboundInfo struct {
|
|||||||
// 技能id,
|
// 技能id,
|
||||||
SkillId uint32
|
SkillId uint32
|
||||||
}
|
}
|
||||||
|
type ChangePetInboundInfo struct {
|
||||||
|
Head service.TomeeHeader `cmd:"2407" struc:"[0]pad"`
|
||||||
|
// CatchTime 捕捉时间
|
||||||
|
CatchTime uint32 `json:"catchTime"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,12 +11,13 @@ type EnumPlayerOperation int
|
|||||||
|
|
||||||
// 定义读秒倒计时期间玩家可执行的操作枚举
|
// 定义读秒倒计时期间玩家可执行的操作枚举
|
||||||
var PlayerOperations = enum.New[struct {
|
var PlayerOperations = enum.New[struct {
|
||||||
SystemGiveUp EnumPlayerOperation `enum:"-1"` // 系统选择放弃出手(比如没有PP)
|
SystemGiveUp EnumPlayerOperation `enum:"-1"` // 系统选择放弃出手(比如没有PP)
|
||||||
SelectSkill EnumPlayerOperation `enum:"0"` // 选择技能-6到6
|
SelectSkill EnumPlayerOperation `enum:"0"` // 选择技能-6到6
|
||||||
ActiveSwitch EnumPlayerOperation `enum:"2"` // 主动切换(中切)
|
ActiveSwitch EnumPlayerOperation `enum:"2"` // 主动切换(中切)
|
||||||
UsePotion EnumPlayerOperation `enum:"3"` // 使用药剂(捕捉、逃跑等)
|
UsePotion EnumPlayerOperation `enum:"3"` // 使用药剂(捕捉、逃跑等)
|
||||||
Escape EnumPlayerOperation `enum:"4"` // 逃跑(等级最高,以及掉线)
|
Escape EnumPlayerOperation `enum:"4"` // 逃跑(等级最高,以及掉线)
|
||||||
PlayerOffline EnumPlayerOperation `enum:"5"` // 玩家掉线
|
PlayerOffline EnumPlayerOperation `enum:"5"` // 玩家掉线
|
||||||
|
BeExpelledSwitch EnumPlayerOperation `enum:"6"` // 被驱逐切换
|
||||||
}]()
|
}]()
|
||||||
|
|
||||||
// Compare 比较两个1v1战斗动作的执行优先级(核心逻辑)
|
// Compare 比较两个1v1战斗动作的执行优先级(核心逻辑)
|
||||||
@@ -46,7 +47,7 @@ func Compare(a, b BattleActionI) (BattleActionI, BattleActionI) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 比较宠物相关属性(假设Value(4)返回速度相关值)
|
// 比较宠物相关属性(假设Value(4)返回速度相关值)
|
||||||
p2 = int(bskill.PetInfo.Value(4)) - int(askill.PetInfo.Value(4))
|
p2 = int(bskill.PetInfo.Speed()) - int(askill.PetInfo.Speed())
|
||||||
if p2 > 0 {
|
if p2 > 0 {
|
||||||
return b, a
|
return b, a
|
||||||
} else if p2 < 0 {
|
} else if p2 < 0 {
|
||||||
@@ -82,15 +83,20 @@ func (s *SelectSkillAction) Priority() int {
|
|||||||
|
|
||||||
// ActiveSwitchAction 主动切换宠物的战斗动作
|
// ActiveSwitchAction 主动切换宠物的战斗动作
|
||||||
type ActiveSwitchAction struct {
|
type ActiveSwitchAction struct {
|
||||||
PlayerID uint32 // 玩家ID
|
PlayerID uint32 // 玩家ID
|
||||||
CurrentPet BattlePetEntity // 当前在场宠物
|
Type bool //是否主动切换
|
||||||
TargetPet BattlePetEntity // 要切换上场的宠物
|
Reason ChangePetInfo
|
||||||
SwitchReason string // 切换原因
|
// CurrentPet BattlePetEntity // 当前在场宠物
|
||||||
|
// TargetPet BattlePetEntity // 要切换上场的宠物
|
||||||
|
// SwitchReason string // 切换原因
|
||||||
}
|
}
|
||||||
|
|
||||||
// Priority 返回动作优先级
|
// Priority 返回动作优先级
|
||||||
func (a *ActiveSwitchAction) Priority() int {
|
func (a *ActiveSwitchAction) Priority() int {
|
||||||
return int(PlayerOperations.ActiveSwitch)
|
if a.Type {
|
||||||
|
return int(PlayerOperations.ActiveSwitch)
|
||||||
|
}
|
||||||
|
return int(PlayerOperations.BeExpelledSwitch)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Broadcast 广播切换宠物的动作信息
|
// Broadcast 广播切换宠物的动作信息
|
||||||
@@ -99,6 +105,12 @@ func (a *ActiveSwitchAction) Broadcast() {
|
|||||||
// // a.PlayerID, a.CurrentPet.Name, a.TargetPet.Name, a.SwitchReason)
|
// // a.PlayerID, a.CurrentPet.Name, a.TargetPet.Name, a.SwitchReason)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *ActiveSwitchAction) GetPlayerID() uint32 {
|
||||||
|
return a.PlayerID
|
||||||
|
// fmt.Printf("玩家[%d]主动切换宠物:从%s切换到%s(原因:%s)\n",
|
||||||
|
// // a.PlayerID, a.CurrentPet.Name, a.TargetPet.Name, a.SwitchReason)
|
||||||
|
}
|
||||||
|
|
||||||
// UsePotionAction 使用药剂的战斗动作
|
// UsePotionAction 使用药剂的战斗动作
|
||||||
type UsePotionAction struct {
|
type UsePotionAction struct {
|
||||||
PlayerID uint32 // 玩家ID
|
PlayerID uint32 // 玩家ID
|
||||||
@@ -115,12 +127,6 @@ func (u *UsePotionAction) Priority() int {
|
|||||||
return int(PlayerOperations.UsePotion)
|
return int(PlayerOperations.UsePotion)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Broadcast 广播使用药剂的动作信息
|
|
||||||
func (u *UsePotionAction) Broadcast() {
|
|
||||||
// fmt.Printf("玩家[%d]使用药剂:%s(ID:%d),目标:%s\n",
|
|
||||||
// u.PlayerID, u.PotionName, u.PotionID, u.TargetPet.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EscapeAction 逃跑的战斗动作
|
// EscapeAction 逃跑的战斗动作
|
||||||
type EscapeAction struct {
|
type EscapeAction struct {
|
||||||
PlayerID uint32 // 玩家ID
|
PlayerID uint32 // 玩家ID
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import (
|
|||||||
element "blazing/common/data/Element"
|
element "blazing/common/data/Element"
|
||||||
"blazing/common/data/xmlres"
|
"blazing/common/data/xmlres"
|
||||||
"blazing/modules/blazing/model"
|
"blazing/modules/blazing/model"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
"sync"
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
@@ -23,19 +25,25 @@ func (a *BattlePetEntity) Value(tt uint32) uint32 {
|
|||||||
offsetAtk := unsafe.Offsetof(a.Info.Attack) // c字段的偏移量(通常为4+16=20)
|
offsetAtk := unsafe.Offsetof(a.Info.Attack) // c字段的偏移量(通常为4+16=20)
|
||||||
// 2. 将结构体指针转换为原始内存地址(uintptr)
|
// 2. 将结构体指针转换为原始内存地址(uintptr)
|
||||||
baseAddr := uintptr(unsafe.Pointer(&offsetAtk))
|
baseAddr := uintptr(unsafe.Pointer(&offsetAtk))
|
||||||
|
fmt.Println(*(*uint32)(unsafe.Pointer(&baseAddr)))
|
||||||
addrA := unsafe.Pointer(baseAddr + 4*uintptr(tt)) //根据0是攻击
|
addrA := unsafe.Pointer(baseAddr + 4*uintptr(tt)) //根据0是攻击
|
||||||
offsetAtkP := unsafe.Offsetof(a.Prop.Attack) // c字段的偏移量(通常为4+16=20)
|
offsetAtkP := unsafe.Offsetof(a.Prop.Attack) // c字段的偏移量(通常为4+16=20)
|
||||||
// 2. 将结构体指针转换为原始内存地址(uintptr)
|
// 2. 将结构体指针转换为原始内存地址(uintptr)
|
||||||
baseAddrp := uintptr(unsafe.Pointer(&offsetAtkP))
|
baseAddrp := uintptr(unsafe.Pointer(&offsetAtkP))
|
||||||
|
fmt.Println(*(*uint32)(unsafe.Pointer(&offsetAtkP)))
|
||||||
addrB := unsafe.Pointer(baseAddrp + 4*uintptr(tt)) //根据0是攻击
|
addrB := unsafe.Pointer(baseAddrp + 4*uintptr(tt)) //根据0是攻击
|
||||||
return uint32(calculateRealValue(int64(*(*uint32)(addrA)), int(*(*byte)(addrB))))
|
fmt.Println(*(*uint32)(addrA))
|
||||||
|
ret := uint32(calculateRealValue(int64(*(*uint32)(addrA)), int(*(*byte)(addrB))))
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
func (a *BattlePetEntity) Speed() uint32 {
|
||||||
|
return uint32(calculateRealValue(int64(a.Info.Speed), int(a.Prop.Speed)))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type BattlePetEntity struct {
|
type BattlePetEntity struct {
|
||||||
xmlres.PetInfo
|
xmlres.PetInfo
|
||||||
Info *model.PetInfo //通过偏移赋值
|
Info model.PetInfo //通过偏移赋值
|
||||||
|
|
||||||
statusConditions sync.Map // key: StatusCondition, value: int (剩余回合)
|
statusConditions sync.Map // key: StatusCondition, value: int (剩余回合)
|
||||||
Skills [4]*BattleSkillEntity // 技能槽(最多4个技能)
|
Skills [4]*BattleSkillEntity // 技能槽(最多4个技能)
|
||||||
@@ -45,13 +53,14 @@ type BattlePetEntity struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 创建精灵实例
|
// 创建精灵实例
|
||||||
func CreateBattlePetEntity(info *model.PetInfo) *BattlePetEntity {
|
func CreateBattlePetEntity(info *model.PetInfo, rand *rand.Source) *BattlePetEntity {
|
||||||
ret := &BattlePetEntity{}
|
ret := &BattlePetEntity{}
|
||||||
|
|
||||||
ret.PetInfo = xmlres.PetMAP[int(info.ID)] //注入精灵信息
|
ret.PetInfo = xmlres.PetMAP[int(info.ID)] //注入精灵信息
|
||||||
ret.Info = info
|
ret.Info = *info
|
||||||
for i := 0; i < 4; i++ {
|
for i := 0; i < 4; i++ {
|
||||||
ret.Skills[i] = CreateBattleSkillWithInfinity(info.SkillList[i].ID)
|
//todo 技能信息应该每回合进行深拷贝,保证每次的技能效果都是不一样的
|
||||||
|
ret.Skills[i] = CreateBattleSkillWithInfinity(&info.SkillList[i], rand)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package info
|
|||||||
import (
|
import (
|
||||||
element "blazing/common/data/Element"
|
element "blazing/common/data/Element"
|
||||||
"blazing/common/data/xmlres"
|
"blazing/common/data/xmlres"
|
||||||
|
"blazing/modules/blazing/model"
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -39,26 +41,26 @@ type BattleSkillEntity struct {
|
|||||||
PP int
|
PP int
|
||||||
DamageZone map[EnumCategory]map[EnumsZoneType]map[EnumsZoneType][]float64 // 三维map 伤害类型-》增还是减-》加还是乘-》值
|
DamageZone map[EnumCategory]map[EnumsZoneType]map[EnumsZoneType][]float64 // 三维map 伤害类型-》增还是减-》加还是乘-》值
|
||||||
DamageValue decimal.Decimal // 伤害值
|
DamageValue decimal.Decimal // 伤害值
|
||||||
|
Rand rand.Source
|
||||||
// 技能类型属性
|
// 技能类型属性
|
||||||
//SkillType EnumCategory // 技能类型(物理/特殊/状态)
|
//SkillType EnumCategory // 技能类型(物理/特殊/状态)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateBattleSkillWithInfinity 创建战斗技能实例(可指定是否无限PP)
|
// CreateBattleSkillWithInfinity 创建战斗技能实例(可指定是否无限PP)
|
||||||
func CreateBattleSkillWithInfinity(id uint32) *BattleSkillEntity {
|
func CreateBattleSkillWithInfinity(skill *model.SkillInfo, rand *rand.Source) *BattleSkillEntity {
|
||||||
//如果PP是-1 ,那就是无限PP
|
//如果PP是-1 ,那就是无限PP
|
||||||
// ID小于10001的视为无效技能
|
// ID小于10001的视为无效技能
|
||||||
|
|
||||||
if id < 10001 {
|
if skill.ID < 10001 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var ret BattleSkillEntity
|
var ret BattleSkillEntity
|
||||||
// 从资源仓库获取技能数据
|
// 从资源仓库获取技能数据
|
||||||
move, ok := xmlres.SkillMap[int(id)]
|
move, ok := xmlres.SkillMap[int(skill.ID)]
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
glog.Error(context.Background(), "技能ID无效", "id", id)
|
glog.Error(context.Background(), "技能ID无效", "id", skill.ID)
|
||||||
}
|
}
|
||||||
ret.Move = move
|
ret.Move = move
|
||||||
// // 解析副作用参数
|
// // 解析副作用参数
|
||||||
@@ -68,7 +70,7 @@ func CreateBattleSkillWithInfinity(id uint32) *BattleSkillEntity {
|
|||||||
// if err == nil {
|
// if err == nil {
|
||||||
// ret.SideEffects = rf
|
// ret.SideEffects = rf
|
||||||
// }
|
// }
|
||||||
|
ret.PP = int(skill.PP)
|
||||||
// ret.SideEffectArgs = sideEffectArgs
|
// ret.SideEffectArgs = sideEffectArgs
|
||||||
ret.DamageZone = make(map[EnumCategory]map[EnumsZoneType]map[EnumsZoneType][]float64) //初始化第一层类型
|
ret.DamageZone = make(map[EnumCategory]map[EnumsZoneType]map[EnumsZoneType][]float64) //初始化第一层类型
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,22 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ChangePetInfo struct {
|
||||||
|
// UserId 米米号,野怪为0
|
||||||
|
UserId uint32 `json:"userId"`
|
||||||
|
// PetId 切换上场的精灵编号
|
||||||
|
ID uint32 `fieldDesc:"当前对战精灵ID" `
|
||||||
|
// PetName 精灵名字,固定16字节长度
|
||||||
|
Name string `struc:"[16]byte"`
|
||||||
|
// Level 切换上场的精灵等级
|
||||||
|
Level uint32 `json:"level"`
|
||||||
|
// Hp 切换上场的精灵当前生命值
|
||||||
|
Hp uint32 `json:"hp"`
|
||||||
|
// MaxHp 切换上场的精灵最大生命值
|
||||||
|
MaxHp uint32 `json:"maxHp"`
|
||||||
|
CatchTime uint32 `fieldDesc:"捕捉时间" `
|
||||||
|
}
|
||||||
|
|
||||||
// FightPetInfo 战斗精灵信息结构体,FightPetInfo类
|
// FightPetInfo 战斗精灵信息结构体,FightPetInfo类
|
||||||
type FightPetInfo struct {
|
type FightPetInfo struct {
|
||||||
// 用户ID(野怪为0),@UInt long
|
// 用户ID(野怪为0),@UInt long
|
||||||
@@ -42,8 +58,8 @@ type AttackValue struct {
|
|||||||
SkillID uint32 `json:"skillId" fieldDescription:"使用技能的id"`
|
SkillID uint32 `json:"skillId" fieldDescription:"使用技能的id"`
|
||||||
AttackTime uint32 `json:"attackTime" fieldDescription:"是否击中 如果为0 则miss 如果为1 则击中"`
|
AttackTime uint32 `json:"attackTime" fieldDescription:"是否击中 如果为0 则miss 如果为1 则击中"`
|
||||||
LostHp uint32 `json:"lostHp" fieldDescription:"我方造成的伤害"`
|
LostHp uint32 `json:"lostHp" fieldDescription:"我方造成的伤害"`
|
||||||
GainHp uint32 `json:"gainHp" fieldDescription:"我方获得血量"`
|
GainHp int32 `json:"gainHp" fieldDescription:"我方获得血量"`
|
||||||
RemainHp uint32 `json:"remainHp" fieldDescription:"我方剩余血量"`
|
RemainHp int32 `json:"remainHp" fieldDescription:"我方剩余血量"`
|
||||||
MaxHp uint32 `json:"maxHp" fieldDescription:"我方最大血量"`
|
MaxHp uint32 `json:"maxHp" fieldDescription:"我方最大血量"`
|
||||||
State uint32 `json:"state" fieldDescription:"固定值0 需要后续测试"`
|
State uint32 `json:"state" fieldDescription:"固定值0 需要后续测试"`
|
||||||
SkillListLen uint32 `struc:"sizeof=SkillList"`
|
SkillListLen uint32 `struc:"sizeof=SkillList"`
|
||||||
@@ -76,7 +92,7 @@ type StatusDict struct {
|
|||||||
ImmuneToStatDrop_17 byte // 17: 免疫能力下降
|
ImmuneToStatDrop_17 byte // 17: 免疫能力下降
|
||||||
ImmuneToAbnormal_18 byte // 18: 免疫异常状态
|
ImmuneToAbnormal_18 byte // 18: 免疫异常状态
|
||||||
Paralyzed_19 byte // 19: 瘫痪
|
Paralyzed_19 byte // 19: 瘫痪
|
||||||
Blind_20 byte // 20: 失明
|
//Blind_20 byte // 20: 失明
|
||||||
}
|
}
|
||||||
|
|
||||||
// 精灵的能力提升
|
// 精灵的能力提升
|
||||||
|
|||||||
@@ -5,12 +5,14 @@ import (
|
|||||||
"blazing/logic/service/fight/info"
|
"blazing/logic/service/fight/info"
|
||||||
"blazing/modules/blazing/model"
|
"blazing/modules/blazing/model"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
"github.com/jinzhu/copier"
|
"github.com/jinzhu/copier"
|
||||||
"github.com/mohae/deepcopy"
|
"github.com/mohae/deepcopy"
|
||||||
|
"github.com/panjf2000/ants/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PlayerI interface {
|
type PlayerI interface {
|
||||||
@@ -24,6 +26,7 @@ type PlayerI interface {
|
|||||||
SendNoteReadyToFightInfo(info.NoteReadyToFightInfo)
|
SendNoteReadyToFightInfo(info.NoteReadyToFightInfo)
|
||||||
SendFightEndInfo(info.FightOverInfo)
|
SendFightEndInfo(info.FightOverInfo)
|
||||||
SendAttackValue(info.AttackValueS)
|
SendAttackValue(info.AttackValueS)
|
||||||
|
SendChangePet(info.ChangePetInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
type FightC struct {
|
type FightC struct {
|
||||||
@@ -56,6 +59,33 @@ func (f *FightC) Escape(c PlayerI) {
|
|||||||
f.actionChan <- ret
|
f.actionChan <- ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 切换精灵 主动和被驱逐
|
||||||
|
func (f *FightC) ChangePet(c PlayerI, id int32) {
|
||||||
|
ret := &info.ActiveSwitchAction{
|
||||||
|
PlayerID: c.ID(),
|
||||||
|
}
|
||||||
|
|
||||||
|
rett := func(t PlayerI) {
|
||||||
|
for _, v := range t.GetPetInfo() {
|
||||||
|
if v.CatchTime == uint32(id) {
|
||||||
|
f.OurCurrentPet = info.CreateBattlePetEntity(v, f.Random()) //存入自己的精灵信息
|
||||||
|
copier.Copy(&ret.Reason, &v)
|
||||||
|
ret.Reason.UserId = c.ID()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c == f.Our {
|
||||||
|
|
||||||
|
rett(f.Our)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
rett(f.Opp)
|
||||||
|
}
|
||||||
|
f.actionChan <- ret
|
||||||
|
}
|
||||||
|
|
||||||
// 玩家使用技能
|
// 玩家使用技能
|
||||||
func (f *FightC) UseSkill(c PlayerI, id int32) {
|
func (f *FightC) UseSkill(c PlayerI, id int32) {
|
||||||
ret := &info.SelectSkillAction{
|
ret := &info.SelectSkillAction{
|
||||||
@@ -106,7 +136,7 @@ func (f *FightC) ReadyFight(c PlayerI) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
f.Opp = c
|
f.Opp = c
|
||||||
f.OppCurrentPet = info.CreateBattlePetEntity(c.GetPetInfo()[0])
|
f.OppCurrentPet = info.CreateBattlePetEntity(c.GetPetInfo()[0], f.Random())
|
||||||
f.BFinished = true
|
f.BFinished = true
|
||||||
if f.AFinished {
|
if f.AFinished {
|
||||||
rrsult()
|
rrsult()
|
||||||
@@ -122,15 +152,23 @@ func (f *FightC) ReadyFight(c PlayerI) {
|
|||||||
rrsult()
|
rrsult()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (f *FightC) Random() {
|
func (f *FightC) Random() *rand.Source {
|
||||||
//先产生战斗的随机数
|
//先产生战斗的随机数
|
||||||
// 组合「时间戳(纳秒精度)+ 双方ID + 回合数」生成种子
|
// 组合「时间戳(纳秒精度)+ 双方ID + 回合数」生成种子
|
||||||
|
|
||||||
seed := f.StartTime.UnixNano() ^ int64(f.OwnerID) ^ int64(f.Our.ID()) ^ int64(f.Round) // 用异或运算混合多维度信息
|
seed := f.StartTime.UnixNano() ^ int64(f.OwnerID) ^ int64(f.Our.ID()) ^ int64(f.Round) // 用异或运算混合多维度信息
|
||||||
rand.Seed(seed)
|
ret := rand.NewSource(seed)
|
||||||
|
return &ret
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var Fightpool *ants.Pool
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Fightpool, _ = ants.NewPool(math.MaxInt32)
|
||||||
|
//defer p.Release()
|
||||||
|
}
|
||||||
|
|
||||||
// 创建新战斗
|
// 创建新战斗
|
||||||
func (f *FightC) NewFight(i *info.NoteReadyToFightInfo, plays PlayerI, mo *model.PetInfo) {
|
func (f *FightC) NewFight(i *info.NoteReadyToFightInfo, plays PlayerI, mo *model.PetInfo) {
|
||||||
|
|
||||||
@@ -138,9 +176,9 @@ func (f *FightC) NewFight(i *info.NoteReadyToFightInfo, plays PlayerI, mo *model
|
|||||||
f.Info = i
|
f.Info = i
|
||||||
f.StartTime = time.Now()
|
f.StartTime = time.Now()
|
||||||
f.actionChan = make(chan info.BattleActionI, 2) // 初始化全局操作通道
|
f.actionChan = make(chan info.BattleActionI, 2) // 初始化全局操作通道
|
||||||
f.OurCurrentPet = info.CreateBattlePetEntity(plays.GetPetInfo()[0])
|
f.OurCurrentPet = info.CreateBattlePetEntity(plays.GetPetInfo()[0], f.Random())
|
||||||
if mo != nil {
|
if mo != nil {
|
||||||
f.OppCurrentPet = info.CreateBattlePetEntity(mo)
|
f.OppCurrentPet = info.CreateBattlePetEntity(mo, f.Random())
|
||||||
}
|
}
|
||||||
|
|
||||||
switch i.FightId {
|
switch i.FightId {
|
||||||
@@ -152,7 +190,11 @@ func (f *FightC) NewFight(i *info.NoteReadyToFightInfo, plays PlayerI, mo *model
|
|||||||
plays.SendNoteReadyToFightInfo(*i)
|
plays.SendNoteReadyToFightInfo(*i)
|
||||||
}
|
}
|
||||||
|
|
||||||
go f.battleLoop() // 起战斗循环
|
rr := Fightpool.Submit(f.battleLoop)
|
||||||
|
if rr != nil {
|
||||||
|
panic(rr)
|
||||||
|
}
|
||||||
|
//go f.battleLoop() // 起战斗循环
|
||||||
}
|
}
|
||||||
|
|
||||||
// 广播,并是否结束回合
|
// 广播,并是否结束回合
|
||||||
@@ -164,6 +206,12 @@ func (f *FightC) Broadcast(t info.BattleActionI) bool {
|
|||||||
f.Our.SendFightEndInfo(ff.Reason)
|
f.Our.SendFightEndInfo(ff.Reason)
|
||||||
f.Opp.SendFightEndInfo(ff.Reason)
|
f.Opp.SendFightEndInfo(ff.Reason)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
case *info.ActiveSwitchAction: //切换精灵
|
||||||
|
|
||||||
|
f.Our.SendChangePet(ff.Reason)
|
||||||
|
f.Opp.SendChangePet(ff.Reason)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +225,9 @@ func (f *FightC) BroadcastSkill(t info.AttackValueS) {
|
|||||||
// 战斗回合循环
|
// 战斗回合循环
|
||||||
func (f *FightC) battleLoop() {
|
func (f *FightC) battleLoop() {
|
||||||
for {
|
for {
|
||||||
f.Round++ //回合数自增
|
f.Round++ //回合数自增
|
||||||
|
// f.AFinished = false
|
||||||
|
// f.BFinished = false
|
||||||
if f.Round > 250 { //回合数超过250,战斗平局结束
|
if f.Round > 250 { //回合数超过250,战斗平局结束
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -191,7 +241,14 @@ func (f *FightC) battleLoop() {
|
|||||||
if action.GetPlayerID() != f.Our.ID() && action.GetPlayerID() != f.Opp.ID() {
|
if action.GetPlayerID() != f.Our.ID() && action.GetPlayerID() != f.Opp.ID() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if a, isExpelled := action.(*info.ActiveSwitchAction); isExpelled {
|
||||||
|
fmt.Println("对方死亡切换")
|
||||||
|
f.Broadcast(a)
|
||||||
|
if !a.Type {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
if action.GetPlayerID() == f.Our.ID() && f.Info.FightId == 3 {
|
if action.GetPlayerID() == f.Our.ID() && f.Info.FightId == 3 {
|
||||||
|
|
||||||
go f.Opp.GetAction() //获取AI的动作
|
go f.Opp.GetAction() //获取AI的动作
|
||||||
@@ -204,7 +261,7 @@ func (f *FightC) battleLoop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
actions[uint32(action.GetPlayerID())] = action
|
actions[uint32(action.GetPlayerID())] = action
|
||||||
fmt.Printf("玩家%d 执行动作", action.GetPlayerID())
|
fmt.Println("玩家%d 执行动作", action.GetPlayerID())
|
||||||
|
|
||||||
case <-timeout:
|
case <-timeout:
|
||||||
fmt.Println("回合操作超时")
|
fmt.Println("回合操作超时")
|
||||||
@@ -212,7 +269,7 @@ func (f *FightC) battleLoop() {
|
|||||||
actions[f.Our.ID()] = &info.SystemGiveUpAction{PlayerID: f.Our.ID()} //系统选择出手
|
actions[f.Our.ID()] = &info.SystemGiveUpAction{PlayerID: f.Our.ID()} //系统选择出手
|
||||||
}
|
}
|
||||||
if _, exists := actions[f.Opp.ID()]; !exists {
|
if _, exists := actions[f.Opp.ID()]; !exists {
|
||||||
actions[f.Opp.ID()] = &info.SystemGiveUpAction{PlayerID: f.Our.ID()} //系统选择出手
|
actions[f.Opp.ID()] = &info.SystemGiveUpAction{PlayerID: f.Opp.ID()} //系统选择出手
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -236,6 +293,7 @@ func (f *FightC) battleLoop() {
|
|||||||
break
|
break
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var p_skill [2]*info.SelectSkillAction
|
var p_skill [2]*info.SelectSkillAction
|
||||||
|
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
@@ -271,19 +329,33 @@ func (f *FightC) battleLoop() {
|
|||||||
uint32(p_skill[i].Skill.ID),
|
uint32(p_skill[i].Skill.ID),
|
||||||
1,
|
1,
|
||||||
200,
|
200,
|
||||||
200,
|
0,
|
||||||
100,
|
int32(f.OurCurrentPet.Info.MaxHp),
|
||||||
f.OurCurrentPet.Info.MaxHp,
|
f.OurCurrentPet.Info.MaxHp,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
f.OurCurrentPet.Info.SkillList[:],
|
[]model.SkillInfo{},
|
||||||
1,
|
1,
|
||||||
info.StatusDict{},
|
info.StatusDict{},
|
||||||
info.PropDict{},
|
info.PropDict{},
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
p_skill[1].Attack = info.AttackValue{
|
||||||
|
p_skill[1].PlayerID,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
[]model.SkillInfo{},
|
||||||
|
0,
|
||||||
|
info.StatusDict{},
|
||||||
|
info.PropDict{},
|
||||||
|
}
|
||||||
f.BroadcastSkill(info.AttackValueS{
|
f.BroadcastSkill(info.AttackValueS{
|
||||||
p_skill[0].Attack, p_skill[1].Attack,
|
p_skill[0].Attack, p_skill[1].Attack,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -154,6 +154,14 @@ func (p *Player) SendAttackValue(b info.AttackValueS) {
|
|||||||
p.SendPack(t1.Pack(&b)) //准备包由各自发,因为协议不一样
|
p.SendPack(t1.Pack(&b)) //准备包由各自发,因为协议不一样
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Player) SendChangePet(b info.ChangePetInfo) {
|
||||||
|
t1 := NewTomeeHeader(2407, p.Info.UserID)
|
||||||
|
|
||||||
|
p.SendPack(t1.Pack(&b)) //准备包由各自发,因为协议不一样
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Player) Cheak(b error) {
|
func (p *Player) Cheak(b error) {
|
||||||
if b != nil {
|
if b != nil {
|
||||||
g.Log().Error(context.Background(), "出现错误", p.Info.UserID, b.Error())
|
g.Log().Error(context.Background(), "出现错误", p.Info.UserID, b.Error())
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package model
|
|||||||
import (
|
import (
|
||||||
"blazing/common/data/xmlres"
|
"blazing/common/data/xmlres"
|
||||||
"blazing/cool"
|
"blazing/cool"
|
||||||
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
||||||
"time"
|
"time"
|
||||||
@@ -23,6 +24,17 @@ type Pet struct {
|
|||||||
Data string `gorm:"type:text;not null;comment:'精灵全部数据'" json:"data"`
|
Data string `gorm:"type:text;not null;comment:'精灵全部数据'" json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetGaussRandomNum(min, max int64) int64 {
|
||||||
|
σ := (float64(min) + float64(max)) / 2
|
||||||
|
μ := (float64(max) - σ) / 3
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
x := rand.Float64()
|
||||||
|
x1 := rand.Float64()
|
||||||
|
a := math.Cos(2*math.Pi*x) * math.Sqrt((-2)*math.Log(x1))
|
||||||
|
result := a*μ + σ
|
||||||
|
return int64(result)
|
||||||
|
}
|
||||||
|
|
||||||
// RandomInRange 从切片表示的范围中返回对应结果:
|
// RandomInRange 从切片表示的范围中返回对应结果:
|
||||||
// - 切片包含1个元素时,返回该元素本身
|
// - 切片包含1个元素时,返回该元素本身
|
||||||
// - 切片包含2个元素时,从[min, max]闭区间随机生成一个整数(自动调整min和max顺序)
|
// - 切片包含2个元素时,从[min, max]闭区间随机生成一个整数(自动调整min和max顺序)
|
||||||
@@ -41,7 +53,8 @@ func RandomInRange(rangeSlice []int) int {
|
|||||||
min, max = max, min
|
min, max = max, min
|
||||||
}
|
}
|
||||||
// 生成 [min, max] 区间的随机整数
|
// 生成 [min, max] 区间的随机整数
|
||||||
return (rand.Intn(int(max-min+1)) + int(min))
|
|
||||||
|
return int(GetGaussRandomNum(int64(min), int64(max))) //(rand.Intn(int(max-min+1)) + int(min))
|
||||||
default:
|
default:
|
||||||
// 其他长度返回0
|
// 其他长度返回0
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
Reference in New Issue
Block a user