diff --git a/common/data/socket/player.go b/common/data/socket/player.go index d0a21d717..258658d4c 100644 --- a/common/data/socket/player.go +++ b/common/data/socket/player.go @@ -2,9 +2,9 @@ package socket import ( "blazing/common/utils" + "blazing/modules/blazing/model" "blazing/modules/blazing/service" - "context" "fmt" "sync" @@ -41,6 +41,16 @@ func (c *Conn) SendPack(bytes []byte) error { return nil } +type OgreInfo struct { + Data [9]OgrePetInfo +} + +type OgrePetInfo struct { + Id uint32 + Shiny uint32 + Lv uint32 `struc:"skip"` //等级 +} + type Player struct { MainConn *Conn @@ -54,6 +64,9 @@ type Player struct { context.Context Playerinvite uint32 //当前邀请的玩家ID Onlinetime uint32 //当前登录时间 + OgreInfo *OgreInfo + FightID string //绑定战斗标识 + //FightInfo info.NoteReadyToFightInfo } // PlayerOption 定义配置 Player 的函数类型 diff --git a/logic/controller/fight.go b/logic/controller/fight.go index 6d004e820..2577b0447 100644 --- a/logic/controller/fight.go +++ b/logic/controller/fight.go @@ -4,6 +4,9 @@ import ( "blazing/common/data/socket" "blazing/common/socket/errorcode" "blazing/common/socket/handler" + "math/rand" + "time" + "blazing/logic/service/fight" "blazing/logic/service/fight/info" "blazing/modules/blazing/model" @@ -11,15 +14,15 @@ import ( "github.com/jinzhu/copier" ) -func (h Controller) OnPlayerFightNpcMonster(data *fight.FightNpcMonsterInboundInfo, c *socket.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) { +func (h Controller) OnPlayerFightNpcMonster(data *info.FightNpcMonsterInboundInfo, c *socket.Player) (result *info.NullOutboundInfo, err errorcode.ErrorCode) { c.IsFighting = true - t1 := handler.NewTomeeHeader(2503, c.Info.UserID) + ttt := info.NoteReadyToFightInfo{ OwnerID: data.Head.UserID, FightId: 3, } - ttt.OurInfo = info.FightUserInfo{UserID: c.Info.UserID, Nick: c.Info.Nick} + copier.Copy(&ttt.OurInfo, &c.Info) len := len(c.Info.PetList) ttt.OurPetList = make([]info.ReadyFightPetInfo, len) for i := 0; i < len; i++ { @@ -31,61 +34,49 @@ func (h Controller) OnPlayerFightNpcMonster(data *fight.FightNpcMonsterInboundIn } ttt.OpponentInfo = info.FightUserInfo{UserID: 0} - ttt.OpponentPetList = []info.ReadyFightPetInfo{{ID: 1, - Level: 100, - MaxHp: 100, - SkillListLen: 4, - Hp: 100}} - for i := 0; i < 4; i++ { - ttt.OpponentPetList[0].SkillList[i] = model.SkillInfo{ID: 10001, Pp: 1} + refpet := c.OgreInfo.Data[data.Number] + + dv := rand.New(rand.NewSource(time.Now().UnixNano())).Intn(32) + mo := model.GenPetInfo(refpet.Id, uint32(dv), 0, 1006, refpet.Shiny, refpet.Lv) + ttt.OpponentPetList = make([]info.ReadyFightPetInfo, 1) + + err1 := copier.CopyWithOption(&ttt.OpponentPetList[0], &mo, copier.Option{IgnoreEmpty: true, DeepCopy: true}) + if err1 != nil { + panic(err) } - c.SendPack(t1.Pack(&ttt)) + + fight.NewFight(&ttt, c) //把两个玩家都传进去 + return nil, -1 } // 准备战斗 -func (h Controller) OnReadyToFight(data *fight.ReadyToFightInboundInfo, c *socket.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) { +func (h Controller) OnReadyToFight(data *info.ReadyToFightInboundInfo, c *socket.Player) (result *info.NullOutboundInfo, err errorcode.ErrorCode) { - t1 := handler.NewTomeeHeader(2504, c.Info.UserID) - rett := fight.FightStartOutboundInfo{ - IsCanAuto: 0, - - Info2: fight.FightPetInfo{ - UserID: 0, - ID: 1, - Hp: 1000, - MaxHp: 1000, - Level: 1, - CatchTime: 0, - Catchable: 1, - BattleLV: [6]byte{1, 1, 1, 1, 1, 1}}, - } - copier.Copy(&rett.Info1, &c.Info.PetList[0]) - rett.Info1.UserID = c.Info.UserID - c.SendPack(t1.Pack(&rett)) + fight.ReadyFight(c) return nil, -1 } // 接收战斗或者取消战斗的包 -func (h Controller) OnPlayerHandleFightInvite(data *fight.HandleFightInviteInboundInfo, c *socket.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) { +func (h Controller) OnPlayerHandleFightInvite(data *info.HandleFightInviteInboundInfo, c *socket.Player) (result *info.NullOutboundInfo, err errorcode.ErrorCode) { return nil, -1 } // 使用技能包 -func (h Controller) UseSkill(data *fight.UseSkillInboundInfo, c *socket.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) { +func (h Controller) UseSkill(data *info.UseSkillInboundInfo, c *socket.Player) (result *info.NullOutboundInfo, err errorcode.ErrorCode) { return nil, 0 } // 战斗逃跑 -func (h Controller) Escape(data *fight.EscapeFightInboundInfo, c *socket.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) { +func (h Controller) Escape(data *info.EscapeFightInboundInfo, c *socket.Player) (result *info.NullOutboundInfo, err errorcode.ErrorCode) { defer func() { //战斗结束Escape ttt := handler.NewTomeeHeader(2506, c.Info.UserID) - c.SendPack(ttt.Pack(&fight.FightOverInfo{ + c.SendPack(ttt.Pack(&info.FightOverInfo{ Reason: 0, })) c.IsFighting = false diff --git a/logic/controller/room.go b/logic/controller/room.go index 9060c57b0..a7660a766 100644 --- a/logic/controller/room.go +++ b/logic/controller/room.go @@ -26,7 +26,7 @@ func (h Controller) OnGetRoomPetShowInfo(data *room.PetRoomListInboundInfo, c *s // 获取自己房间的家具 func (h Controller) OnGetFitmentAll(data *room.FitmentAllInboundEmpty, c *socket.Player) (result *room.FitmentAllOutboundInfo, err errorcode.ErrorCode) { result = &room.FitmentAllOutboundInfo{} - result.Fitments = make([]room.FitmentShowInfo, 0) - result.Fitments = append(result.Fitments, room.FitmentShowInfo{Id: 500001, Status: 1, X: 1, Y: 1, Dir: 1}) + result.Fitments = make([]room.FitmentItemInfo, 0) + return } diff --git a/logic/service/fight/battle.go b/logic/service/fight/battle.go deleted file mode 100644 index 82c4e98bd..000000000 --- a/logic/service/fight/battle.go +++ /dev/null @@ -1,61 +0,0 @@ -package fight - -import "blazing/logic/service/fight/info" - -func NewBattle(i info.NoteReadyToFightInfo) { - //调用技能产生effect参数后,创建effect实例,而非技能创建 - c := info.NewBattleContainer1v1(i) //创建战斗容器 - t := info.BattleSkillEntity{} // - t.SideEffectArgs = []int{1, 2, 3} - //先提交effecet后然后计算伤害 - - //物理和特殊,百分比和固定伤害也算,真实伤害不分类别,故直接扣血就行,不需要计算 - if t.Category() == info.Category.PHYSICAL || t.Category() == info.Category.SPECIAL { - c.Effects.Exec(func(e info.Effect) bool { - return e.PreDamage() //执行预处理效果 - }) - - // Apply pre-damage effects for pet sources - // battle.applyEffects(context, EffectTrigger.PreDamage) - // if (context.crit) { - // battle.applyEffects(context, EffectTrigger.OnCritPreDamage) // Trigger crit pre-damage effects - // } - //假如说这里需要能力提升 - // c.Exec(func(e Effect) func() { - // return e.OnBeforeAddMark() - // }) - //添加印记前的效果如果有任何一个false,说明组织了添加效果 - //这里能力提升 - // c.Exec(func(e Effect) bool { - // return e.OnAnyMarkAdded() - // }) - - // var candidates []*Effect - // for _, eff := range c.Effects { - // if eff.Trigger == trigger { - // candidates = append(candidates, eff) - // } - // } - - // // 按优先级排序 - // sort.SliceStable(candidates, func(i, j int) bool { - // return candidates[i].Priority > candidates[j].Priority - // }) - - // // 执行 - // for _, eff := range candidates { - // ctx.Effect = eff - // keep := eff.Apply(ctx) - - // if !keep { - // // 持续回合结束 / 返回 false 的 effect 删除 - // c.removeEffect(eff) - // } - - // if ctx.Done { - // break // 被拦截 - // } - // } - } - -} diff --git a/logic/service/fight/fight.go b/logic/service/fight/fight.go index c4c0fc5e8..c00097fbf 100644 --- a/logic/service/fight/fight.go +++ b/logic/service/fight/fight.go @@ -1,102 +1,127 @@ package fight import ( + "blazing/common/data/socket" "blazing/common/socket/handler" - "blazing/modules/blazing/model" + "blazing/logic/service/fight/info" + "strings" + + "github.com/google/uuid" + "github.com/jinzhu/copier" ) -// 野怪对战包 -type FightNpcMonsterInboundInfo struct { - Head handler.TomeeHeader `cmd:"2408" struc:"[0]pad"` - // Number 地图刷新怪物结构体对应的序号(1-9的位置序号) - // @UInt long类型,使用uint32保持无符号特性 - Number uint32 `fieldDesc:"地图刷新怪物结构体对应的序号 1 - 9 的位置序号" ` +var FightCache = make(map[string]*info.NoteReadyToFightInfo) //默认our是房主 + +func ReadyFight(c *socket.Player) { + tt, _ := FightCache[c.FightID] + t1 := handler.NewTomeeHeader(2504, c.Info.UserID) + rett := info.FightStartOutboundInfo{ + IsCanAuto: 0, + } + copier.Copy(&rett.Info1, &c.Info.PetList[0]) //复制自己的信息 + switch tt.FightId { //判断战斗类型 + case 1: + //1v1 + + if c.Info.UserID == tt.OwnerID { //这个时候是房主发来的消息 + tt.AFinished = true + if tt.BFinished { + + copier.Copy(&rett.Info2, &tt.OpponentPetList[0]) //复制对方信息 + c.SendPack(t1.Pack(&rett)) //给自己发 + tt.Opp.SendPack(t1.Pack(&rett)) //给对方发 + } + + } else { + tt.BFinished = true + if tt.AFinished { //如果房主完成 + + copier.Copy(&rett.Info2, &tt.OurPetList[0]) //复制房主信息,因为这时候不是房主发来的消息 + c.SendPack(t1.Pack(&rett)) //给自己发 + tt.Our.SendPack(t1.Pack(&rett)) //给房主发 + } + } + + case 3: //野怪战斗 + + copier.Copy(&rett.Info2, &tt.OpponentPetList[0]) + rett.Info1.UserID = c.Info.UserID //用户ID复制进去 + c.SendPack(t1.Pack(&rett)) + } + } +func NewFight(i *info.NoteReadyToFightInfo, plays *socket.Player) { + + t12, _ := uuid.NewV7() + uuid := strings.Replace(t12.String(), "-", "", -1) //绑定战斗ID + FightCache[uuid] = i + //先发送战斗准备包 + switch i.FightId { + case 1: + //1v1 + + case 3: //野怪战斗 + + t1 := handler.NewTomeeHeader(2503, plays.Info.UserID) + + plays.FightID = uuid //绑定战斗ID + plays.SendPack(t1.Pack(i)) //准备包由各自发,因为协议不一样 + + } + + //调用技能产生effect参数后,创建effect实例,而非技能创建 + c := info.NewBattleContainer1v1(*i) //创建战斗容器 + t := info.BattleSkillEntity{} // + t.SideEffectArgs = []int{1, 2, 3} + //先提交effecet后然后计算伤害 + + //物理和特殊,百分比和固定伤害也算,真实伤害不分类别,故直接扣血就行,不需要计算 + if t.Category() == info.Category.PHYSICAL || t.Category() == info.Category.SPECIAL { + c.Effects.Exec(func(e info.Effect) bool { + return e.PreDamage() //执行预处理效果 + }) + + // Apply pre-damage effects for pet sources + // battle.applyEffects(context, EffectTrigger.PreDamage) + // if (context.crit) { + // battle.applyEffects(context, EffectTrigger.OnCritPreDamage) // Trigger crit pre-damage effects + // } + //假如说这里需要能力提升 + // c.Exec(func(e Effect) func() { + // return e.OnBeforeAddMark() + // }) + //添加印记前的效果如果有任何一个false,说明组织了添加效果 + //这里能力提升 + // c.Exec(func(e Effect) bool { + // return e.OnAnyMarkAdded() + // }) + + // var candidates []*Effect + // for _, eff := range c.Effects { + // if eff.Trigger == trigger { + // candidates = append(candidates, eff) + // } + // } + + // // 按优先级排序 + // sort.SliceStable(candidates, func(i, j int) bool { + // return candidates[i].Priority > candidates[j].Priority + // }) + + // // 执行 + // for _, eff := range candidates { + // ctx.Effect = eff + // keep := eff.Apply(ctx) + + // if !keep { + // // 持续回合结束 / 返回 false 的 effect 删除 + // c.removeEffect(eff) + // } + + // if ctx.Done { + // break // 被拦截 + // } + // } + } -type NullOutboundInfo struct { -} - -// 准备战斗包 -type ReadyToFightInboundInfo struct { - Head handler.TomeeHeader `cmd:"2404" struc:"[0]pad"` -} - -type FightStartOutboundInfo struct { - // @UInt long类型 - IsCanAuto uint32 `fieldDesc:"是否自动 默认给0 怀疑是自动战斗器使用的" ` - - // 当前战斗精灵信息1(前端通过userid判断是否为我方) - Info1 FightPetInfo `fieldDesc:"当前战斗精灵的信息 可能不准.看前端代码是以userid来判断哪个结构体是我方的" serialize:"struct"` - - // 当前战斗精灵信息2(前端通过userid判断是否为我方) - Info2 FightPetInfo `fieldDesc:"当前战斗精灵的信息 可能不准.看前端代码是以userid来判断哪个结构体是我方的" serialize:"struct"` -} - -// FightPetInfo 战斗精灵信息结构体,FightPetInfo类 -type FightPetInfo struct { - // 用户ID(野怪为0),@UInt long - UserID uint32 `fieldDesc:"用户ID 野怪为0" ` - - // 当前对战精灵ID,@UInt long - ID uint32 `fieldDesc:"当前对战精灵ID" ` - - Name string `struc:"[16]byte"` - // 精灵的捕获时间,@UInt long - CatchTime uint32 `fieldDesc:"精灵的捕获时间" ` - - // 当前HP,@UInt long - Hp uint32 `fieldDesc:"当前HP" ` - - // 最大HP,@UInt long - MaxHp uint32 `fieldDesc:"最大HP" ` - - // 当前等级,@UInt long - Level uint32 `fieldDesc:"当前等级" ` - - // 精灵是否能捕捉(1为能捕捉,0为不能捕捉),@UInt long - Catchable uint32 `fieldDesc:"精灵是否能捕捉. 1为能捕捉 0为不能捕捉" ` - - // 战斗属性等级数组(6个单字节) - // byte[],固定长度6,存储buff等级、攻击、速度等属性 - BattleLV [6]byte `fieldDesc:"这里实际上应该是6个单字节byte, 内容为buff等级 攻击 速度 特攻 防御 特防 命中等.但具体顺序未知可能需要测试. 具体数值为1-6等级" serialize:"fixedLength=6,type=byteArray"` -} - -// AttackValue 战斗中的攻击数值信息 -type AttackValue struct { - UserID uint32 `json:"userId" fieldDescription:"玩家的米米号 与野怪对战userid = 0"` - SkillID uint32 `json:"skillId" fieldDescription:"使用技能的id"` - AttackTime uint32 `json:"attackTime" fieldDescription:"是否击中 如果为0 则miss 如果为1 则击中"` - LostHp uint32 `json:"lostHp" fieldDescription:"我方造成的伤害"` - GainHp uint32 `json:"gainHp" fieldDescription:"我方获得血量"` - RemainHp uint32 `json:"remainHp" fieldDescription:"我方剩余血量"` - MaxHp uint32 `json:"maxHp" fieldDescription:"我方最大血量"` - State uint32 `json:"state" fieldDescription:"固定值0 需要后续测试"` - SkillList []model.SkillInfo `json:"skillList" fieldDescription:"根据精灵的数据插入技能 最多4条 不定长"` - IsCritical uint32 `json:"isCritical" fieldDescription:"是否暴击"` - Status [20]byte `json:"status" fieldDescription:"20个字节 各种状态: 0:\"麻痹\",1:\"中毒\",2:\"烧伤\",4:\"寄生\",5:\"冻伤\",6:\"害怕\",7:\"疲惫\",8:\"睡眠\",9:\"石化\",10:\"混乱\",15:\"冰封\",16:\"流血\""` - BattleLv [6]byte `json:"battleLv" fieldDescription:"6个单字节byte, 内容为buff等级 攻击 速度 特攻 防御 特防命中等. 但具体顺序未知可能需要测试. 具体数值为1-6等级"` - // OwnerMaxShield uint32 `json:"ownerMaxShield" fieldDescription:"我方最大护盾"` - // OwnerCurrentShield uint32 `json:"ownerCurrentShield" fieldDescription:"我方当前护盾"` -} - -// NoteUseSkillOutboundInfo 战斗技能使用通知的出站信息结构体 -type NoteUseSkillOutboundInfo struct { - FirstAttackInfo AttackValue // 本轮先手的精灵在释放技能结束后的状态 - SecondAttackInfo AttackValue // 本轮后手的精灵在释放技能结束后的状态 -} - -// 战斗逃跑 -type EscapeFightInboundInfo struct { - Head handler.TomeeHeader `cmd:"2410" struc:"[0]pad"` -} - -// FightOverInfo 战斗结束信息结构体 2506 -type FightOverInfo struct { - Reason uint32 // 固定值0 - WinnerId uint32 // 胜者的米米号 野怪为0 - TwoTimes uint32 // 双倍经验剩余次数 - ThreeTimes uint32 // 三倍经验剩余次数 - AutoFightTimes uint32 // 自动战斗剩余次数 - EnergyTimes uint32 // 能量吸收器剩余次数 - LearnTimes uint32 // 双倍学习器剩余次数 } diff --git a/logic/service/fight/info/BattleInputSourceEntity.go b/logic/service/fight/info/BattleInputSourceEntity.go index 7b0d81a01..291e52c38 100644 --- a/logic/service/fight/info/BattleInputSourceEntity.go +++ b/logic/service/fight/info/BattleInputSourceEntity.go @@ -7,9 +7,9 @@ import ( const Input_ctx = "player" type BattleInputSourceEntity struct { - FightUserInfo //用户信息 + FightUserInfo //用户信息 PetEntities []*BattlePetEntity //宠物信息 - ctx context.Context //输入源的上下文 + ctx context.Context //输入源的上下文 } diff --git a/logic/service/fight/info/NoteReadyToFightInfo.go b/logic/service/fight/info/NoteReadyToFightInfo.go deleted file mode 100644 index c2682aa69..000000000 --- a/logic/service/fight/info/NoteReadyToFightInfo.go +++ /dev/null @@ -1,70 +0,0 @@ -package info - -import ( - "blazing/modules/blazing/model" -) - -type FightUserInfo struct { - // 用户ID(野怪为0),@UInt long - UserID uint32 `fieldDesc:"userID 如果为野怪则为0" ` - - // 玩家名称(野怪为UTF-8的'-',固定16字节) - // 使用[16]byte存储固定长度的字节数组 - Nick string `struc:"[16]byte"` -} - -// NoteReadyToFightInfo 战斗准备就绪消息结构体,NoteReadyToFightInfo -type NoteReadyToFightInfo struct { - //战斗发起者ID - OwnerID uint32 `struc:"skip"` - // 战斗类型ID(与野怪战斗为3,与人战斗为1,前端似乎未使用) - // @UInt long - FightId uint32 `fieldDesc:"战斗类型ID 但前端好像没有用到 与野怪战斗为3,与人战斗似乎是1" ` - - // 我方信息 - OurInfo FightUserInfo `fieldDesc:"我方信息" serialize:"struct"` - OurPetListLen uint32 `struc:"sizeof=OurPetList"` - // 我方携带精灵的信息 - // ArrayList,使用切片模拟动态列表 - OurPetList []ReadyFightPetInfo `fieldDesc:"我方携带精灵的信息" serialize:"lengthFirst,lengthType=uint16,type=structArray"` - - // 对方信息 - OpponentInfo FightUserInfo `fieldDesc:"对方信息" serialize:"struct"` - OpponentPetListLen uint32 `struc:"sizeof=OpponentPetList"` - // 敌方的精灵信息 - // 野怪战斗时:客户端接收此包前已生成精灵PetInfo,将部分信息写入该列表 - OpponentPetList []ReadyFightPetInfo `fieldDesc:"敌方的精灵信息 如果是野怪 那么再给客户端发送这个包体时就提前生成好了这只精灵的PetInfo,然后把从PetInfo中把部分信息写入到这个敌方的精灵信息中再发送这个包结构体" serialize:"lengthFirst,lengthType=uint16,type=structArray"` -} - -// ReadyFightPetInfo 准备战斗的精灵信息结构体,ReadyFightPetInfo类 -type ReadyFightPetInfo struct { - // 精灵ID,@UInt long - ID uint32 `fieldDesc:"精灵ID" ` - - // 精灵等级,@UInt long - Level uint32 `fieldDesc:"精灵等级" ` - - // 精灵当前HP,@UInt long - Hp uint32 `fieldDesc:"精灵HP" ` - - // 精灵最大HP,@UInt long - MaxHp uint32 `fieldDesc:"最大HP" ` - SkillListLen uint32 - // 技能信息列表(固定4个元素,技能ID和剩余PP,无技能则为0) - // List,初始化容量为4 - SkillList [4]model.SkillInfo `fieldDesc:"技能信息 技能ID跟剩余PP 固定32字节 没有给0" serialize:"fixedLength=4,type=structArray"` - - // 精灵捕获时间,@UInt long - CatchTime uint32 `fieldDesc:"精灵捕获时间" ` - - // 捕捉地图(固定给0),@UInt long - CatchMap uint32 `fieldDesc:"捕捉地图 给0" ` - - // 固定给0,@UInt long - CatchRect uint32 `fieldDesc:"给0" ` - - // 固定给0,@UInt long - CatchLevel uint32 `fieldDesc:"给0" ` - SkinID uint32 `fieldDesc:"精灵皮肤ID" ` - Shiny uint32 `fieldDesc:"精灵是否闪" ` -} diff --git a/logic/service/fight/info/battle.go b/logic/service/fight/info/battle.go index 51e9b1609..c62131a44 100644 --- a/logic/service/fight/info/battle.go +++ b/logic/service/fight/info/battle.go @@ -65,3 +65,16 @@ var BattleOverReason = enum.New[struct { PlayerCaptureSuccess EnumBattleOverReason `enum:"3"` //捕捉成功 DefaultEnd EnumBattleOverReason `enum:"4"` //默认结束 }]() + +// 战斗模式 + +var BattleMode_PVP = enum.New[struct { + PVP_1V1 EnumBattleMode `enum:"1"` + PVP_6V6 EnumBattleMode `enum:"2"` +}]() +var Playerinvitemap map[uint32][]Playerinvite = make(map[uint32][]Playerinvite) //玩家邀请信息 ,比如一个玩家被多人邀请对战 + +type Playerinvite struct { //挂载到[]Playerinvite上? 被邀请者->邀请者 + InviteID uint32 // 邀请者 + InviteTime EnumBattleMode //游戏模式 +} diff --git a/logic/service/fight/info/fight.go b/logic/service/fight/info/fight.go new file mode 100644 index 000000000..1f126d568 --- /dev/null +++ b/logic/service/fight/info/fight.go @@ -0,0 +1,203 @@ +package info + +import ( + "blazing/common/data/socket" + "blazing/common/socket/handler" + "blazing/modules/blazing/model" + "fmt" +) + +// 野怪对战包 +type FightNpcMonsterInboundInfo struct { + Head handler.TomeeHeader `cmd:"2408" struc:"[0]pad"` + // Number 地图刷新怪物结构体对应的序号(1-9的位置序号) + // @UInt long类型,使用uint32保持无符号特性 + Number uint32 `fieldDesc:"地图刷新怪物结构体对应的序号 1 - 9 的位置序号" ` +} + +type NullOutboundInfo struct { +} + +// 准备战斗包 +type ReadyToFightInboundInfo struct { + Head handler.TomeeHeader `cmd:"2404" struc:"[0]pad"` +} + +type FightStartOutboundInfo struct { + // @UInt long类型 + IsCanAuto uint32 `fieldDesc:"是否自动 默认给0 怀疑是自动战斗器使用的" ` + + // 当前战斗精灵信息1(前端通过userid判断是否为我方) + Info1 FightPetInfo `fieldDesc:"当前战斗精灵的信息 可能不准.看前端代码是以userid来判断哪个结构体是我方的" serialize:"struct"` + + // 当前战斗精灵信息2(前端通过userid判断是否为我方) + Info2 FightPetInfo `fieldDesc:"当前战斗精灵的信息 可能不准.看前端代码是以userid来判断哪个结构体是我方的" serialize:"struct"` +} + +// FightPetInfo 战斗精灵信息结构体,FightPetInfo类 +type FightPetInfo struct { + // 用户ID(野怪为0),@UInt long + UserID uint32 `fieldDesc:"用户ID 野怪为0" ` + + // 当前对战精灵ID,@UInt long + ID uint32 `fieldDesc:"当前对战精灵ID" ` + + Name string `struc:"[16]byte"` + // 精灵的捕获时间,@UInt long + CatchTime uint32 `fieldDesc:"精灵的捕获时间" ` + + // 当前HP,@UInt long + Hp uint32 `fieldDesc:"当前HP" ` + + // 最大HP,@UInt long + MaxHp uint32 `fieldDesc:"最大HP" ` + + // 当前等级,@UInt long + Level uint32 `fieldDesc:"当前等级" ` + + // 精灵是否能捕捉(1为能捕捉,0为不能捕捉),@UInt long + Catchable uint32 `fieldDesc:"精灵是否能捕捉. 1为能捕捉 0为不能捕捉" ` + + // 战斗属性等级数组(6个单字节) + // byte[],固定长度6,存储buff等级、攻击、速度等属性 + BattleLV [6]byte `fieldDesc:"这里实际上应该是6个单字节byte, 内容为buff等级 攻击 速度 特攻 防御 特防 命中等.但具体顺序未知可能需要测试. 具体数值为1-6等级" serialize:"fixedLength=6,type=byteArray"` +} + +// AttackValue 战斗中的攻击数值信息 +type AttackValue struct { + UserID uint32 `json:"userId" fieldDescription:"玩家的米米号 与野怪对战userid = 0"` + SkillID uint32 `json:"skillId" fieldDescription:"使用技能的id"` + AttackTime uint32 `json:"attackTime" fieldDescription:"是否击中 如果为0 则miss 如果为1 则击中"` + LostHp uint32 `json:"lostHp" fieldDescription:"我方造成的伤害"` + GainHp uint32 `json:"gainHp" fieldDescription:"我方获得血量"` + RemainHp uint32 `json:"remainHp" fieldDescription:"我方剩余血量"` + MaxHp uint32 `json:"maxHp" fieldDescription:"我方最大血量"` + State uint32 `json:"state" fieldDescription:"固定值0 需要后续测试"` + SkillList []model.SkillInfo `json:"skillList" fieldDescription:"根据精灵的数据插入技能 最多4条 不定长"` + IsCritical uint32 `json:"isCritical" fieldDescription:"是否暴击"` + Status [20]byte `json:"status" fieldDescription:"20个字节 各种状态: 0:\"麻痹\",1:\"中毒\",2:\"烧伤\",4:\"寄生\",5:\"冻伤\",6:\"害怕\",7:\"疲惫\",8:\"睡眠\",9:\"石化\",10:\"混乱\",15:\"冰封\",16:\"流血\""` + BattleLv [6]byte `json:"battleLv" fieldDescription:"6个单字节byte, 内容为buff等级 攻击 速度 特攻 防御 特防命中等. 但具体顺序未知可能需要测试. 具体数值为1-6等级"` + // OwnerMaxShield uint32 `json:"ownerMaxShield" fieldDescription:"我方最大护盾"` + // OwnerCurrentShield uint32 `json:"ownerCurrentShield" fieldDescription:"我方当前护盾"` +} + +// NoteUseSkillOutboundInfo 战斗技能使用通知的出站信息结构体 +type NoteUseSkillOutboundInfo struct { + FirstAttackInfo AttackValue // 本轮先手的精灵在释放技能结束后的状态 + SecondAttackInfo AttackValue // 本轮后手的精灵在释放技能结束后的状态 +} + +// 战斗逃跑 +type EscapeFightInboundInfo struct { + Head handler.TomeeHeader `cmd:"2410" struc:"[0]pad"` +} + +// FightOverInfo 战斗结束信息结构体 2506 +type FightOverInfo struct { + Reason uint32 // 固定值0 + WinnerId uint32 // 胜者的米米号 野怪为0 + TwoTimes uint32 // 双倍经验剩余次数 + ThreeTimes uint32 // 三倍经验剩余次数 + AutoFightTimes uint32 // 自动战斗剩余次数 + EnergyTimes uint32 // 能量吸收器剩余次数 + LearnTimes uint32 // 双倍学习器剩余次数 +} + +// HandleFightInviteInboundInfo 处理战斗邀请的入站消息 +// 回空包就行 +type HandleFightInviteInboundInfo struct { + Head handler.TomeeHeader `cmd:"2403" struc:"[0]pad"` + UserID uint32 `json:"userId" codec:"userId,uint"` // 邀请我对战人的userid + Flag uint32 `json:"flag" codec:"flag,uint"` // 1为同意对战 0为取消对战 + Mode uint32 `json:"mode" codec:"mode,uint"` // 战斗类型 1 = 1v1 2 = 6v6 +} + +// 2502的回复包 PVP邀请消息 +type NoteHandleFightInviteOutboundInfo struct { + UserID uint32 + Nickname string `struc:"[16]byte"` // 固定长度16字节 + Result uint32 // 0=拒绝 1=同意 2=在线超6小时 3=无出战精灵 4=不在线 +} + +// 实现入站消息接口(Go中通过方法集隐式实现) +type UseSkillInboundInfo struct { + Head handler.TomeeHeader `cmd:"2405" struc:"[0]pad"` + // 技能id, + SkillId uint32 +} + +type FightUserInfo struct { + // 用户ID(野怪为0),@UInt long + UserID uint32 `fieldDesc:"userID 如果为野怪则为0" ` + + // 玩家名称(野怪为UTF-8的'-',固定16字节) + // 使用[16]byte存储固定长度的字节数组 + Nick string `struc:"[16]byte"` +} + +// NoteReadyToFightInfo 战斗准备就绪消息结构体,NoteReadyToFightInfo +type NoteReadyToFightInfo struct { + MAXPET uint32 `struc:"skip"` //,最大精灵数 + //战斗发起者ID + OwnerID uint32 `struc:"skip"` + + AFinished bool `struc:"skip"` + BFinished bool `struc:"skip"` + // 战斗类型ID(与野怪战斗为3,与人战斗为1,前端似乎未使用) + // @UInt long + FightId EnumBattleMode `fieldDesc:"战斗类型ID 但前端好像没有用到 与野怪战斗为3,与人战斗似乎是1" ` + + // 我方信息 + OurInfo FightUserInfo `fieldDesc:"我方信息" serialize:"struct"` + Our *socket.Player `struc:"skip"` + OurPetListLen uint32 `struc:"sizeof=OurPetList"` + // 我方携带精灵的信息 + // ArrayList,使用切片模拟动态列表 + OurPetList []ReadyFightPetInfo `fieldDesc:"我方携带精灵的信息" serialize:"lengthFirst,lengthType=uint16,type=structArray"` + + // 对方信息 + OpponentInfo FightUserInfo `fieldDesc:"对方信息" serialize:"struct"` + Opp *socket.Player `struc:"skip"` + OpponentPetListLen uint32 `struc:"sizeof=OpponentPetList"` + // 敌方的精灵信息 + // 野怪战斗时:客户端接收此包前已生成精灵PetInfo,将部分信息写入该列表 + OpponentPetList []ReadyFightPetInfo `fieldDesc:"敌方的精灵信息 如果是野怪 那么再给客户端发送这个包体时就提前生成好了这只精灵的PetInfo,然后把从PetInfo中把部分信息写入到这个敌方的精灵信息中再发送这个包结构体" serialize:"lengthFirst,lengthType=uint16,type=structArray"` +} + +// 当A和B都 这时候给双方回复开始战斗包 +func (t *NoteReadyToFightInfo) onBothFinished() { + fmt.Println("A和B都已完成,触发onBothFinished") +} + +// ReadyFightPetInfo 准备战斗的精灵信息结构体,ReadyFightPetInfo类 +type ReadyFightPetInfo struct { + // 精灵ID,@UInt long + ID uint32 `fieldDesc:"精灵ID" ` + + // 精灵等级,@UInt long + Level uint32 `fieldDesc:"精灵等级" ` + + // 精灵当前HP,@UInt long + Hp uint32 `fieldDesc:"精灵HP" ` + + // 精灵最大HP,@UInt long + MaxHp uint32 `fieldDesc:"最大HP" ` + SkillListLen uint32 + // 技能信息列表(固定4个元素,技能ID和剩余PP,无技能则为0) + // List,初始化容量为4 + SkillList [4]model.SkillInfo `fieldDesc:"技能信息 技能ID跟剩余PP 固定32字节 没有给0" serialize:"fixedLength=4,type=structArray"` + + // 精灵捕获时间,@UInt long + CatchTime uint32 `fieldDesc:"精灵捕获时间" ` + + // 捕捉地图(固定给0),@UInt long + CatchMap uint32 `fieldDesc:"捕捉地图 给0" ` + + // 固定给0,@UInt long + CatchRect uint32 `fieldDesc:"给0" ` + + // 固定给0,@UInt long + CatchLevel uint32 `fieldDesc:"给0" ` + SkinID uint32 `fieldDesc:"精灵皮肤ID" ` + Shiny uint32 `fieldDesc:"精灵是否闪" ` +} diff --git a/logic/service/fight/info/invite.go b/logic/service/fight/info/invite.go deleted file mode 100644 index 58e6eac3f..000000000 --- a/logic/service/fight/info/invite.go +++ /dev/null @@ -1,18 +0,0 @@ -package info - -import "github.com/tnnmigga/enum" - -// 战斗模式 - -var BattleMode_PVP = enum.New[struct { - PVP_1V1 EnumBattleMode `enum:"1"` - PVP_6V6 EnumBattleMode `enum:"2"` -}]() -var Playerinvitemap map[uint32][]Playerinvite = make(map[uint32][]Playerinvite) //玩家邀请信息 ,比如一个玩家被多人邀请对战 - -type Playerinvite struct { //挂载到[]Playerinvite上? 被邀请者->邀请者 - InviteID uint32 // 邀请者 - InviteTime EnumBattleMode //游戏模式 -} - - diff --git a/logic/service/fight/pvp.go b/logic/service/fight/pvp.go deleted file mode 100644 index 0b1c8b972..000000000 --- a/logic/service/fight/pvp.go +++ /dev/null @@ -1,26 +0,0 @@ -package fight - -import "blazing/common/socket/handler" - -// HandleFightInviteInboundInfo 处理战斗邀请的入站消息 -// 回空包就行 -type HandleFightInviteInboundInfo struct { - Head handler.TomeeHeader `cmd:"2403" struc:"[0]pad"` - UserID uint32 `json:"userId" codec:"userId,uint"` // 邀请我对战人的userid - Flag uint32 `json:"flag" codec:"flag,uint"` // 1为同意对战 0为取消对战 - Mode uint32 `json:"mode" codec:"mode,uint"` // 战斗类型 1 = 1v1 2 = 6v6 -} - -// 2502的回复包 PVP邀请消息 -type NoteHandleFightInviteOutboundInfo struct { - UserID uint32 - Nickname string `struc:"[16]byte"` // 固定长度16字节 - Result uint32 // 0=拒绝 1=同意 2=在线超6小时 3=无出战精灵 4=不在线 -} - -// 实现入站消息接口(Go中通过方法集隐式实现) -type UseSkillInboundInfo struct { - Head handler.TomeeHeader `cmd:"2405" struc:"[0]pad"` - // 技能id, - SkillId uint32 -} diff --git a/logic/service/maps/Map_Ogre.go b/logic/service/maps/Map_Ogre.go deleted file mode 100644 index e2e145d5c..000000000 --- a/logic/service/maps/Map_Ogre.go +++ /dev/null @@ -1,11 +0,0 @@ -package maps - -type OgreInfo struct { - Data [9]OgrePetInfo -} - -type OgrePetInfo struct { - Id uint32 - Shiny uint32 - Lv uint32 `struc:"skip"` //等级 -} diff --git a/logic/service/maps/mapin.go b/logic/service/maps/mapin.go index 4fbee3c17..103c849aa 100644 --- a/logic/service/maps/mapin.go +++ b/logic/service/maps/mapin.go @@ -65,6 +65,7 @@ func (t *InInfo) SpawnMonsters(c *socket.Player, isfrist bool) { } t1 := t.genMonster(c.Info.MapID) if t1 != nil { + c.OgreInfo = t1 t1 := tt.Pack(t1) c.SendPack(t1) } @@ -80,16 +81,16 @@ func RandomStringFromSlice(s []string) string { } // 应该根据怪物信息决定后端生成 -func (t *InInfo) genMonster(mapid uint32) *OgreInfo { +func (t *InInfo) genMonster(mapid uint32) *socket.OgreInfo { // 设置怪物信息 - t1 := OgreInfo{} + t1 := socket.OgreInfo{} mapss, ok := xmlres.MonsterMap[gconv.Int(mapid)] if ok && mapss.Monsters != nil { for i, m := range mapss.Monsters.Monsters { //这里是9个 id := strings.Split(m.ID, " ") lv := strings.Split(m.Lv, " ") - ttt := OgrePetInfo{ + ttt := socket.OgrePetInfo{ Id: gconv.Uint32(RandomStringFromSlice(id)), } if ttt.Id != 0 { @@ -102,7 +103,7 @@ func (t *InInfo) genMonster(mapid uint32) *OgreInfo { } - t2 := OgreInfo{} + t2 := socket.OgreInfo{} for i := 0; i < 3; i++ { t2.Data[t.monsters[i]] = t1.Data[t.monsters[i]] diff --git a/logic/service/room/FitmentShowInfo.go b/logic/service/room/FitmentShowInfo.go index e6e80b2c8..9fc01f3a9 100644 --- a/logic/service/room/FitmentShowInfo.go +++ b/logic/service/room/FitmentShowInfo.go @@ -55,5 +55,17 @@ type FitmentAllInboundEmpty struct { type FitmentAllOutboundInfo struct { FitmentsLen uint32 `json:"fitmentsLen" struc:"sizeof=Fitments"` // 基地摆放物品的数组, 就算没有摆放物品, 也必带一个小屋的参数 - Fitments []FitmentShowInfo `codec:"auto" json:"fitments"` + Fitments []FitmentItemInfo `codec:"auto" json:"fitments"` +} + +// FitmentItemInfo 对应Java的FitmentItemInfo类 +type FitmentItemInfo struct { + // Id 家具id 或 默认房型id: 500001(对应Java的@UInt long id) + Id uint32 `json:"id"` + + // UsedCount 使用数量(默认房型id项目的使用数据固定为1)(对应Java的@UInt long usedCount) + UsedCount uint32 `json:"usedCount"` + + // AllCount 拥有数量(默认房型id项目的拥有数量固定为1)(对应Java的@UInt long allCount) + AllCount uint32 `json:"allCount"` } diff --git a/modules/blazing/model/pet.go b/modules/blazing/model/pet.go index d4c88d274..7a5536622 100644 --- a/modules/blazing/model/pet.go +++ b/modules/blazing/model/pet.go @@ -22,6 +22,16 @@ type Pet struct { Data string `gorm:"type:text;not null;comment:'精灵全部数据'" json:"data"` } +func LastFourElements[T any](s []T) []T { + n := len(s) + if n <= 4 { + // 切片长度小于等于4时,返回整个切片 + return s + } + // 切片长度大于4时,返回最后4个元素(从n-4索引到末尾) + return s[n-4:] +} + // * @param petTypeId 精灵类型ID // * @param individualValue 个体值 // * @param natureId 性格ID @@ -29,19 +39,19 @@ type Pet struct { // * @param isShiny 是否为闪光 // * @param level 等级 // * @return 生成的精灵实体 -func GenPetInfo(id, individual, natureId, abilityTypeEnum, shinyid, level uint32) *PetInfo { +func GenPetInfo(id, dv, natureId, abilityTypeEnum, shinyid, level uint32) *PetInfo { p := &PetInfo{ID: id, Shiny: shinyid, //闪光 Nature: natureId, //性格 - Dv: individual, + Dv: dv, EffectInfo: make([]PetEffectInfo, 0), CatchTime: uint32(time.Now().Unix()), Level: level} //等级 p.EffectInfo = append(p.EffectInfo, PetEffectInfo{ItemID: abilityTypeEnum}) - petxml := xmlres.PetMAP[int(id)] naxml := xmlres.NatureRootMap[int(natureId)] + petxml := xmlres.PetMAP[int(id)] tttt := make([]uint32, 0) for _, v := range petxml.LearnableMoves.Moves { if p.Level >= uint32(v.LearningLv) { @@ -50,6 +60,7 @@ func GenPetInfo(id, individual, natureId, abilityTypeEnum, shinyid, level uint32 } } + tttt = LastFourElements(tttt) //获取最后四个技能,如果不足,那就取全部技能 for i := 0; i < len(tttt); i++ { p.SkillList[i].ID = tttt[i] p.SkillList[i].Pp = uint32(xmlres.SkillMap[int(tttt[i])].MaxPP) diff --git a/public/oldswf/GroupFightDLL.swf b/public/oldswf/GroupFightDLL.swf new file mode 100644 index 000000000..534ca7701 Binary files /dev/null and b/public/oldswf/GroupFightDLL.swf differ