refactor(fight): 重构战斗系统
- 优化了技能解析和存储逻辑 - 重构了战斗流程和回合结算机制 - 调整了数据结构以提高性能 - 移除了未使用的代码和注释
This commit is contained in:
@@ -49,10 +49,18 @@ func initfile() {
|
||||
})
|
||||
|
||||
Skill := getXml[MovesTbl](path + "227.xml")
|
||||
SkillMap = utils.ToMap[Move, int](Skill.Moves, func(m Move) int {
|
||||
return m.ID
|
||||
// SkillMap = utils.ToMap[Move, int](Skill.Moves, func(m Move) int {
|
||||
|
||||
// return m.ID
|
||||
|
||||
// })
|
||||
SkillMap = make(map[int]Move, len(Skill.Moves))
|
||||
for _, v := range Skill.Moves {
|
||||
v.SideEffectS = parseSideEffectArgs(v.SideEffect)
|
||||
v.SideEffectArgS = parseSideEffectArgs(v.SideEffectArg)
|
||||
SkillMap[v.ID] = v
|
||||
}
|
||||
|
||||
})
|
||||
pet := getXml[Monsters](path + "226.xml")
|
||||
PetMAP = utils.ToMap[PetInfo, int](pet.Monsters, func(m PetInfo) int {
|
||||
return m.ID
|
||||
|
||||
@@ -20,11 +20,11 @@ type PetInfo struct {
|
||||
Type int `xml:"Type,attr"` //类型
|
||||
GrowthType int `xml:"GrowthType,attr"` //成长类型
|
||||
HP int `xml:"HP,attr"` //血量种族值
|
||||
Atk int `xml:"Atk,attr"`
|
||||
Def int `xml:"Def,attr"`
|
||||
SpAtk int `xml:"SpAtk,attr"`
|
||||
SpDef int `xml:"SpDef,attr"`
|
||||
Spd int `xml:"Spd,attr"`
|
||||
Atk uint32 `xml:"Atk,attr"` //攻击种族值
|
||||
Def uint32 `xml:"Def,attr"`
|
||||
SpAtk uint32 `xml:"SpAtk,attr"`
|
||||
SpDef uint32 `xml:"SpDef,attr"`
|
||||
Spd uint32 `xml:"Spd,attr"`
|
||||
YieldingExp int `xml:"YieldingExp,attr"`
|
||||
CatchRate string `xml:"CatchRate,attr"`
|
||||
YieldingEV string `xml:"YieldingEV,attr"`
|
||||
|
||||
@@ -5,9 +5,28 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func parseSideEffectArgs(argsStr string) []int {
|
||||
if argsStr == "" {
|
||||
return []int{}
|
||||
}
|
||||
|
||||
parts := strings.Fields(argsStr)
|
||||
args := make([]int, 0, len(parts))
|
||||
|
||||
for _, part := range parts {
|
||||
if num, err := strconv.Atoi(part); err == nil {
|
||||
args = append(args, num)
|
||||
}
|
||||
}
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
// MovesTbl 定义 XML 根元素
|
||||
type MovesTbl struct {
|
||||
XMLName xml.Name `xml:"MovesTbl"`
|
||||
@@ -43,15 +62,18 @@ type Move struct {
|
||||
PwrBindDv int `xml:"PwrBindDv,attr,omitempty"` //威力(power)取决于自身的潜力(个体值)
|
||||
PwrDouble int `xml:"PwrDouble,attr,omitempty"` //攻击时,若对方处于异常状态, 则威力翻倍;
|
||||
|
||||
SideEffect string `xml:"SideEffect,attr,omitempty"`
|
||||
SideEffectArg string `xml:"SideEffectArg,attr,omitempty"`
|
||||
AtkNum int `xml:"AtkNum,attr,omitempty"`
|
||||
Url string `xml:"Url,attr,omitempty"`
|
||||
SideEffect string `xml:"SideEffect,attr,omitempty"`
|
||||
SideEffectArg string `xml:"SideEffectArg,attr,omitempty"`
|
||||
SideEffectS []int
|
||||
SideEffectArgS []int
|
||||
AtkNum int `xml:"AtkNum,attr,omitempty"`
|
||||
Url string `xml:"Url,attr,omitempty"`
|
||||
|
||||
Info string `xml:"info,attr,omitempty"`
|
||||
|
||||
CD int `xml:"CD,attr"`
|
||||
}
|
||||
|
||||
type SideEffect struct {
|
||||
ID int `xml:"ID,attr"`
|
||||
Help string `xml:"help,attr"`
|
||||
|
||||
@@ -50,6 +50,7 @@ var s = `
|
||||
func Test_main(t *testing.T) {
|
||||
|
||||
initfile()
|
||||
fmt.Println(SkillMap[10073])
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
func (h Controller) OnPlayerFightNpcMonster(data *fight.FightNpcMonsterInboundInfo, c *service.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
|
||||
|
||||
ttt := info.NoteReadyToFightInfo{
|
||||
OwnerID: data.Head.UserID,
|
||||
|
||||
FightId: 3,
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ func (h Controller) OnPlayerFightNpcMonster(data *fight.FightNpcMonsterInboundIn
|
||||
}
|
||||
c.FightC = &service.FightC{}
|
||||
c.FightC.NewFight(&ttt, c) //把两个玩家都传进去
|
||||
|
||||
c.FightC.OwnerID = c.Info.UserID
|
||||
return nil, -1
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ func (h Controller) OnPlayerHandleFightInvite(data *fight.HandleFightInviteInbou
|
||||
|
||||
// 使用技能包
|
||||
func (h Controller) UseSkill(data *fight.UseSkillInboundInfo, c *service.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
|
||||
|
||||
c.FightC.UseSkill(c, data.SkillId)
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package service
|
||||
|
||||
import (
|
||||
"blazing/logic/service/fight/info"
|
||||
"blazing/modules/blazing/model"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
@@ -22,9 +21,10 @@ func (f *AI_player) MapID() uint32 {
|
||||
panic("not implemented") // TODO: Implement
|
||||
}
|
||||
|
||||
func (f *AI_player) GetInfo() model.PlayerInfo {
|
||||
panic("not implemented") // TODO: Implement
|
||||
}
|
||||
// func (f *AI_player) GetInfo() model.PlayerInfo {
|
||||
// return f.FightC.Opp.
|
||||
|
||||
// }
|
||||
|
||||
func (f *AI_player) SendPack(b []byte) error {
|
||||
panic("not implemented") // TODO: Implement
|
||||
|
||||
@@ -77,20 +77,14 @@ func (this *EffectNode) GetSkill() *info.BattleSkillEntity {
|
||||
}
|
||||
|
||||
// 获取对方精灵
|
||||
func (this *EffectNode) GetBattle() *info.Battle1V1 {
|
||||
pet, _ := this.Ctx.Value(info.BattleContainerCtx).(*info.Battle1V1)
|
||||
|
||||
return pet
|
||||
// // 获取我方输入源
|
||||
// func (this *EffectNode) GetInput() *info.BattleInputSourceEntity {
|
||||
// pet, _ := this.Ctx.Value(info.Input_ctx).(*info.BattleInputSourceEntity)
|
||||
|
||||
}
|
||||
// return pet
|
||||
|
||||
// 获取我方输入源
|
||||
func (this *EffectNode) GetInput() *info.BattleInputSourceEntity {
|
||||
pet, _ := this.Ctx.Value(info.Input_ctx).(*info.BattleInputSourceEntity)
|
||||
|
||||
return pet
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
// 获取自身精灵
|
||||
func (this *EffectNode) GetOwnerPet() *info.BattlePetEntity {
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
package base
|
||||
|
||||
// 生命周期管理器
|
||||
type LifeCycle struct {
|
||||
remainTurn int // 剩余回合(-1 表示不限回合)
|
||||
remainCount int // 剩余次数(-1 表示不限次数)
|
||||
}
|
||||
|
||||
// 创建一个回合持续类效果
|
||||
func NewTurnLife(turns int) LifeCycle {
|
||||
return LifeCycle{remainTurn: turns, remainCount: -1}
|
||||
}
|
||||
|
||||
// 创建一个次数持续类效果
|
||||
func NewCountLife(count int) LifeCycle {
|
||||
return LifeCycle{remainTurn: -1, remainCount: count}
|
||||
}
|
||||
|
||||
// 每回合 tick
|
||||
func (lc *LifeCycle) Tick() {
|
||||
if lc.remainTurn > 0 {
|
||||
lc.remainTurn--
|
||||
}
|
||||
}
|
||||
|
||||
// 使用一次
|
||||
func (lc *LifeCycle) Use() {
|
||||
if lc.remainCount > 0 {
|
||||
lc.remainCount--
|
||||
}
|
||||
}
|
||||
|
||||
// 是否还活跃
|
||||
func (lc *LifeCycle) Alive() bool {
|
||||
return (lc.remainTurn != 0) && (lc.remainCount != 0)
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tnnmigga/enum"
|
||||
)
|
||||
|
||||
@@ -17,14 +15,18 @@ var PlayerOperations = enum.New[struct {
|
||||
ActiveSwitch EnumPlayerOperation `enum:"2"` //`enum:"主动切换(中切)"`
|
||||
|
||||
UsePotion EnumPlayerOperation `enum:"3"` //`enum:"使用药剂"` 捕捉 逃跑
|
||||
Escape EnumPlayerOperation `enum:"4"` //`enum:"使用药剂"` 逃跑 等级最高
|
||||
Escape EnumPlayerOperation `enum:"4"` //`enum:"使用药剂"` 逃跑 等级最高 ,以及掉线
|
||||
|
||||
//DeathSwitch EnumPlayerOperation `enum:"4"` //`enum:"死亡切换"` 这两个本质上还是对action的比较
|
||||
// ExpelledSwitch EnumPlayerOperation `enum:"5"` //`enum:"(被)驱逐切换"`
|
||||
}]()
|
||||
|
||||
type BattleAction struct {
|
||||
PlayerID uint32
|
||||
Priority EnumPlayerOperation //优先级本质上是action的itoa
|
||||
ctx context.Context
|
||||
Skill BattleSkillEntity
|
||||
PetInfo BattlePetEntity
|
||||
//ctx context.Context
|
||||
}
|
||||
|
||||
// Compare 比较两个1v1战斗动作的执行优先级(核心逻辑)
|
||||
@@ -39,20 +41,15 @@ func (c *BattleAction) Compare(a *BattleAction) *BattleAction {
|
||||
}
|
||||
|
||||
if a.Priority == 0 {
|
||||
skillo, _ := a.ctx.Value(BattleSkillEntityCtx).(*BattleSkillEntity)
|
||||
skillt, _ := a.ctx.Value(BattleSkillEntityCtx).(*BattleSkillEntity)
|
||||
// 使用技能
|
||||
|
||||
p2 := skillo.Priority - skillt.Priority
|
||||
p2 := a.Skill.Priority - c.Skill.Priority //对方减自己
|
||||
if p2 > 0 {
|
||||
return a
|
||||
} else if p2 < 0 {
|
||||
return c
|
||||
}
|
||||
peto, _ := a.ctx.Value(Pet_O_Ctx).(*BattlePetEntity)
|
||||
pett, _ := a.ctx.Value(Pet_O_Ctx).(*BattlePetEntity)
|
||||
|
||||
p2 = int(peto.info.Speed) - int(pett.info.Speed) // 假设 Use1v1SkillAction 有 SkillPriority() 方法
|
||||
p2 = int(a.PetInfo.Value(4)) - int(c.PetInfo.Value(4)) // 假设 Use1v1SkillAction 有 SkillPriority() 方法
|
||||
if p2 > 0 {
|
||||
return a
|
||||
} else if p2 < 0 {
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
const Input_ctx = "player"
|
||||
|
||||
type BattleInputSourceEntity struct {
|
||||
FightUserInfo //用户信息
|
||||
PetEntities []*BattlePetEntity //宠物信息
|
||||
ctx context.Context //输入源的上下文
|
||||
|
||||
}
|
||||
|
||||
// 新建一个宠物
|
||||
func (u *BattleInputSourceEntity) NewBattlePetEntity(ctx context.Context) {
|
||||
|
||||
ret := BattlePetEntity{}
|
||||
|
||||
//ret.UnitAttributes = make(map[EnumAttrType]*Attribute)
|
||||
//todo 待实现精灵特性+加成的封装
|
||||
ctx = context.WithValue(ctx, Input_ctx, &ret) //添加用户到上下文
|
||||
ret.ctx = ctx
|
||||
|
||||
}
|
||||
func (u *BattleInputSourceEntity) NewBattleAction(ctx context.Context, actiontype EnumPlayerOperation) {
|
||||
|
||||
ret := BattleAction{
|
||||
Priority: actiontype,
|
||||
}
|
||||
ctx = context.WithValue(ctx, Input_ctx, &ret) //添加用户到上下文
|
||||
ret.ctx = ctx
|
||||
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"blazing/modules/blazing/model"
|
||||
"context"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// 战斗属性类型
|
||||
@@ -15,18 +16,20 @@ type EnumAttrType int
|
||||
const Pet_O_Ctx = "PET_O"
|
||||
const Pet_T_Ctx = "PET_T"
|
||||
|
||||
// 属性封装结构:Ext 存储临时血量增量(key=状态ID,value=增量值)
|
||||
type Attribute struct {
|
||||
//CanSet bool // 是否允许修改
|
||||
originalValue int
|
||||
// 这里获得攻击,防御,特工,特防,速度
|
||||
func (a *BattlePetEntity) Value(tt uint32) uint32 {
|
||||
|
||||
Stat int //提升等级
|
||||
//Ext map[string]interface{} // 例如:{"buff_hp_123": 200} 存储临时血量增量
|
||||
}
|
||||
offsetAtk := unsafe.Offsetof(a.info.Attack) // c字段的偏移量(通常为4+16=20)
|
||||
// 2. 将结构体指针转换为原始内存地址(uintptr)
|
||||
baseAddr := uintptr(unsafe.Pointer(&offsetAtk))
|
||||
|
||||
func (a *Attribute) Value() int64 {
|
||||
addrA := unsafe.Pointer(baseAddr + 4*uintptr(tt)) //根据0是攻击
|
||||
offsetAtkP := unsafe.Offsetof(a.Prop.Attack) // c字段的偏移量(通常为4+16=20)
|
||||
// 2. 将结构体指针转换为原始内存地址(uintptr)
|
||||
baseAddrp := uintptr(unsafe.Pointer(&offsetAtkP))
|
||||
|
||||
return calculateRealValue(int64(a.originalValue), a.Stat)
|
||||
addrB := unsafe.Pointer(baseAddrp + 4*uintptr(tt)) //根据0是攻击
|
||||
return uint32(calculateRealValue(int64(*(*uint32)(addrA)), int(*(*byte)(addrB))))
|
||||
}
|
||||
|
||||
type BattlePetEntity struct {
|
||||
@@ -36,7 +39,9 @@ type BattlePetEntity struct {
|
||||
Capturable bool // 是否可捕获
|
||||
statusConditions sync.Map // key: StatusCondition, value: int (剩余回合)
|
||||
skills [4]*BattleSkillEntity // 技能槽(最多4个技能)
|
||||
|
||||
Status StatusDict //精灵的状态
|
||||
//能力提升属性
|
||||
Prop PropDict
|
||||
}
|
||||
|
||||
// calculateRealValue 计算实际属性值根据状态变化计算实际值
|
||||
@@ -64,15 +69,6 @@ func calculateRealValue(value int64, stat int) 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
|
||||
|
||||
}
|
||||
|
||||
func (u *BattlePetEntity) Type() element.ElementType {
|
||||
|
||||
//todo 待实现获取精灵的类型
|
||||
|
||||
@@ -3,12 +3,10 @@ package info
|
||||
import (
|
||||
element "blazing/common/data/Element"
|
||||
"blazing/common/data/xmlres"
|
||||
"blazing/common/utils/random"
|
||||
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
"github.com/shopspring/decimal"
|
||||
@@ -36,15 +34,11 @@ var Category = enum.New[struct {
|
||||
// 战斗中可以修改技能实体值,比如是否暴击,是否必中等
|
||||
type BattleSkillEntity struct {
|
||||
xmlres.Move
|
||||
ctx context.Context
|
||||
SideEffects []int
|
||||
SideEffectArgs []int
|
||||
PP int
|
||||
InfinityPP bool
|
||||
DamageZone map[EnumCategory]map[EnumsZoneType]map[EnumsZoneType][]float64 // 三维map 伤害类型-》增还是减-》加还是乘-》值
|
||||
|
||||
ATTACK_COUNT_ZONE int //攻击次数
|
||||
DamageValue decimal.Decimal // 伤害值
|
||||
// SideEffects []int
|
||||
// SideEffectArgs []int
|
||||
PP int
|
||||
DamageZone map[EnumCategory]map[EnumsZoneType]map[EnumsZoneType][]float64 // 三维map 伤害类型-》增还是减-》加还是乘-》值
|
||||
DamageValue decimal.Decimal // 伤害值
|
||||
|
||||
// 技能类型属性
|
||||
//SkillType EnumCategory // 技能类型(物理/特殊/状态)
|
||||
@@ -52,28 +46,30 @@ type BattleSkillEntity struct {
|
||||
}
|
||||
|
||||
// CreateBattleSkillWithInfinity 创建战斗技能实例(可指定是否无限PP)
|
||||
func CreateBattleSkillWithInfinity(id int, pp int) *BattleSkillEntity {
|
||||
func CreateBattleSkillWithInfinity(id uint32) *BattleSkillEntity {
|
||||
//如果PP是-1 ,那就是无限PP
|
||||
// ID小于10001的视为无效技能
|
||||
|
||||
if id < 10001 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var ret BattleSkillEntity
|
||||
// 从资源仓库获取技能数据
|
||||
move, ok := xmlres.SkillMap[id]
|
||||
move, ok := xmlres.SkillMap[int(id)]
|
||||
|
||||
if !ok {
|
||||
glog.Error(context.Background(), "技能ID无效", "id", id)
|
||||
}
|
||||
var ret BattleSkillEntity
|
||||
// 解析副作用参数
|
||||
sideEffectArgs := parseSideEffectArgs(move.SideEffectArg)
|
||||
tt := strings.Split(move.SideEffect, " ")
|
||||
rf, err := strSliceToIntSlice(tt)
|
||||
if err == nil {
|
||||
ret.SideEffects = rf
|
||||
}
|
||||
ret.Move = move
|
||||
// // 解析副作用参数
|
||||
// sideEffectArgs := parseSideEffectArgs(move.SideEffectArg)
|
||||
// tt := strings.Split(move.SideEffect, " ")
|
||||
// rf, err := strSliceToIntSlice(tt)
|
||||
// if err == nil {
|
||||
// ret.SideEffects = rf
|
||||
// }
|
||||
|
||||
ret.SideEffectArgs = sideEffectArgs
|
||||
// ret.SideEffectArgs = sideEffectArgs
|
||||
ret.DamageZone = make(map[EnumCategory]map[EnumsZoneType]map[EnumsZoneType][]float64) //初始化第一层类型
|
||||
|
||||
for _, v := range enum.Values[EnumCategory](Category) {
|
||||
@@ -122,15 +118,6 @@ func (s *BattleSkillEntity) Type() element.ElementType {
|
||||
return element.ElementType(s.Move.Type)
|
||||
}
|
||||
|
||||
// 技能产生动作
|
||||
func (u *BattleSkillEntity) NewBattleAction(ctx context.Context) {
|
||||
|
||||
ret := BattleAction{}
|
||||
ctx = context.WithValue(ctx, BattleSkillEntityCtx, &ret) //添加用户到上下文
|
||||
ret.ctx = ctx
|
||||
|
||||
}
|
||||
|
||||
// // 技能产生effect
|
||||
// func (u *BattleSkillEntity) NewEffect(ctx context.Context)*node.EffectNode {
|
||||
|
||||
@@ -140,22 +127,6 @@ func (u *BattleSkillEntity) NewBattleAction(ctx context.Context) {
|
||||
|
||||
// }
|
||||
// 解析副作用参数字符串为整数列表
|
||||
func parseSideEffectArgs(argsStr string) []int {
|
||||
if argsStr == "" {
|
||||
return []int{}
|
||||
}
|
||||
|
||||
parts := strings.Fields(argsStr)
|
||||
args := make([]int, 0, len(parts))
|
||||
|
||||
for _, part := range parts {
|
||||
if num, err := strconv.Atoi(part); err == nil {
|
||||
args = append(args, num)
|
||||
}
|
||||
}
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
// 获取技能名称,为空时使用ID
|
||||
func getSkillName(move *BattleSkillEntity) string {
|
||||
@@ -166,12 +137,12 @@ func getSkillName(move *BattleSkillEntity) string {
|
||||
}
|
||||
|
||||
// 获取副作用列表,处理空值情况
|
||||
func getSideEffects(move *BattleSkillEntity) []int {
|
||||
if move.SideEffect == "" {
|
||||
return []int{}
|
||||
}
|
||||
return move.SideEffects
|
||||
}
|
||||
// func getSideEffects(move *BattleSkillEntity) []int {
|
||||
// if move.SideEffect == "" {
|
||||
// return []int{}
|
||||
// }
|
||||
// return move.SideEffects
|
||||
// }
|
||||
|
||||
type EnumsZoneType int
|
||||
|
||||
@@ -185,12 +156,12 @@ var DamageC = enum.New[struct {
|
||||
reduction EnumsZoneType // 减伤区
|
||||
}]()
|
||||
|
||||
func (s *BattleSkillEntity) Random() *random.RandomXS128 {
|
||||
battle, _ := s.ctx.Value(BattleContainerCtx).(*Battle1V1)
|
||||
// func (s *BattleSkillEntity) Random() *random.RandomXS128 {
|
||||
// battle, _ := s.ctx.Value(BattleContainerCtx).(*Battle1V1)
|
||||
|
||||
return battle.Rand
|
||||
// return battle.Rand
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
// 获得指定的+-区
|
||||
func (s *BattleSkillEntity) GetAddValue(e EnumCategory, c EnumsZoneType) decimal.Decimal {
|
||||
@@ -253,12 +224,13 @@ func (s *BattleSkillEntity) PutDamageZone(e EnumCategory, dtype EnumsZoneType, v
|
||||
// }
|
||||
|
||||
}
|
||||
func (s *BattleSkillEntity) Pet() (*BattlePetEntity, bool) {
|
||||
pet, ok := s.ctx.Value(Pet_O_Ctx).(*BattlePetEntity)
|
||||
|
||||
return pet, ok
|
||||
// func (s *BattleSkillEntity) Pet() (*BattlePetEntity, bool) {
|
||||
// pet, ok := s.ctx.Value(Pet_O_Ctx).(*BattlePetEntity)
|
||||
|
||||
}
|
||||
// return pet, ok
|
||||
|
||||
// }
|
||||
|
||||
// 暴击伤害 返回暴击率和是否暴击
|
||||
func (s *BattleSkillEntity) CriticalRate() decimal.Decimal {
|
||||
@@ -267,16 +239,16 @@ func (s *BattleSkillEntity) CriticalRate() decimal.Decimal {
|
||||
|
||||
}
|
||||
|
||||
func (s *BattleSkillEntity) criticalrandom() decimal.Decimal {
|
||||
//这里应该算上威力区
|
||||
// 初始化随机值,范围217~255
|
||||
// func (s *BattleSkillEntity) criticalrandom() decimal.Decimal {
|
||||
// //这里应该算上威力区
|
||||
// // 初始化随机值,范围217~255
|
||||
|
||||
randomnum := s.Random().NextLongN(39) + 217
|
||||
// 10. 随机倍率,随机值除以255
|
||||
randomFactor := decimal.NewFromInt(int64(randomnum)).Div(decimal.NewFromInt(255))
|
||||
return randomFactor
|
||||
// randomnum := s.Random().NextLongN(39) + 217
|
||||
// // 10. 随机倍率,随机值除以255
|
||||
// randomFactor := decimal.NewFromInt(int64(randomnum)).Div(decimal.NewFromInt(255))
|
||||
// return randomFactor
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
// // 计算技能威力
|
||||
// func (s *BattleSkillEntity) CalculatePower(p *BattlePetEntity) int64 {
|
||||
|
||||
@@ -1,28 +1,26 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"blazing/common/utils/random"
|
||||
|
||||
"github.com/tnnmigga/enum"
|
||||
)
|
||||
|
||||
type Battle struct {
|
||||
Rand *random.RandomXS128 //本次战斗随机数
|
||||
same []BattleInputSourceEntity //同阵营
|
||||
Round int //回合数
|
||||
BattleMode EnumBattleMode //战斗模式
|
||||
opposite []BattleInputSourceEntity //不同阵营
|
||||
Effects *NodeManager //挂载effect,实际上是给每个输入源,然后触发时候循环调用Effects ,
|
||||
// type Battle struct {
|
||||
// Rand *random.RandomXS128 //本次战斗随机数
|
||||
// same []BattleInputSourceEntity //同阵营
|
||||
// Round int //回合数
|
||||
// BattleMode EnumBattleMode //战斗模式
|
||||
// opposite []BattleInputSourceEntity //不同阵营
|
||||
// Effects *NodeManager //挂载effect,实际上是给每个输入源,然后触发时候循环调用Effects ,
|
||||
|
||||
//A的effect->触发死亡->这时候就应该调用对手的切换,实现effect62
|
||||
}
|
||||
// //A的effect->触发死亡->这时候就应该调用对手的切换,实现effect62
|
||||
// }
|
||||
|
||||
// 执行下一回合
|
||||
func (b *Battle) NextRound() {
|
||||
// func (b *Battle) NextRound() {
|
||||
|
||||
b.Round++ //回合数加1
|
||||
// b.Round++ //回合数加1
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
// 战斗模式
|
||||
type EnumBattleMode int
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"blazing/common/utils/random"
|
||||
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Battle1V1 struct {
|
||||
Battle
|
||||
Ownerid uint32 // 房主ID
|
||||
FirstPerson uint32 //先手方ID
|
||||
|
||||
}
|
||||
|
||||
// 返回房主信息
|
||||
func (b *Battle1V1) Owner() *BattleInputSourceEntity {
|
||||
|
||||
return &b.same[0]
|
||||
}
|
||||
|
||||
// 返回邀请者信息,比如野怪
|
||||
func (b *Battle1V1) Target() *BattleInputSourceEntity {
|
||||
|
||||
return &b.opposite[0]
|
||||
}
|
||||
func NewBattleContainer1v1(i NoteReadyToFightInfo) *Battle1V1 {
|
||||
|
||||
ret := Battle1V1{}
|
||||
ret.same = make([]BattleInputSourceEntity, 0) //初始化本阵营
|
||||
ret.opposite = make([]BattleInputSourceEntity, 0) //初始化敌方阵营
|
||||
|
||||
ret.same = append(ret.same, BattleInputSourceEntity{
|
||||
FightUserInfo: i.OurInfo,
|
||||
//todo 待初始化精灵实体
|
||||
|
||||
}) //添加战斗实体
|
||||
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, BattleContainerCtx, &ret) //传入容器的上下文
|
||||
|
||||
return &ret
|
||||
}
|
||||
|
||||
const BattleContainerCtx = "battle"
|
||||
@@ -77,18 +77,18 @@ type StatusDict struct {
|
||||
// 精灵的能力提升
|
||||
type PropDict struct {
|
||||
// 攻击(@UInt long → uint32)
|
||||
Attack uint32 `struc:"[1]byte"`
|
||||
Attack byte
|
||||
// 防御(@UInt long → uint32)
|
||||
Defence uint32 `struc:"[1]byte"`
|
||||
Defence byte
|
||||
// 特攻(@UInt long → uint32)
|
||||
SpecialAttack uint32 `struc:"[1]byte"`
|
||||
SpecialAttack byte
|
||||
// 特防(@UInt long → uint32)
|
||||
SpecialDefence uint32 `struc:"[1]byte"`
|
||||
SpecialDefence byte
|
||||
|
||||
// 速度(@UInt long → uint32)
|
||||
Speed uint32 `struc:"[1]byte"`
|
||||
Speed byte
|
||||
// 命中(@UInt long → uint32)
|
||||
Accuracy uint32 `struc:"[1]byte"`
|
||||
Accuracy byte
|
||||
}
|
||||
|
||||
// BattleLevels 战斗属性等级结构体,对应原6字节数组
|
||||
|
||||
@@ -2,8 +2,8 @@ package service
|
||||
|
||||
import (
|
||||
"blazing/logic/service/fight/info"
|
||||
"blazing/modules/blazing/model"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
@@ -12,167 +12,147 @@ import (
|
||||
type PlayerI interface {
|
||||
ID() uint32
|
||||
MapID() uint32
|
||||
GetInfo() model.PlayerInfo
|
||||
//GetInfo() info.BattlePetEntity
|
||||
SendPack(b []byte) error
|
||||
SendReadyToFightInfo(info.FightStartOutboundInfo)
|
||||
SendNoteReadyToFightInfo(info.NoteReadyToFightInfo)
|
||||
}
|
||||
|
||||
type FightC struct {
|
||||
Info *info.NoteReadyToFightInfo
|
||||
Our PlayerI
|
||||
Opp PlayerI
|
||||
MAXPET uint32 //,最大精灵数
|
||||
//战斗发起者ID
|
||||
OwnerID uint32
|
||||
//玩家拥有者是否准备完成
|
||||
Info *info.NoteReadyToFightInfo
|
||||
Our PlayerI
|
||||
Opp PlayerI
|
||||
MAXPET uint32 // 最大精灵数
|
||||
OwnerID uint32 // 战斗发起者ID
|
||||
AFinished bool
|
||||
BFinished bool
|
||||
//random *rand.Rand //随机数种子
|
||||
StartTime time.Time
|
||||
actionChan chan info.BattleAction // 所有操作统一从这里进入
|
||||
Round int //回合数
|
||||
}
|
||||
|
||||
// 使用技能
|
||||
// 玩家使用技能
|
||||
func (f *FightC) UseSkill(c PlayerI, id uint32) {
|
||||
|
||||
ret := info.BattleAction{
|
||||
PlayerID: c.ID(),
|
||||
Priority: info.PlayerOperations.SelectSkill,
|
||||
// Skill: info.CreateBattleSkillWithInfinity(id),
|
||||
}
|
||||
|
||||
f.actionChan <- ret
|
||||
}
|
||||
|
||||
// 战斗准备
|
||||
func (f *FightC) ReadyFight(c PlayerI) {
|
||||
|
||||
rett := info.FightStartOutboundInfo{}
|
||||
copier.Copy(&rett.Info1, &f.Info.OurPetList[0]) //复制自己的信息
|
||||
switch f.Info.FightId { //判断战斗类型
|
||||
case 1:
|
||||
//1v1
|
||||
|
||||
if c == f.Our { //这个时候是房主发来的消息
|
||||
f.Info.AFinished = true
|
||||
if f.Info.BFinished {
|
||||
copier.Copy(&rett.Info1, &f.Info.OurPetList[0]) // 复制自己的信息
|
||||
|
||||
copier.Copy(&rett.Info2, &f.Info.OpponentPetList[0]) //复制对方信息
|
||||
switch f.Info.FightId {
|
||||
case 1: // 1v1
|
||||
if c == f.Our {
|
||||
f.AFinished = true
|
||||
if f.BFinished {
|
||||
copier.Copy(&rett.Info2, &f.Info.OpponentPetList[0])
|
||||
f.Our.SendReadyToFightInfo(rett)
|
||||
f.Opp.SendReadyToFightInfo(rett)
|
||||
}
|
||||
|
||||
} else {
|
||||
f.Our = c
|
||||
f.Info.BFinished = true
|
||||
if f.Info.AFinished { //如果房主完成
|
||||
|
||||
copier.Copy(&rett.Info2, &f.Info.OurPetList[0]) //复制房主信息,因为这时候不是房主发来的消息
|
||||
f.Opp = c
|
||||
f.BFinished = true
|
||||
if f.AFinished {
|
||||
copier.Copy(&rett.Info2, &f.Info.OurPetList[0])
|
||||
f.Our.SendReadyToFightInfo(rett)
|
||||
f.Opp.SendReadyToFightInfo(rett)
|
||||
}
|
||||
}
|
||||
|
||||
case 3: //野怪战斗
|
||||
|
||||
case 3: // 野怪战斗
|
||||
copier.Copy(&rett.Info2, &f.Info.OpponentPetList[0])
|
||||
rett.Info1.UserID = f.Info.OurInfo.UserID
|
||||
f.Our.SendReadyToFightInfo(rett)
|
||||
f.Opp.SendReadyToFightInfo(rett)
|
||||
}
|
||||
}
|
||||
func (f *FightC) Random() {
|
||||
//先产生战斗的随机数
|
||||
// 组合「时间戳(纳秒精度)+ 双方ID + 回合数」生成种子
|
||||
|
||||
seed := f.StartTime.UnixNano() ^ int64(f.OwnerID) ^ int64(f.Our.ID()) ^ int64(f.Round) // 用异或运算混合多维度信息
|
||||
rand.Seed(seed)
|
||||
|
||||
}
|
||||
|
||||
// 创建新战斗
|
||||
func (f *FightC) NewFight(i *info.NoteReadyToFightInfo, plays PlayerI) {
|
||||
|
||||
f.Our = plays
|
||||
f.Info = i
|
||||
f.StartTime = time.Now()
|
||||
f.actionChan = make(chan info.BattleAction, 2) // 初始化全局操作通道
|
||||
|
||||
f.Info.FightId = i.FightId
|
||||
switch i.FightId {
|
||||
case 1:
|
||||
//1v1
|
||||
|
||||
case 3: //野怪战斗
|
||||
// 1v1,等双方进入
|
||||
case 3: // 野怪战斗
|
||||
plays.SendNoteReadyToFightInfo(*i)
|
||||
f.Opp = &AI_player{
|
||||
fightinfo: *i,
|
||||
}
|
||||
|
||||
//这时候应该建立一个虚拟的player
|
||||
|
||||
f.Opp = &AI_player{fightinfo: *i, FightC: f} // 创建虚拟对手
|
||||
}
|
||||
f.battleLoop()
|
||||
|
||||
go f.battleLoop() // 起战斗循环
|
||||
}
|
||||
|
||||
// 定义操作类型,存储玩家的操作信息(如技能选择、目标等)
|
||||
type Action struct {
|
||||
PlayerID int // 玩家ID:1或2
|
||||
SkillID int // 使用的技能ID
|
||||
TargetID int // 目标ID
|
||||
}
|
||||
|
||||
// 战斗回合循环
|
||||
func (f *FightC) battleLoop() {
|
||||
for { // 战斗回合循环
|
||||
// 每个回合重置:创建两个通道接收双方操作
|
||||
p1ActionChan := make(chan Action) // 玩家1的操作通道
|
||||
p2ActionChan := make(chan Action) // 玩家2的操作通道
|
||||
for {
|
||||
f.Round++ //回合数自增
|
||||
actions := make(map[uint32]info.BattleAction) // 每个玩家一条记录
|
||||
timeout := time.After(60 * time.Second)
|
||||
|
||||
// 启动goroutine处理双方输入(实际项目中这里会绑定用户输入逻辑)
|
||||
go handlePlayerInput(1, p1ActionChan)
|
||||
go handlePlayerInput(2, p2ActionChan)
|
||||
|
||||
// 等待双方操作或超时
|
||||
var p1Action, p2Action Action
|
||||
var p1Done, p2Done bool
|
||||
timeout := time.After(60 * time.Second) // 60秒超时
|
||||
|
||||
// 循环等待双方都完成操作
|
||||
for !(p1Done && p2Done) {
|
||||
for len(actions) < 2 {
|
||||
select {
|
||||
case action := <-p1ActionChan:
|
||||
p1Action = action
|
||||
p1Done = true
|
||||
fmt.Printf("玩家%d已选择技能%d\n", action.PlayerID, action.SkillID)
|
||||
case action := <-p2ActionChan:
|
||||
p2Action = action
|
||||
p2Done = true
|
||||
fmt.Printf("玩家%d已选择技能%d\n", action.PlayerID, action.SkillID)
|
||||
case action := <-f.actionChan:
|
||||
// 只接受有效玩家 ID
|
||||
if action.PlayerID != f.Our.ID() && action.PlayerID != f.Opp.ID() {
|
||||
continue
|
||||
}
|
||||
// 如果该玩家已经提交过,就忽略重复动作
|
||||
if _, exists := actions[uint32(action.PlayerID)]; exists {
|
||||
fmt.Printf("玩家%d 已经提交过动作,忽略重复\n", action.PlayerID)
|
||||
continue
|
||||
}
|
||||
|
||||
actions[uint32(action.PlayerID)] = action
|
||||
fmt.Printf("玩家%d 执行动作", action.PlayerID)
|
||||
|
||||
case <-timeout:
|
||||
// 超时处理:未操作的视为放弃
|
||||
fmt.Println("操作超时,未操作方视为放弃本回合")
|
||||
// 根据超时情况补充未完成的操作(如空操作)
|
||||
if !p1Done {
|
||||
p1Action = Action{PlayerID: 1, SkillID: 0} // 0表示放弃
|
||||
fmt.Println("回合操作超时")
|
||||
if _, exists := actions[f.Our.ID()]; !exists {
|
||||
actions[f.Our.ID()] = info.BattleAction{PlayerID: f.Our.ID(), Priority: info.PlayerOperations.SystemGiveUp} //系统选择出手
|
||||
}
|
||||
if !p2Done {
|
||||
p2Action = Action{PlayerID: 2, SkillID: 0}
|
||||
if _, exists := actions[f.Opp.ID()]; !exists {
|
||||
actions[f.Opp.ID()] = info.BattleAction{PlayerID: f.Our.ID(), Priority: info.PlayerOperations.SystemGiveUp} //系统选择出手
|
||||
}
|
||||
p1Done = true
|
||||
p2Done = true
|
||||
}
|
||||
}
|
||||
|
||||
// 双方都已操作,执行战斗计算
|
||||
fmt.Println("双方操作完成,开始计算本回合结果...")
|
||||
calculateBattleResult(p1Action, p2Action)
|
||||
// 双方动作齐了,取出来结算
|
||||
p1Action := actions[f.Our.ID()]
|
||||
p2Action := actions[f.Opp.ID()]
|
||||
fmt.Printf("开始结算回合")
|
||||
fmt.Println(p1Action)
|
||||
fmt.Println(p2Action)
|
||||
// TODO: 在这里调用技能结算逻辑
|
||||
|
||||
// 检查战斗是否结束(如一方血量为0)
|
||||
if isBattleEnd() {
|
||||
fmt.Println("战斗结束")
|
||||
break
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟处理玩家输入(实际中会绑定UI或网络输入)
|
||||
func handlePlayerInput(playerID int, actionChan chan<- Action) {
|
||||
// 这里只是示例:实际中会等待用户输入(如点击技能按钮)
|
||||
// 假设玩家1选择技能1,目标是玩家2;玩家2选择技能2,目标是玩家1
|
||||
time.Sleep(time.Second * 2) // 模拟思考时间
|
||||
if playerID == 1 {
|
||||
actionChan <- Action{PlayerID: 1, SkillID: 1, TargetID: 2}
|
||||
} else {
|
||||
actionChan <- Action{PlayerID: 2, SkillID: 2, TargetID: 1}
|
||||
}
|
||||
}
|
||||
|
||||
// 战斗计算逻辑(示例)
|
||||
func calculateBattleResult(p1, p2 Action) {
|
||||
// 实际项目中会根据技能ID计算伤害、 buff等
|
||||
fmt.Printf("玩家1使用技能%d攻击玩家%d,玩家2使用技能%d攻击玩家%d\n",
|
||||
p1.SkillID, p1.TargetID, p2.SkillID, p2.TargetID)
|
||||
}
|
||||
|
||||
// 检查战斗是否结束(示例)
|
||||
// 判断战斗是否结束
|
||||
func isBattleEnd() bool {
|
||||
// 实际中会判断双方血量等条件
|
||||
return false // 暂时返回false,持续战斗
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ var tt task.GetTaskBufOutboundInfo
|
||||
|
||||
func main() {
|
||||
//Test_kick()
|
||||
|
||||
cmd.Main.Run(gctx.New())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user