diff --git a/docs/effect-unimplemented-tasks/task-200-effects-1614-1619.md b/docs/effect-unimplemented-tasks/task-200-effects-1614-1619.md deleted file mode 100644 index 0dc1d65f4..000000000 --- a/docs/effect-unimplemented-tasks/task-200-effects-1614-1619.md +++ /dev/null @@ -1,37 +0,0 @@ -# Task 200: Effects 1614-1619 - -## 目标 - -- 补齐以下 5 个(或最后一组不足 5 个)当前判定未实现的 skill effect。 -- 实现位置优先放在 `logic/service/fight/effect/`。 -- 如 effect 需要展示说明,同步更新 `logic/service/fight/effect/effect_info_map.go`。 -- 完成后至少执行:`cd /workspace/logic && go test ./service/fight/effect`。 - -## Effect 列表 - -### Effect 1614 -- `argsNum`: `4` -- `info`: `{0}回合内对手使用攻击技能后{1}%令对手{2},未触发则令对手全属性-{3}` -- `param`: `1,2,2` - -### Effect 1616 -- `argsNum`: `0` -- `info`: `当回合使用的技能克制对手时获得本系属性加成` - -### Effect 1617 -- `argsNum`: `4` -- `info`: `{0}回合内受到攻击后{1}%使对手{2},未触发则自身全属性+{3}` -- `param`: `1,2,2` - -### Effect 1618 -- `argsNum`: `2` -- `info`: `{0}回合内每回合结束时令对手随机{1}个技能PP值归零` - -### Effect 1619 -- `argsNum`: `0` -- `info`: `50%复制对手当回合释放的技能,未触发则恢复自身最大体力的1/2且令对手全属性-1` - -## 备注 - -- 该清单按当前仓库静态注册结果生成;如果某个 effect 实际通过其他模块或运行时路径实现,需要先复核后再落代码。 -- 对 `201`、`445` 这类占位 effect,优先补核心逻辑或补充明确的不可实现说明。 diff --git a/docs/fight-multi-battle-refactor-task-2026-04-04.md b/docs/fight-multi-battle-refactor-task-2026-04-04.md new file mode 100644 index 000000000..48eb22eb0 --- /dev/null +++ b/docs/fight-multi-battle-refactor-task-2026-04-04.md @@ -0,0 +1,283 @@ +# 战斗多单位模式改造交接文档(2026-04-04) + +## 1. 任务目标 + +将当前战斗系统从“每回合双方各 1 个动作”的模型,改造成支持多上场位、多操作者的统一回合模型,最终支持以下 3 种战斗模式: + +1. `1玩家:N精灵:1上场 VS 1玩家:N精灵:1上场` +2. `N玩家:N精灵:N上场 VS N玩家:N精灵:N上场` +3. `1玩家:N精灵:N上场 VS 1玩家:N精灵:N上场` + +当前代码只完整支持模式 1。模式 2 和模式 3 只做了结构铺垫,还没有真正打通。 + +--- + +## 2. 当前已完成的基础改造 + +以下结构改造已经落地: + +- `FightC.Our/Opp` 已改成数组,表示战场单位数组,不再是单对象。 +- `input.Input.CurrentPet` 已改成 `CurPet`,并且是数组。 +- `FightC.OurPlayers/OppPlayers` 已加入,用于表达操作者数组。 +- 战斗单位与操作者已解耦: + - `Our/Opp` 表示战斗位 + - `OurPlayers/OppPlayers` 表示操作这些战斗位的玩家 +- `BattlePetEntity` 已支持绑定控制者:`ControllerUserID` +- 动作模型已支持: + - `ActorIndex` + - `TargetIndex` +- 已提供 indexed 入口: + - `UseSkillAt(c, skillID, actorIndex, targetIndex)` + - `ChangePetAt(c, petID, actorIndex)` + - `UseItemAt(c, catchTime, itemID, actorIndex, targetIndex)` + +当前默认行为仍等价于: + +- `actorIndex = 0` +- `targetIndex = 0` + +也就是当前模式下仍然是操作和结算 `0` 号单位。 + +--- + +## 3. 当前未完成的核心问题 + +### 3.1 回合模型仍然是“双动作模型” + +目前主流程仍然是每回合只处理双方两个动作,而不是处理一个动作列表。 + +关键位置: + +- `logic/service/fight/loop.go` + - `collectPlayerActions(...)` 只收 2 个动作 + - `resolveRound(p1Action, p2Action)` 只结算 2 个动作 + +这意味着: + +- 模式 2 无法支持双方多个操作者或多个上场位同时行动 +- 模式 3 无法支持同一玩家控制多个上场位分别出手 + +### 3.2 动作提交仍按 `playerID` 去重 + +当前动作队列逻辑仍以 `playerID` 作为主要识别维度。 + +关键位置: + +- `logic/service/fight/action.go` + - `submitAction(...)` + +这会导致: + +- 同一玩家在同一回合给多个上场位下达动作时,动作会互相覆盖或无法完整保留 + +这一点对模式 3 是直接阻塞,对模式 2 也不够健壮。 + +### 3.3 切宠和当前上场位逻辑仍大量默认使用 `CurPet[0]` + +虽然 `CurPet` 已经是数组,但主流程中不少逻辑仍固定操作 `0` 号位。 + +典型影响: + +- 死亡换宠 +- 主动换宠 +- 当前出手单位检查 +- 当前目标单位检查 + +这部分需要按 `actorIndex` 或上场槽位改造。 + +### 3.4 开战协议仍然只有两个当前单位 + +当前开战下发协议仍然是双单位结构。 + +关键位置: + +- `logic/service/fight/info/info.go` + - `FightStartOutboundInfo` + - 仍只有 `Info1` 和 `Info2` + +这不适合多上场位模式。 + +### 3.5 公共接口仍是旧的单单位接口 + +关键位置: + +- `logic/service/common/fight.go` + - `FightI` + +目前接口仍只有: + +- `UseSkill(c, id)` +- `ChangePet(c, id)` +- `UseItem(c, cacthid, itemid)` + +而 indexed 版本只存在于具体实现 `FightC` 上,没有进入正式接口层。 + +--- + +## 4. 当前实现与目标模式的对应关系 + +### 4.1 模式 1 + +`1玩家:N精灵:1上场 VS 1玩家:N精灵:1上场` + +当前支持。 + +原因: + +- 当前默认就是操作 `0` 号单位 +- 当前默认就是攻击 `0` 号目标 +- 当前回合系统仍是每边 1 个动作,这与模式 1 一致 + +### 4.2 模式 2 + +`N玩家:N精灵:N上场 VS N玩家:N精灵:N上场` + +当前不支持。 + +直接原因: + +- 一回合只收 2 个动作 +- 一回合只结算 2 个动作 +- 协议仍只同步 2 个当前上场位 + +### 4.3 模式 3 + +`1玩家:N精灵:N上场 VS 1玩家:N精灵:N上场` + +当前不支持。 + +直接原因: + +- 同一玩家的多个动作无法作为同回合动作列表完整保留 +- 主流程仍不是按动作列表统一排序和执行 + +--- + +## 5. 需要完成的工作 + +### 5.1 改造动作收集模型 + +将当前“每边 1 个动作”的模型改成“每个可操作上场位 1 个动作”的模型。 + +至少需要做到: + +- 同一玩家可以在同一回合提交多个动作 +- 每个动作能区分是哪个上场位发出的 +- 每个动作能区分目标上场位 + +建议将动作唯一键至少扩为: + +- `playerID` +- `actorIndex` + +### 5.2 改造回合结算模型 + +将当前: + +- `resolveRound(p1Action, p2Action)` + +改成: + +- `resolveRound(actions []action.BattleActionI)` + +并完成: + +- 动作列表排序 +- 按优先级、速度等规则统一排序 +- 排序后逐个结算 + +注意: + +- 当前 effect/node 体系里仍有大量“双动作”接口,不适合一次性全部重写 +- 建议先在主流程做兼容层,逐步过渡 + +### 5.3 按槽位处理切宠与死亡换宠 + +将当前固定 `CurPet[0]` 的逻辑改成按槽位处理: + +- 主动换宠 +- 被动死亡换宠 +- 死亡校验 +- 出手资格判断 + +### 5.4 增加开战与战斗同步结构 + +将当前的双单位同步结构扩成可支持多上场位的结构。但是保持协议结构不变。现在是固定两个,可以改成数组来实现 + +重点是: + +- 开战协议 +- 当前上场位同步 +- 切宠同步 +- 可能的回合播报结构 + +### 5.5 补齐公共接口 + +将 indexed 版本能力补进接口层,避免只能通过具体实现类型访问。 + +建议新增类似接口: + +- `UseSkillAt(...)` +- `ChangePetAt(...)` +- `UseItemAt(...)` + +--- + +## 6. 推荐实施顺序 + +建议按下面顺序推进,避免一次性改动面过大: + +1. 先改动作队列和动作收集逻辑 +2. 再改回合结算为动作列表 +3. 再改切宠和死亡换宠按槽位处理 +4. 最后改协议和正式接口 + +不建议一开始就全量重写 effect/node 接口,因为当前大量效果实现仍假设双动作上下文。 + +--- + +## 7. 建议重点查看文件 + +- `logic/service/fight/action.go` +- `logic/service/fight/loop.go` +- `logic/service/fight/fightc.go` +- `logic/service/fight/input.go` +- `logic/service/fight/input/input.go` +- `logic/service/fight/action/BattleAction.go` +- `logic/service/fight/info/info.go` +- `logic/service/common/fight.go` + +--- + +## 8. 完成标准 + +至少满足以下条件,才算这次改造完成: + +1. 同一玩家可以在同一回合给多个上场位分别提交动作,动作不会互相覆盖 +2. 双方多个上场位可以在同一回合统一排序并依次结算 +3. 攻击目标位可选,不再默认只能打对面 `0` 号 +4. 切宠可以按上场槽位处理 +5. 模式 1 不回归 +6. 代码编译通过 + +--- + +## 9. 最低验证要求 + +至少执行: + +- `cd /workspace/logic && go build ./...` +- `cd /workspace/logic && go test ./service/fight/effect` + +如果本轮改动较大,建议再补一轮: + +- `cd /workspace/logic && go test ./...` + +--- + +## 10. 额外提醒 + +- 当前仓库工作区可能是脏的,不要回滚无关修改。 +- 这次改造的真正核心不是结构字段改数组,而是把回合系统从“双动作模型”改成“动作列表模型”。 +- 已有 `ActorIndex/TargetIndex` 只是入口铺垫,不代表多单位模式已经完成。 + diff --git a/logic/controller/systemtime.go b/logic/controller/systemtime.go index 61065c8f8..bceeb7b81 100644 --- a/logic/controller/systemtime.go +++ b/logic/controller/systemtime.go @@ -23,5 +23,5 @@ type InInfo struct { //这里直接使用组合来实现将传入的原始头部 // OutInfo 表示系统时间的出站消息 type OutInfo struct { - SystemTime uint32 `json:"systemTime"` // @UInt long类型 + SystemTime uint32 `json:"systemTime"` } diff --git a/logic/service/fight/action.go b/logic/service/fight/action.go index cd0d7409f..1962bda1d 100644 --- a/logic/service/fight/action.go +++ b/logic/service/fight/action.go @@ -6,7 +6,6 @@ import ( "blazing/logic/service/fight/info" "blazing/logic/service/fight/input" "blazing/modules/player/model" - "github.com/jinzhu/copier" ) @@ -40,7 +39,7 @@ func (f *FightC) closeActionWindow() { f.pendingActions = f.pendingActions[:0] f.actionRound.Store(0) f.actionMu.Unlock() - + } func (f *FightC) submitAction(act action.BattleActionI) { @@ -225,6 +224,10 @@ func (f *FightC) Capture(c common.PlayerI, id uint32) { } +func (f *FightC) c(c common.PlayerI, cacthid, itemid uint32) { + f.UseItemAt(c, cacthid, itemid, 0, 0) +} + func (f *FightC) UseItem(c common.PlayerI, cacthid, itemid uint32) { f.UseItemAt(c, cacthid, itemid, 0, 0) } diff --git a/logic/service/fight/cmd.go b/logic/service/fight/cmd.go index 9c09ee23f..3dc569944 100644 --- a/logic/service/fight/cmd.go +++ b/logic/service/fight/cmd.go @@ -64,8 +64,8 @@ type ARENA_OWENR_ACCE struct { // 表示"宠物王加入"的入站消息数据 type PetKingJoinInboundInfo struct { Head common.TomeeHeader `cmd:"2413" struc:"skip"` - Type uint32 // 战斗类型:5=单精灵,6=多精灵,11=精灵大师赛 (对应Java的@UInt long type) - FightType uint32 // 仅当Type为11时有效 (对应Java的@UInt long fightType) + Type uint32 // 战斗类型:5=单精灵,6=多精灵,11=精灵大师赛 + FightType uint32 // 仅当Type为11时有效 } // HandleFightInviteInboundInfo 处理战斗邀请的入站消息 @@ -122,13 +122,13 @@ type LoadPercentInboundInfo struct { type UsePetItemInboundInfo struct { Head common.TomeeHeader `cmd:"2406" struc:"skip"` // 字段首字母大写以导出(对应Java的可访问性,配合@Data的getter/setter) - CatchTime uint32 `description:"精灵捕获时间" codec:"catchTime"` // @UInt long 对应Go的uint32(无符号64位) + CatchTime uint32 `description:"精灵捕获时间" codec:"catchTime"` ItemId uint32 `description:"使用的物品ID" codec:"itemId"` // 结构体标签模拟@FieldDescription和@AutoCodec注解 Reversed1 uint32 `description:"填充字段 0" codec:"reversed1"` // reversed1对应原Java的填充字段 } type ChatInfo struct { Head common.TomeeHeader `cmd:"50002" struc:"skip"` - Reserve uint32 `json:"reserve" fieldDescription:"填充 默认值为0" uint:"true"` // @UInt long reserve,无符号长整数 + Reserve uint32 `json:"reserve" fieldDescription:"填充 默认值为0" uint:"true"` MessageLen uint32 `struc:"sizeof=Message"` Message string `json:"message" fieldDescription:"消息内容, 结束符为utf-8的数字0"` // 消息内容,包含utf-8空字符('\x00')作为结束符 } diff --git a/logic/service/fight/effect/1609_1613.go b/logic/service/fight/effect/1609_1613.go index 0e35185c2..d276fa122 100644 --- a/logic/service/fight/effect/1609_1613.go +++ b/logic/service/fight/effect/1609_1613.go @@ -98,6 +98,7 @@ func (e *Effect1610Sub) SkillHit_ex() bool { return true } e.Ctx().SkillEntity.SetNoSide() + e.Ctx().SkillEntity.AttackTime = 0 return true } diff --git a/logic/service/fight/effect/1614_1619.go b/logic/service/fight/effect/1614_1619.go new file mode 100644 index 000000000..e6af93de6 --- /dev/null +++ b/logic/service/fight/effect/1614_1619.go @@ -0,0 +1,211 @@ +package effect + +import ( + element "blazing/common/data/Element" + "blazing/logic/service/fight/action" + "blazing/logic/service/fight/info" + "blazing/logic/service/fight/input" + "blazing/logic/service/fight/node" + + "github.com/alpacahq/alpacadecimal" +) + +// Effect 1614: {0}回合内对手使用攻击技能后{1}%令对手{2},未触发则令对手全属性-{3} +type Effect1614 struct{ node.EffectNode } + +func (e *Effect1614) Skill_Use() bool { + if len(e.Args()) < 4 || e.Ctx().Opp == nil { + return true + } + sub := e.Ctx().Opp.InitEffect(input.EffectType.Sub, 1614, e.SideEffectArgs...) + if sub != nil { + e.Ctx().Opp.AddEffect(e.Ctx().Our, sub) + } + return true +} + +type Effect1614Sub struct { + RoundEffectSideArg0Base + attempted bool + triggered bool +} + +func (e *Effect1614Sub) Skill_Use() bool { + if e.triggered || e.attempted || len(e.Args()) < 4 { + return true + } + skill := e.Ctx().SkillEntity + if skill == nil || skill.Category() == info.Category.STATUS { + return true + } + e.attempted = true + if ok, _, _ := e.Input.Player.Roll(int(e.Args()[1].IntPart()), 100); ok { + if addStatusByID(e.Ctx().Opp, e.Ctx().Our, int(e.Args()[2].IntPart())) { + e.triggered = true + e.Alive(false) + } + } + return true +} + +func (e *Effect1614Sub) TurnEnd() { + if e.Duration() == 1 && !e.triggered && len(e.Args()) >= 4 { + applyAllPropDown(e.Ctx().Opp, e.Ctx().Our, int8(e.Args()[3].IntPart())) + } + e.EffectNode.TurnEnd() +} + +// Effect 1616: 当回合使用的技能克制对手时获得本系属性加成 +type Effect1616 struct{ node.EffectNode } + +func (e *Effect1616) Damage_Mul(zone *info.DamageZone) bool { + if zone == nil || zone.Type != info.DamageType.Red || e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.Category() == info.Category.STATUS { + return true + } + if e.Ctx().Opp == nil || e.Ctx().Opp.CurPet[0] == nil { + return true + } + mul, err := element.Calculator.GetOffensiveMultiplier(e.Ctx().SkillEntity.GetType().ID, e.Ctx().Opp.CurPet[0].GetType().ID) + if err != nil || mul <= 1 { + return true + } + zone.Damage = zone.Damage.Mul(hundred.Add(alpacadecimal.NewFromInt(20))).Div(hundred) + return true +} + +// Effect 1617: {0}回合内受到攻击后{1}%使对手{2},未触发则自身全属性+{3} +type Effect1617 struct{ node.EffectNode } + +func (e *Effect1617) Skill_Use() bool { + if len(e.Args()) < 4 || e.Ctx().Opp == nil { + return true + } + sub := e.Ctx().Opp.InitEffect(input.EffectType.Sub, 1617, e.SideEffectArgs...) + if sub != nil { + e.Ctx().Opp.AddEffect(e.Ctx().Our, sub) + } + return true +} + +type Effect1617Sub struct { + RoundEffectSideArg0Base + attempted bool + triggered bool +} + +func (e *Effect1617Sub) Skill_Use() bool { + if e.triggered || e.attempted || len(e.Args()) < 4 { + return true + } + skill := e.Ctx().SkillEntity + if skill == nil || skill.Category() == info.Category.STATUS { + return true + } + e.attempted = true + if ok, _, _ := e.Input.Player.Roll(int(e.Args()[1].IntPart()), 100); ok { + if addStatusByID(e.Ctx().Opp, e.Ctx().Our, int(e.Args()[2].IntPart())) { + e.triggered = true + e.Alive(false) + } + } + return true +} + +func (e *Effect1617Sub) TurnEnd() { + if e.Duration() == 1 && !e.triggered && len(e.Args()) >= 4 { + applyAllPropUp(e.Ctx().Opp, int8(e.Args()[3].IntPart())) + } + e.EffectNode.TurnEnd() +} + +// Effect 1618: {0}回合内每回合结束时令对手随机{1}个技能PP值归零 +type Effect1618 struct{ node.EffectNode } + +func (e *Effect1618) Skill_Use() bool { + if len(e.Args()) < 2 || e.Ctx().Opp == nil { + return true + } + sub := e.Ctx().Our.InitEffect(input.EffectType.Sub, 1618, e.SideEffectArgs...) + if sub != nil { + e.Ctx().Our.AddEffect(e.Ctx().Our, sub) + } + return true +} + +type Effect1618Sub struct{ RoundEffectArg0Base } + +func (e *Effect1618Sub) TurnEnd() { + if e.Duration() > 0 && len(e.Args()) >= 2 && e.Ctx().Opp != nil { + count := int(e.Args()[1].IntPart()) + zeroRandomSkillPP(e.Ctx().Opp, count) + } + e.EffectNode.TurnEnd() +} + +// Effect 1619: 50%复制对手当回合释放的技能,未触发则恢复自身最大体力的1/2且令对手全属性-1 +type Effect1619 struct { + node.EffectNode + copyAttempted bool + copySucceeded bool + fallbackApplied bool +} + +func (e *Effect1619) ActionStart(fattack, sattack *action.SelectSkillAction) bool { + if e.copyAttempted || e.Ctx().Opp == nil { + return true + } + current := actionByPlayer(fattack, sattack, e.Ctx().Our.UserID) + if current == nil || current.SkillEntity == nil { + return true + } + opponent := actionByPlayer(fattack, sattack, e.Ctx().Opp.UserID) + if opponent == nil || opponent.SkillEntity == nil || opponent.SkillEntity.Category() == info.Category.STATUS { + return true + } + e.copyAttempted = true + if ok, _, _ := e.Input.Player.Roll(50, 100); !ok { + return true + } + clone := cloneSkillEntity(opponent.SkillEntity) + if clone == nil { + return true + } + current.SkillEntity = clone + e.copySucceeded = true + return true +} + +func (e *Effect1619) Skill_Use() bool { + if !e.copyAttempted || e.copySucceeded || e.fallbackApplied || e.Ctx().Opp == nil || e.Ctx().Our == nil || e.Ctx().Our.CurPet[0] == nil { + return true + } + heal := e.Ctx().Our.CurPet[0].GetMaxHP().Div(alpacadecimal.NewFromInt(2)) + if heal.Cmp(alpacadecimal.Zero) > 0 { + e.Ctx().Our.Heal( + e.Ctx().Our, + &action.SelectSkillAction{BaseAction: action.BaseAction{PlayerID: e.Ctx().Our.UserID}}, + heal, + ) + } + applyAllPropDown(e.Ctx().Opp, e.Ctx().Our, 1) + e.fallbackApplied = true + return true +} + +func (e *Effect1619) TurnEnd() { + e.copyAttempted = false + e.copySucceeded = false + e.fallbackApplied = false + e.EffectNode.TurnEnd() +} + +func init() { + input.InitEffect(input.EffectType.Skill, 1614, &Effect1614{}) + input.InitEffect(input.EffectType.Sub, 1614, &Effect1614Sub{}) + input.InitEffect(input.EffectType.Skill, 1616, &Effect1616{}) + input.InitEffect(input.EffectType.Skill, 1617, &Effect1617{}) + input.InitEffect(input.EffectType.Sub, 1617, &Effect1617Sub{}) + input.InitEffect(input.EffectType.Skill, 1618, &Effect1618{}) + input.InitEffect(input.EffectType.Sub, 1618, &Effect1618Sub{}) + input.InitEffect(input.EffectType.Skill, 1619, &Effect1619{}) +} diff --git a/logic/service/fight/effect/1620_1624.go b/logic/service/fight/effect/1620_1624.go index 49c74c073..c854e3a63 100644 --- a/logic/service/fight/effect/1620_1624.go +++ b/logic/service/fight/effect/1620_1624.go @@ -110,9 +110,9 @@ func (e *Effect1622Sub) SkillHit_ex() bool { if count <= 0 || percent <= 0 { return true } - sub := e.Ctx().Our.InitEffect(input.EffectType.Sub, 16221, count, percent) + sub := e.Ctx().Opp.InitEffect(input.EffectType.Sub, 16221, count, percent) if sub != nil { - e.Ctx().Our.AddEffect(e.Ctx().Our, sub) + e.Ctx().Opp.AddEffect(e.Ctx().Opp, sub) } return true } diff --git a/logic/service/fight/effect/1625_1629.go b/logic/service/fight/effect/1625_1629.go new file mode 100644 index 000000000..ed1520937 --- /dev/null +++ b/logic/service/fight/effect/1625_1629.go @@ -0,0 +1,267 @@ +package effect + +import ( + "blazing/logic/service/fight/action" + "blazing/logic/service/fight/info" + "blazing/logic/service/fight/input" + "blazing/logic/service/fight/node" + + "github.com/alpacahq/alpacadecimal" + "github.com/gogf/gf/v2/util/grand" +) + +// Effect 1625: 造成的伤害高于{0}则{1}%令自身全属性+{2} +type Effect1625 struct{ node.EffectNode } + +func (e *Effect1625) Skill_Use() bool { + if len(e.Args()) < 3 || e.Ctx().Our.SumDamage.Cmp(e.Args()[0]) <= 0 { + return true + } + if ok, _, _ := e.Input.Player.Roll(int(e.Args()[1].IntPart()), 100); ok { + applyAllPropUp(e.Ctx().Our, int8(e.Args()[2].IntPart())) + } + return true +} + +// Effect 1626: 后出手时将当回合护盾所承受的伤害值以百分比伤害的形式{0}%反弹给对手 +type Effect1626 struct{ node.EffectNode } + +func (e *Effect1626) ComparePre(fattack, sattack *action.SelectSkillAction) bool { + current := actionByPlayer(fattack, sattack, e.Ctx().Our.UserID) + if current == nil || fattack == nil || fattack.PlayerID == e.Ctx().Our.UserID || len(e.Args()) == 0 { + return true + } + sub := e.Ctx().Our.InitEffect(input.EffectType.Sub, 1626, int(e.Args()[0].IntPart())) + if sub != nil { + e.Ctx().Our.AddEffect(e.Ctx().Our, sub) + } + return true +} + +type Effect1626Sub struct { + FixedDuration1Base + absorbed alpacadecimal.Decimal +} + +func (e *Effect1626Sub) Damage_Shield(zone *info.DamageZone) bool { + if zone == nil || zone.Damage.Cmp(alpacadecimal.Zero) <= 0 { + return true + } + absorbed := alpacadecimal.Min(e.Ctx().Our.CurrentShield(), zone.Damage) + if absorbed.Cmp(alpacadecimal.Zero) <= 0 { + return true + } + e.absorbed = e.absorbed.Add(absorbed) + return true +} + +func (e *Effect1626Sub) TurnEnd() { + if len(e.Args()) > 0 && e.absorbed.Cmp(alpacadecimal.Zero) > 0 { + damage := e.absorbed.Mul(e.Args()[0]).Div(hundred) + if damage.Cmp(alpacadecimal.Zero) > 0 { + e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{Type: info.DamageType.Percent, Damage: damage}) + } + } + e.EffectNode.TurnEnd() +} + +// Effect 1627: {0}回合做{1}-{2}次攻击,若本回合攻击次数达到最大则必定秒杀对手 +type Effect1627 struct{ node.EffectNode } + +func (e *Effect1627) Skill_Use() bool { + if len(e.Args()) < 3 { + return true + } + sub := e.Ctx().Our.InitEffect(input.EffectType.Sub, 1627, e.SideEffectArgs...) + if sub != nil { + e.Ctx().Our.AddEffect(e.Ctx().Our, sub) + } + return true +} + +type Effect1627Sub struct { + RoundEffectArg0Base + ohko bool +} + +func (e *Effect1627Sub) SkillHit() bool { + e.ohko = false + if len(e.Args()) < 3 || e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.Category() == info.Category.STATUS || e.Ctx().SkillEntity.AttackTime == 0 { + return true + } + minHits := int(e.Args()[1].IntPart()) + maxHits := int(e.Args()[2].IntPart()) + if minHits <= 0 { + minHits = 1 + } + if maxHits < minHits { + maxHits = minHits + } + + hits := minHits + if maxHits > minHits { + hits += grand.Intn(maxHits - minHits + 1) + } + if hits > 1 { + e.Ctx().SkillEntity.AttackTime += uint32(hits - 1) + } + e.ohko = hits == maxHits + return true +} + +func (e *Effect1627Sub) OnSkill() bool { + if !e.ohko || e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.AttackTime == 0 || e.Ctx().Opp == nil || e.Ctx().Opp.CurPet[0] == nil || e.Ctx().Opp.CurPet[0].Info.Hp == 0 { + return true + } + e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{ + Type: info.DamageType.Fixed, + Damage: e.Ctx().Opp.CurPet[0].GetHP(), + }) + return true +} + +// Effect 1628: 每次使用该技能击败对手则恢复自身全部体力,同时重置该技能使用次数并使该技能攻击威力提升{0}点,未击败对手时令自身下回合攻击技能先制+{1} +type Effect1628 struct { + node.EffectNode + bonusPower int +} + +func (e *Effect1628) SetArgs(t *input.Input, a ...int) { + e.EffectNode.SetArgs(t, a...) + if old := t.GetEffect(input.EffectType.Skill, 1628); old != nil { + if prev, ok := old.(*Effect1628); ok { + e.bonusPower = prev.bonusPower + } + } +} + +func (e *Effect1628) SkillHit() bool { + if e.bonusPower == 0 || e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.Category() == info.Category.STATUS { + return true + } + e.Ctx().SkillEntity.XML.Power += e.bonusPower + return true +} + +func (e *Effect1628) Skill_Use() bool { + if len(e.Args()) < 2 || e.Ctx().Our == nil || e.Ctx().Our.CurPet[0] == nil || e.Ctx().Opp == nil || e.Ctx().Opp.CurPet[0] == nil { + return true + } + if e.Ctx().Opp.CurPet[0].Info.Hp == 0 { + e.Ctx().Our.Heal(e.Ctx().Our, &action.SelectSkillAction{}, e.Ctx().Our.CurPet[0].GetMaxHP()) + if e.Ctx().SkillEntity != nil && e.Ctx().SkillEntity.Info != nil { + e.Ctx().SkillEntity.Info.PP = uint32(e.Ctx().SkillEntity.XML.MaxPP) + } + e.bonusPower += int(e.Args()[0].IntPart()) + return true + } + + sub := e.Ctx().Our.InitEffect(input.EffectType.Sub, 1628, int(e.Args()[1].IntPart())) + if sub != nil { + e.Ctx().Our.AddEffect(e.Ctx().Our, sub) + } + return true +} + +type Effect1628Sub struct { + node.EffectNode + remaining int + priority int +} + +func (e *Effect1628Sub) SetArgs(t *input.Input, a ...int) { + e.EffectNode.SetArgs(t, a...) + e.Duration(-1) + e.CanStack(false) + e.remaining = 1 + if len(a) > 0 { + e.priority = a[0] + } +} + +func (e *Effect1628Sub) ComparePre(fattack, sattack *action.SelectSkillAction) bool { + if e.remaining <= 0 { + e.Alive(false) + return true + } + current := actionByPlayer(fattack, sattack, e.Ctx().Our.UserID) + if current == nil || current.SkillEntity == nil || current.SkillEntity.Category() == info.Category.STATUS { + return true + } + current.SkillEntity.XML.Priority += e.priority + e.remaining-- + if e.remaining <= 0 { + e.Alive(false) + } + return true +} + +// Effect 1629: {0}基础速度值{1}{2}则自身下回合先制+{3} +type Effect1629 struct{ node.EffectNode } + +func (e *Effect1629) Skill_Use() bool { + if len(e.Args()) < 4 { + return true + } + compareTarget := e.Ctx().Our + if int(e.Args()[1].IntPart()) != 0 { + compareTarget = e.Ctx().Opp + } + if compareTarget == nil || compareTarget.CurPet[0] == nil { + return true + } + speed := alpacadecimal.NewFromInt(int64(compareTarget.CurPet[0].PetInfo.Spd)) + if !effectCompareByMode(int(e.Args()[2].IntPart()), speed, e.Args()[0]) { + return true + } + sub := e.Ctx().Our.InitEffect(input.EffectType.Sub, 1629, int(e.Args()[3].IntPart())) + if sub != nil { + e.Ctx().Our.AddEffect(e.Ctx().Our, sub) + } + return true +} + +type Effect1629Sub struct { + node.EffectNode + remaining int + priority int +} + +func (e *Effect1629Sub) SetArgs(t *input.Input, a ...int) { + e.EffectNode.SetArgs(t, a...) + e.Duration(-1) + e.CanStack(false) + e.remaining = 1 + if len(a) > 0 { + e.priority = a[0] + } +} + +func (e *Effect1629Sub) ComparePre(fattack, sattack *action.SelectSkillAction) bool { + if e.remaining <= 0 { + e.Alive(false) + return true + } + current := actionByPlayer(fattack, sattack, e.Ctx().Our.UserID) + if current == nil || current.SkillEntity == nil { + return true + } + current.SkillEntity.XML.Priority += e.priority + e.remaining-- + if e.remaining <= 0 { + e.Alive(false) + } + return true +} + +func init() { + input.InitEffect(input.EffectType.Skill, 1625, &Effect1625{}) + input.InitEffect(input.EffectType.Skill, 1626, &Effect1626{}) + input.InitEffect(input.EffectType.Sub, 1626, &Effect1626Sub{}) + input.InitEffect(input.EffectType.Skill, 1627, &Effect1627{}) + input.InitEffect(input.EffectType.Sub, 1627, &Effect1627Sub{}) + input.InitEffect(input.EffectType.Skill, 1628, &Effect1628{}) + input.InitEffect(input.EffectType.Sub, 1628, &Effect1628Sub{}) + input.InitEffect(input.EffectType.Skill, 1629, &Effect1629{}) + input.InitEffect(input.EffectType.Sub, 1629, &Effect1629Sub{}) +} diff --git a/logic/service/fight/effect/1630_1634.go b/logic/service/fight/effect/1630_1634.go index 67ed68ddf..5ee5b697a 100644 --- a/logic/service/fight/effect/1630_1634.go +++ b/logic/service/fight/effect/1630_1634.go @@ -27,7 +27,7 @@ func (e *Effect1630) ComparePre(fattack, sattack *action.SelectSkillAction) bool if current == nil || current.SkillEntity == nil || oppAction == nil || oppAction.SkillEntity == nil { return true } - if oppAction.SkillEntity.Category() == info.Category.STATUS || current.SkillEntity.Category() == info.Category.STATUS { + if oppAction.SkillEntity.Category() == info.Category.STATUS { return true } current.SkillEntity.XML.Priority = math.MaxInt @@ -36,7 +36,7 @@ func (e *Effect1630) ComparePre(fattack, sattack *action.SelectSkillAction) bool } func (e *Effect1630) OnSkill() bool { - if !e.armed || len(e.Args()) < 2 || e.Ctx().Opp == nil { + if !e.armed || len(e.Args()) < 2 || e.Ctx().Opp == nil || e.Ctx().SkillEntity == nil || e.Ctx().SkillEntity.AttackTime == 0 { return true } chance := int(e.Args()[0].IntPart()) @@ -181,7 +181,7 @@ func (e *Effect1634) ComparePre(fattack, sattack *action.SelectSkillAction) bool return true } current := actionByPlayer(fattack, sattack, e.Ctx().Our.UserID) - if current == nil || current.SkillEntity == nil || current.SkillEntity.Category() == info.Category.STATUS { + if current == nil || current.SkillEntity == nil { return true } current.SkillEntity.XML.Priority = math.MaxInt diff --git a/logic/service/fight/effect/effect_info_map.go b/logic/service/fight/effect/effect_info_map.go index c7a4322dc..68f34d615 100644 --- a/logic/service/fight/effect/effect_info_map.go +++ b/logic/service/fight/effect/effect_info_map.go @@ -1073,11 +1073,21 @@ var effectInfoByID = map[int]string{ 1611: "攻击命中后5%的概率汲取泰坦源脉的力量,本次攻击造成5倍伤害且战斗结束后获得5000泰坦之灵(每日上限50000)", 1612: "{0}回合内受到的伤害低于{1}时{2}%令对手{3},未触发则附加{4}点固定伤害", 1613: "自身不处于能力提升状态则吸取对手{0}点体力,若先出手则额外吸取{1}点体力", + 1614: "{0}回合内对手使用攻击技能后{1}%令对手{2},未触发则令对手全属性-{3}", + 1616: "当回合使用的技能克制对手时获得本系属性加成", + 1617: "{0}回合内受到攻击后{1}%使对手{2},未触发则自身全属性+{3}", + 1618: "{0}回合内每回合结束时令对手随机{1}个技能PP值归零", + 1619: "50%复制对手当回合释放的技能,未触发则恢复自身最大体力的1/2且令对手全属性-1", 1620: "对手基础速度值高于{0}则下回合先制-1", 1621: "{0}%令对手所有技能PP值-{1},自身满体力时效果翻倍", 1622: "{0}回合内每回合{1}%对手属性技能无效,未触发则下{2}次受到的攻击伤害减少{3}%", 1623: "若对手是{0}精灵则下{1}回合对手受到的伤害提高{2}%", 1624: "对手不处于异常状态时随机附加{0}种异常状态", + 1625: "造成的伤害高于{0}则{1}%令自身全属性+{2}", + 1626: "后出手时将当回合护盾所承受的伤害值以百分比伤害的形式{0}%反弹给对手", + 1627: "{0}回合做{1}-{2}次攻击,若本回合攻击次数达到最大则必定秒杀对手", + 1628: "每次使用该技能击败对手则恢复自身全部体力,同时重置该技能使用次数并使该技能攻击威力提升{0}点,未击败对手时令自身下回合攻击技能先制+{1}", + 1629: "{0}基础速度值{1}{2}则自身下回合先制+{3}", 1670: "{0}%令对手{1},对手为自身天敌时概率提升{2}%,未触发则消除对手回合类效果", 1671: "造成的攻击伤害不低于{0},若对手处于能力提升状态则造成的攻击伤害不低于{1}", 1672: "出手时若自身未满体力则吸取对手{0}点体力", diff --git a/logic/service/fight/info/info.go b/logic/service/fight/info/info.go index 5211959f1..d5ba31b77 100644 --- a/logic/service/fight/info/info.go +++ b/logic/service/fight/info/info.go @@ -73,23 +73,23 @@ type RPCFightStartinfo struct { // FightPetInfo 战斗精灵信息结构体,FightPetInfo类 type FightPetInfo struct { - // 用户ID(野怪为0),@UInt long + // 用户ID(野怪为0) UserID uint32 `fieldDesc:"用户ID 野怪为0" ` - // 当前对战精灵ID,@UInt long + // 当前对战精灵ID ID uint32 `fieldDesc:"当前对战精灵ID" ` Name string `struc:"[16]byte"` - // 精灵的捕获时间,@UInt long + // 精灵的捕获时间 CatchTime uint32 `fieldDesc:"精灵的捕获时间" ` - // 当前HP,@UInt long + // 当前HP Hp uint32 `fieldDesc:"当前HP" ` - // 最大HP,@UInt long + // 最大HP MaxHp uint32 `fieldDesc:"最大HP" ` - // 当前等级,@UInt long + // 当前等级 Level uint32 `fieldDesc:"当前等级" ` // 精灵是否能捕捉(1为能捕捉,0为不能捕捉), @@ -180,18 +180,12 @@ type EnumPetStatus = byte // 精灵的能力提升 type PropDict struct { - // 攻击(@UInt long → uint32) - Attack int8 - // 防御(@UInt long → uint32) - Defence int8 - // 特攻(@UInt long → uint32) - SpecialAttack int8 - // 特防(@UInt long → uint32) + Attack int8 + Defence int8 + SpecialAttack int8 SpecialDefence int8 - // 速度(@UInt long → uint32) - Speed int8 - // 命中(@UInt long → uint32) + Speed int8 Accuracy int8 } @@ -204,7 +198,6 @@ type NoteUseSkillOutboundInfo struct { } type FightStartOutboundInfo struct { - // @UInt long类型 IsCanAuto uint32 `fieldDesc:"是否自动 默认给0 怀疑是自动战斗器使用的" ` // 当前战斗精灵信息1(前端通过userid判断是否为我方) @@ -215,7 +208,7 @@ type FightStartOutboundInfo struct { } type S2C_2404 struct { - // 用户ID(野怪为0),@UInt long + // 用户ID(野怪为0) UserID uint32 `fieldDesc:"userID 如果为野怪则为0" ` } type S2C_50005 struct { diff --git a/logic/service/fight/info/item.go b/logic/service/fight/info/item.go index 10cec1a17..90db99c36 100644 --- a/logic/service/fight/info/item.go +++ b/logic/service/fight/info/item.go @@ -2,7 +2,7 @@ package info // UsePetIteminfo 对应Java的UsePetIteminfo,实现OutboundMessage接口 type UsePetIteminfo struct { - UserID uint32 `description:"玩家ID" codec:"userId"` // @UInt long 对应Go的uint32(无符号64位) + UserID uint32 `description:"玩家ID" codec:"userId"` ItemID uint32 `description:"使用的物品ID" codec:"itemId"` // 结构体标签模拟@FieldDescription和@AutoCodec注解 UserHp uint32 `description:"用户血量 这里是原始HP+药剂回复的HP总和 比如我只有20血使用了150药剂 这里应该是170 使用PP药剂 这里为原始HP" codec:"userHp"` //这里实现是int, 可以+血 diff --git a/logic/service/fight/info/update.go b/logic/service/fight/info/update.go index 912f17861..0cdedfad0 100644 --- a/logic/service/fight/info/update.go +++ b/logic/service/fight/info/update.go @@ -2,49 +2,35 @@ package info // UpdatePropInfo 对应Java的UpdatePropInfo类,用于精灵属性更新信息(所有数值类型改为uint32) type UpdatePropInfo struct { - // CatchTime 精灵的捕获时间,对应Java的@UInt long(改为uint32) CatchTime uint32 `fieldDescription:"精灵的捕获时间" uint:"true" autoCodec:"true"` - // 精灵编号(@UInt long → uint32) ID uint32 `fieldDesc:"精灵编号" ` - // Level 精灵等级,对应Java的@UInt long(改为uint32) Level uint32 `fieldDescription:"精灵等级" uint:"true" autoCodec:"true"` - // 当前等级已获得经验(@UInt long → uint32) - Exp uint32 `fieldDesc:"当前等级已经获得的经验 2538" ` + Exp uint32 `fieldDesc:"当前等级已经获得的经验 2538" ` - // 当前等级所需经验(@UInt long → uint32) LvExp uint32 `fieldDesc:"当前等级所需的经验" ` - // 升到下一级的经验(@UInt long → uint32) NextLvExp uint32 `fieldDesc:"升到下一级的经验" ` - // MaxHp 最大血量,对应Java的@UInt long(改为uint32) MaxHp uint32 `fieldDescription:"最大血量" uint:"true" autoCodec:"true"` Prop [5]uint32 `fieldDesc:"属性" ` - // 生命学习力(@UInt long → uint32) EvHp uint32 `fieldDesc:"生命学习力" ` - // 攻击学习力(@UInt long → uint32) EvAttack uint32 `fieldDesc:"攻击学习力" ` - // 防御学习力(@UInt long → uint32) EvDefence uint32 `fieldDesc:"防御学习力" ` - // 特攻学习力(@UInt long → uint32) EvSpecialAttack uint32 `fieldDesc:"特攻学习力" ` - // 特防学习力(@UInt long → uint32,注意原Java拼写:evSpecialDefense) EvSpecialDefense uint32 `fieldDesc:"特防学习力" ` - // 速度学习力(@UInt long → uint32) EvSpeed uint32 `fieldDesc:"速度学习力" ` } type PetUpdateOutboundInfo struct { // Addition 超No加成,数值固定为20,若此字段为0则为普通经验分配 - // 对应Java的@UInt long,使用uint32(参考历史转换习惯) Addition uint32 `fieldDescription:"超No加成,数值固定为20,若此字段为0则为普通经验分配" uint:"true" autoCodec:"true"` DataLen uint32 `struc:"sizeof=Data"` // Data 更新数据,对应Java的List diff --git a/logic/service/item/buy.go b/logic/service/item/buy.go index 37df71445..34f0a0e09 100644 --- a/logic/service/item/buy.go +++ b/logic/service/item/buy.go @@ -22,7 +22,7 @@ type BuyOutboundInfo struct { type BuyMultiInboundInfo struct { Head common.TomeeHeader `cmd:"2606" struc:"skip"` ItemListLen uint32 `struc:"sizeof=ItemIds"` - ItemIds []uint32 `json:"itemIds" description:"购买的物品ID列表"` // @UInt Long对应uint64,List对应切片 + ItemIds []uint32 `json:"itemIds" description:"购买的物品ID列表"` } type BuyMultiOutboundInfo struct { //剩余的数量 diff --git a/logic/service/item/talk.go b/logic/service/item/talk.go index 5217351b4..524096d80 100644 --- a/logic/service/item/talk.go +++ b/logic/service/item/talk.go @@ -4,14 +4,14 @@ import "blazing/logic/service/common" type TalkCountInboundInfo struct { Head common.TomeeHeader `cmd:"2701" struc:"skip"` - ID uint32 `description:"奖品的Type, 即ID" codec:"uint"` // @UInt long -> uint64,字段描述对应@FieldDescription + ID uint32 `description:"奖品的Type, 即ID" codec:"uint"` } type TalkCountOutboundInfo struct { - GiftCount uint32 `description:"已领取奖励的次数" codec:"uint"` // @UInt long -> uint64,字段描述对应@FieldDescription + GiftCount uint32 `description:"已领取奖励的次数" codec:"uint"` } type TalkCateInboundInfo struct { Head common.TomeeHeader `cmd:"2702" struc:"skip"` - ID uint32 `description:"奖品的Type, 即ID" codec:"uint"` // @UInt long -> uint64,字段描述对应@FieldDescription + ID uint32 `description:"奖品的Type, 即ID" codec:"uint"` } type DayTalkInfo struct { CateList uint32 `description:"要序列list数量字段 只序列数量 结构体数据给null"` // 对应Java的cateList @@ -20,6 +20,6 @@ type DayTalkInfo struct { } type CateInfo struct { // 示例字段,需替换为实际定义 - ID int64 `struc:"uint32"` + ID int64 `struc:"uint32"` Count uint32 } diff --git a/logic/service/nono/nono.go b/logic/service/nono/nono.go index 8aac7ea3e..2672148ad 100644 --- a/logic/service/nono/nono.go +++ b/logic/service/nono/nono.go @@ -63,11 +63,10 @@ type NonoFollowOrHomeInInfo struct { Head common.TomeeHeader `cmd:"9019" struc:"skip"` // Flag 1为跟随 0为收回 且如果为收回收回 那么后续结构不需要发送 - // 对应Java的@UInt long类型,在Go中使用uint64 Flag uint32 `fieldDescription:"1为跟随 0为收回 且如果为收回 那么后续结构不需要发送" uint:"true"` } type NonoFollowOutInfo struct { - // UserID 米米号,对应Java的@UInt long,改为uint32 + // UserID 米米号 UserID uint32 `fieldDescription:"米米号" uint:"true"` // SuperStage 设置的值与下面的flag变量相同,改为uint32 @@ -87,11 +86,11 @@ type NonoFollowOutInfo struct { } type SwitchFlyingInboundInfo struct { Head common.TomeeHeader `cmd:"2112" struc:"skip"` - Type uint32 `description:"开关, 0为取消飞行模式, 大于0为开启飞行模式" codec:"auto" uint:"true"` // 对应@FieldDescription、@UInt、@AutoCodec + Type uint32 `description:"开关, 0为取消飞行模式, 大于0为开启飞行模式" codec:"auto" uint:"true"` } type SwitchFlyingOutboundInfo struct { - UserId uint32 `description:"玩家账号ID" codec:"auto" uint:"true"` // 对应@FieldDescription、@UInt、@AutoCodec - Type uint32 `description:"开关, 0为取消飞行模式, 大于0为开启飞行模式" codec:"auto" uint:"true"` // 对应@FieldDescription、@UInt、@AutoCodec + UserId uint32 `description:"玩家账号ID" codec:"auto" uint:"true"` + Type uint32 `description:"开关, 0为取消飞行模式, 大于0为开启飞行模式" codec:"auto" uint:"true"` } type PetCureInboundInfo struct { Head common.TomeeHeader `cmd:"2306" struc:"skip"` diff --git a/logic/service/pet/BargeList.go b/logic/service/pet/BargeList.go index 20113c243..b1e2d20f2 100644 --- a/logic/service/pet/BargeList.go +++ b/logic/service/pet/BargeList.go @@ -7,8 +7,8 @@ import ( // PetBargeListInboundInfo 对应Java的PetBargeListInboundInfo,实现InboundMessage接口 type PetBargeListInboundInfo struct { Head common.TomeeHeader `cmd:"2309" struc:"skip"` - StartPetId uint32 `description:"开始精灵id" codec:"startPetId"` // @UInt long 对应Go的uint32(无符号64位) - EndPetId uint32 `description:"结束精灵id" codec:"endPetId"` // 字段标签模拟注解功能(描述、编解码标识) + StartPetId uint32 `description:"开始精灵id" codec:"startPetId"` + EndPetId uint32 `description:"结束精灵id" codec:"endPetId"` // 字段标签模拟注解功能(描述、编解码标识) } type C2S_9756 struct { Head common.TomeeHeader `cmd:"9756" struc:"skip"` @@ -16,7 +16,7 @@ type C2S_9756 struct { // PetBargeListInfo 对应Java的PetBargeListInfo类 type PetBargeListInfo struct { - PetId uint32 `description:"精灵ID"` // @UInt long 对应Go的uint32(无符号64位整数) + PetId uint32 `description:"精灵ID"` EnCntCnt uint32 `description:"未知"` // public字段在Go中通过首字母大写导出 IsCatched uint32 `description:"捕获记录"` // 结构体标签模拟@FieldDescription注解 IsKilled uint32 `description:"击杀记录"` // 字段名采用帕斯卡命名法(首字母大写)以匹配Java的public访问权限 diff --git a/logic/service/pet/exp.go b/logic/service/pet/exp.go index bba87ceed..9c852d585 100644 --- a/logic/service/pet/exp.go +++ b/logic/service/pet/exp.go @@ -4,16 +4,13 @@ import "blazing/logic/service/common" // 实现InboundMessage接口,用于处理宠物设置经验的入站消息 type PetSetExpInboundInfo struct { - Head common.TomeeHeader `cmd:"2318" struc:"skip"` - // CatchTime 精灵获取时间,对应Java的@UInt long - CatchTime uint32 `fieldDescription:"精灵获取时间" uint:"true" autoCodec:"true"` + Head common.TomeeHeader `cmd:"2318" struc:"skip"` + CatchTime uint32 `fieldDescription:"精灵获取时间" uint:"true" autoCodec:"true"` - // Exp 分配经验,对应Java的@UInt long - Exp int64 `struc:"uint32"` + Exp int64 `struc:"uint32"` } // 实现OutboundMessage接口,用于处理宠物设置经验的出站消息 type PetSetExpOutboundInfo struct { - // Exp 剩余累计经验,对应Java的@UInt long - Exp int64 `struc:"uint32"` + Exp int64 `struc:"uint32"` } diff --git a/logic/service/pet/list.go b/logic/service/pet/list.go index 71abae4eb..b69ffdb84 100644 --- a/logic/service/pet/list.go +++ b/logic/service/pet/list.go @@ -19,11 +19,10 @@ type GetPetListOutboundInfo struct { // PetShortInfo 精灵简要信息结构体 type PetShortInfo struct { - ID uint32 // 精灵类型ID( - CatchTime uint32 // 精灵生成时间 - Level uint32 // 精灵等级 - SkinID uint32 // 精灵皮肤ID - // 是否闪光(@UInt long → uint32,0=否,1=是) + ID uint32 // 精灵类型ID( + CatchTime uint32 // 精灵生成时间 + Level uint32 // 精灵等级 + SkinID uint32 // 精灵皮肤ID ShinyLen uint32 `json:"-" struc:"sizeof=ShinyInfo"` ShinyInfo []data.GlowFilter `json:"ShinyInfo,omitempty"` } @@ -52,10 +51,8 @@ type RoomPetInfo struct { ID uint32 `fieldDesc:"精灵编号" ` Nature uint32 `fieldDesc:"性格" ` - // 等级(@UInt long → uint32) Level uint32 `fieldDesc:"等级" ` - // 当前生命(@UInt long → uint32) - Hp uint32 + Hp uint32 // * battle_lv: atk(0), def(1), sp_atk(2), sp_def(3), spd(4), accuracy(5) Prop [5]uint32 `fieldDesc:"属性" ` SkillListLen uint32 `struc:"sizeof=SkillList"` diff --git a/logic/service/pet/pet.go b/logic/service/pet/pet.go index f8501f3dc..0c4954d58 100644 --- a/logic/service/pet/pet.go +++ b/logic/service/pet/pet.go @@ -41,12 +41,11 @@ type PetShowInboundInfo struct { } type PetShowOutboundInfo struct { - UserID uint32 `codec:"UserID" description:"米米号"` - CatchTime uint32 `codec:"CatchTime" description:"精灵获得的时间"` - ID uint32 `codec:"PetID" description:"精灵编号"` - Flag uint32 `codec:"flag" description:"1为显示 0为收回"` - Dv uint32 `codec:"dv" description:"个体"` - // 是否闪光(@UInt long → uint32,0=否,1=是) + UserID uint32 `codec:"UserID" description:"米米号"` + CatchTime uint32 `codec:"CatchTime" description:"精灵获得的时间"` + ID uint32 `codec:"PetID" description:"精灵编号"` + Flag uint32 `codec:"flag" description:"1为显示 0为收回"` + Dv uint32 `codec:"dv" description:"个体"` ShinyLen uint32 `json:"-" struc:"sizeof=ShinyInfo"` ShinyInfo []data.GlowFilter `json:"ShinyInfo,omitempty"` SkinID uint32 `codec:"skinID" description:"皮肤ID"` diff --git a/logic/service/space/info.go b/logic/service/space/info.go index ff1d651a4..666912e90 100644 --- a/logic/service/space/info.go +++ b/logic/service/space/info.go @@ -30,7 +30,7 @@ type InInfo struct { } type WalkInInfo struct { Head common.TomeeHeader `cmd:"2101" struc:"skip"` //走路包 - // Flag: 0为走,1为飞行模式,@UInt long + // Flag: 0为走,1为飞行模式 Flag uint32 // Point: 直接给坐标x,y diff --git a/logic/service/space/info/info.go b/logic/service/space/info/info.go index 2bce13d29..2b7748670 100644 --- a/logic/service/space/info/info.go +++ b/logic/service/space/info/info.go @@ -96,8 +96,7 @@ type SimpleInfo struct { SpiritID uint32 `struc:"uint32" fieldDesc:"暂时不明给0" json:"spirit_id"` // 宠物 ID 暂时无法测试,给 0 - PetDV uint32 `struc:"uint32" fieldDesc:"宠物ID暂时无法测试, 给0" json:"pet_dv"` - // 是否闪光(@UInt long → uint32,0=否,1=是) + PetDV uint32 `struc:"uint32" fieldDesc:"宠物ID暂时无法测试, 给0" json:"pet_dv"` ShinyLen uint32 `json:"-" struc:"sizeof=ShinyInfo"` ShinyInfo []data.GlowFilter `json:"ShinyInfo,omitempty"` // 宠物皮肤暂时无法测试,给 0 diff --git a/logic/service/task/Delete_Task.go b/logic/service/task/Delete_Task.go index 5dfa26988..e202ccc67 100644 --- a/logic/service/task/Delete_Task.go +++ b/logic/service/task/Delete_Task.go @@ -5,8 +5,8 @@ import "blazing/logic/service/common" // DeleteTaskInboundInfo type DeleteTaskInboundInfo struct { Head common.TomeeHeader `cmd:"2205|2232" struc:"skip"` - TaskId uint32 `json:"taskId" description:"任务ID"` // 使用uint64 + TaskId uint32 `json:"taskId" description:"任务ID"` } type DeleteTaskOutboundInfo struct { - TaskId uint32 `json:"taskId" description:"任务ID"` // 对应@UInt long和@FieldDescription + TaskId uint32 `json:"taskId" description:"任务ID"` } diff --git a/logic/service/user/CREATE_ROLE.go b/logic/service/user/CREATE_ROLE.go index 63e66bc99..2ea05578e 100644 --- a/logic/service/user/CREATE_ROLE.go +++ b/logic/service/user/CREATE_ROLE.go @@ -7,7 +7,7 @@ type CreatePlayerInboundInfo struct { //这里直接使用组合来实现将传 // 玩家昵称,@ArraySerialize注解 Nickname string `struc:"[16]byte"` // 固定长度16字节 - // 机器人人物颜色 rgb,@UInt注解 + // 机器人人物颜色 rgb Color uint32 `fieldDescription:"机器人人物颜色 rgb" uint:"true"` } type CreatePlayerOutInfo struct { diff --git a/logic/service/user/GET_SIM_USERINFO.go b/logic/service/user/GET_SIM_USERINFO.go index 44a241fcb..152a4d84d 100644 --- a/logic/service/user/GET_SIM_USERINFO.go +++ b/logic/service/user/GET_SIM_USERINFO.go @@ -20,55 +20,42 @@ type SimUserInfoOutboundInfo struct { Color uint32 `codec:"true"` // Texture 纹理 0 - // 对应 Java 注解: @FieldDescription("纹理 0") @UInt Texture uint32 `codec:"true"` // Vip 默认值 1 位置 - // 对应 Java 注解: @FieldDescription("默认值 1 位置") @UInt Vip uint32 `codec:"true"` // Status 默认值0 未知 - // 对应 Java 注解: @FieldDescription("默认值0 未知") @UInt Status uint32 `codec:"true"` // MapType 地图类型 进入地图包传入的字段 - // 对应 Java 注解: @FieldDescription("地图类型 进入地图包传入的字段") @UInt MapType uint32 `codec:"true"` // MapID 地图id - // 对应 Java 注解: @FieldDescription("地图id") @UInt MapID uint32 `codec:"true"` // IsCanBeTeacher 能不能做教官 - // 对应 Java 注解: @FieldDescription("能不能做教官") @UInt IsCanBeTeacher uint32 `codec:"true"` // TeacherID 教官id - // 对应 Java 注解: @FieldDescription("教官id") @UInt TeacherID uint32 `codec:"true"` // StudentID 学生id - // 对应 Java 注解: @FieldDescription("学生id") @UInt StudentID uint32 `codec:"true"` // GraduationCount 教官成绩 - // 对应 Java 注解: @FieldDescription("教官成绩") @UInt GraduationCount uint32 `codec:"true"` // VipLevel vip等级 8 - // 对应 Java 注解: @FieldDescription("vip等级 8") @UInt VipLevel uint32 `codec:"true"` // TeamId 战队id - // 对应 Java 注解: @FieldDescription("战队id") @UInt TeamId uint32 `codec:"true"` // IsShow 有没有跟随的精灵 - // 对应 Java 注解: @FieldDescription("有没有跟随的精灵") @UInt IsShow uint32 `codec:"true"` ClothesCount uint32 `struc:"sizeof=Clothes" json:"clothes_count"` // 穿戴装备数量 // Clothes 穿戴装备 - // 对应 Java 注解: @FieldDescription("穿戴装备") @Builder.Default Clothes []model.PeopleItemInfo `codec:"true"` } type MoreUserInfoInboundInfo struct { @@ -77,7 +64,6 @@ type MoreUserInfoInboundInfo struct { } type MoreUserInfoOutboundInfo struct { // UserID 米米号 - // 对应 Java 注解: @FieldDescription("米米号") @UInt UserID uint32 `codec:"true"` Nick string `struc:"[16]byte" default:"seer" json:"nick"` // 16字节昵称 @@ -85,35 +71,27 @@ type MoreUserInfoOutboundInfo struct { RegisterTime uint32 `struc:"uint32" json:"register_time"` // 注册时间(秒时间戳) // PetAllNum 所有精灵数量 - // 对应 Java 注解: @FieldDescription("所有精灵数量") @UInt AllPetNumber uint32 `codec:"true"` // PetMaxLev 精灵最大等级 - // 对应 Java 注解: @FieldDescription("精灵最大等级") @UInt PetMaxLevel uint32 `codec:"true"` // BossAchievement spt boos成就 20字节 以任务状态完成 3为击败该boss, 目前spt只有12个, 剩下的长度以3填充 - // 对应 Java 注解: @FieldDescription(...) @ArraySerialize(value = ArraySerializeType.FIXED_LENGTH, fixedLength = 20) @Builder.Default BossAchievement [20]byte `codec:"true"` // GraduationCount 教官成绩 - // 对应 Java 注解: @FieldDescription("教官成绩") @UInt GraduationCount uint32 `codec:"true"` // MonKingWin 精灵王胜场 - // 对应 Java 注解: @FieldDescription("精灵王胜场") @UInt MonKingWin uint32 `codec:"true"` // MessWin 大乱斗胜场 - // 对应 Java 注解: @FieldDescription("大乱斗胜场") @UInt MessWin uint32 `codec:"true"` // MaxStage 勇者之塔层数 - // 对应 Java 注解: @FieldDescription("勇者之塔层数") @UInt MaxStage uint32 `codec:"true"` // MaxArenaWins 星际擂台胜场 - // 对应 Java 注解: @FieldDescription("星际擂台胜场") @UInt MaxArenaWins uint32 `codec:"true"` } diff --git a/logic/service/user/chat.go b/logic/service/user/chat.go index bd588e92a..707431751 100644 --- a/logic/service/user/chat.go +++ b/logic/service/user/chat.go @@ -4,48 +4,48 @@ import "blazing/logic/service/common" type ChatInboundInfo struct { Head common.TomeeHeader `cmd:"2102" struc:"skip"` - Reserve uint32 `json:"reserve" fieldDescription:"填充 默认值为0" uint:"true"` // @UInt long reserve,无符号长整数 + Reserve uint32 `json:"reserve" fieldDescription:"填充 默认值为0" uint:"true"` MessageLen uint32 `struc:"sizeof=Message"` Message string `json:"message" fieldDescription:"消息内容, 结束符为utf-8的数字0"` // 消息内容,包含utf-8空字符('\x00')作为结束符 } type ChatOutboundInfo struct { - SenderId uint32 `description:"发送人的米米号" codec:"uint"` // @UInt long -> uint64 + SenderId uint32 `description:"发送人的米米号" codec:"uint"` SenderNickname string `struc:"[16]byte" default:"seer" json:"nick"` // 固定16字节的字符串,对应@ArraySerialize注解 - ToId uint32 `description:"可能是私聊用的 公屏发送时为0" codec:"uint"` // @UInt long -> uint64 + ToId uint32 `description:"可能是私聊用的 公屏发送时为0" codec:"uint"` MessageLen uint32 `struc:"sizeof=Message"` Message string `description:"这里的内容没有结束符" codec:"string"` // String -> string } type ChangeColorInboundInfo struct { Head common.TomeeHeader `cmd:"2063" struc:"skip"` - Color uint32 `codec:"color"` // 更改的颜色 rgb (对应Java的@UInt long) + Color uint32 `codec:"color"` // 更改的颜色 rgb } type ChangeColorOutboundInfo struct { - UserId uint32 `codec:"userId"` // 更改人的用户id (对应Java的@UInt long) - Color uint32 `codec:"color"` // 前端发来的更改的颜色rgb值 (对应Java的@UInt long) - Texture uint32 `codec:"texture"` // 大概是当前的涂装 by 7 (对应Java的@UInt long) + UserId uint32 `codec:"userId"` // 更改人的用户id + Color uint32 `codec:"color"` // 前端发来的更改的颜色rgb值 + Texture uint32 `codec:"texture"` // 大概是当前的涂装 by 7 Coins int64 `struc:"uint32"` } type ChangeDoodleInboundInfo struct { Head common.TomeeHeader `cmd:"2062" struc:"skip"` - Id uint32 `codec:"id"` // 涂鸦ID (对应Java的@UInt long) - Color uint32 `codec:"color"` // 前端发来的更改的颜色rgb值 (对应Java的@UInt long) + Id uint32 `codec:"id"` // 涂鸦ID + Color uint32 `codec:"color"` // 前端发来的更改的颜色rgb值 } type ChangeDoodleOutboundInfo struct { - UserId uint32 `codec:"userId"` // 更改人的userid (对应Java的@UInt long) - Color uint32 `codec:"color"` // 使用前端发的id 从itemInfo中获得 (对应Java的@UInt long) - Texture uint32 `codec:"texture"` // 使用前端发的id 从itemInfo中获得 (对应Java的@UInt long) - Coins int64 `struc:"uint32"` + UserId uint32 `codec:"userId"` // 更改人的userid + Color uint32 `codec:"color"` // 使用前端发的id 从itemInfo中获得 + Texture uint32 `codec:"texture"` // 使用前端发的id 从itemInfo中获得 + Coins int64 `struc:"uint32"` } type ChangeNONOColorInboundInfo struct { Head common.TomeeHeader `cmd:"9012" struc:"skip"` - Color uint32 `codec:"color"` // 更改的颜色 rgb (对应Java的@UInt long) + Color uint32 `codec:"color"` // 更改的颜色 rgb } type ChangeNONOColorOutboundInfo struct { - UserID uint32 `codec:"userId"` // 更改人的用户id (对应Java的@UInt long) - Color uint32 `codec:"color"` // 前端发来的更改的颜色rgb值 (对应Java的@UInt long) + UserID uint32 `codec:"userId"` // 更改人的用户id + Color uint32 `codec:"color"` // 前端发来的更改的颜色rgb值 } diff --git a/modules/base/controller/admin/base_sys_user.go b/modules/base/controller/admin/base_sys_user.go index c3fc37cfe..404747d8d 100644 --- a/modules/base/controller/admin/base_sys_user.go +++ b/modules/base/controller/admin/base_sys_user.go @@ -127,7 +127,7 @@ type RegReq struct { Authorization string `json:"Authorization" in:"header"` // 玩家昵称,@ArraySerialize注解 Nickname string `json:"nickname" ` // 固定长度16字节 - // 机器人人物颜色 rgb,@UInt注解 + // 机器人人物颜色 rgb Color uint32 `json:"color" ` // 4字节 } diff --git a/modules/player/model/TeamInfo.go b/modules/player/model/TeamInfo.go index 6a4fad08c..f2545cef0 100644 --- a/modules/player/model/TeamInfo.go +++ b/modules/player/model/TeamInfo.go @@ -23,8 +23,8 @@ func (t *TeamInfo) InitDefaults() { // TeamPKInfo 战队PK相关信息结构 type TeamPKInfo struct { - GroupID uint32 `struc:"uint32" default:"1"` // 分组ID,默认值1(@UInt long) - HomeTeamID uint32 `struc:"uint32" default:"1"` // 主队ID,默认值1(@UInt long) + GroupID uint32 `struc:"uint32" default:"1"` // 分组ID,默认值1 + HomeTeamID uint32 `struc:"uint32" default:"1"` // 主队ID,默认值1 } // InitDefaults 初始化默认值(确保字段默认值正确赋值) diff --git a/modules/player/model/pet.go b/modules/player/model/pet.go index 61a736232..6b9cb4d03 100644 --- a/modules/player/model/pet.go +++ b/modules/player/model/pet.go @@ -96,8 +96,6 @@ func (r Attr) sub() uint32 { // PetInfo 精灵信息结构(合并后的优化版本) type PetInfo struct { - - // 精灵编号(@UInt long → uint32) ID uint32 `fieldDesc:"精灵编号" ` // 名字:默认为全0,补齐到16字节(固定长度 → [16]byte) @@ -107,28 +105,20 @@ type PetInfo struct { Generation uint16 `fieldDesc:"世代" ` - // 个体值(@UInt long → uint32) Dv uint32 `struc:"uint32" ` - // 性格(@UInt long → uint32) Nature uint32 `fieldDesc:"性格" ` - // 等级(@UInt long → uint32) Level uint32 `fieldDesc:"等级" ` - // 当前等级已获得经验(@UInt long → uint32) Exp int64 `struc:"uint32"` - // 当前等级所需经验(@UInt long → uint32) LvExp int64 `struc:"uint32"` - // 升到下一级的经验(@UInt long → uint32) NextLvExp int64 `struc:"uint32"` - // 当前生命(@UInt long → uint32) Hp uint32 - // 最大生命(@UInt long → uint32) MaxHp uint32 `fieldDesc:"最大生命" ` // * battle_lv: atk(0), def(1), sp_atk(2), sp_def(3), spd(4), accuracy(5) Prop [5]uint32 `fieldDesc:"属性" ` @@ -141,26 +131,20 @@ type PetInfo struct { // 技能信息:固定4条,空则赋值0(固定长度List → [4]SkillInfo,零值即符合“赋值0”) SkillList []SkillInfo - // 捕捉时间(@UInt long → 若为时间戳用uint32;若需时间类型可改为time.Time,需配合序列化处理) CatchTime uint32 //显式忽略,不参与序列化 OldCatchTime uint32 `struc:"skip" fieldDesc:"旧捕捉时间" ` - // 捕捉地图(@UInt long → uint32) CatchMap uint32 `json:"CatchMap,omitempty"` - // 未知默认0(@UInt long → uint32) CatchRect uint32 `json:"CatchRect,omitempty"` - // 捕获等级默认0(@UInt long → uint32) CatchLevel uint32 `fieldDesc:"捕获等级 默认为0" ` EffectInfoLen uint16 `struc:"sizeof=EffectInfo" json:"-"` // 特性列表:长度用UShort存储(变长List → []PetEffectInfo + 长度前缀规则) 第一个一定是特性 EffectInfo []PetEffectInfo - // 皮肤ID默认0(@UInt long → uint32) SkinID uint32 `fieldDesc:"皮肤id默认为0" ` - // 是否闪光(@UInt long → uint32,0=否,1=是) ShinyLen uint32 `struc:"sizeof=ShinyInfo"` ShinyInfo []data.GlowFilter `json:"ShinyInfo,omitempty"` diff --git a/modules/player/model/pvp.go b/modules/player/model/pvp.go index 9051f830f..7b2bdddf8 100644 --- a/modules/player/model/pvp.go +++ b/modules/player/model/pvp.go @@ -60,7 +60,6 @@ type PVPRankInfo struct { type NoteReadyToFightInfo struct { //MAXPET uint32 `struc:"skip"` // 最大精灵数 struc:"skip"` // 战斗类型ID(与野怪战斗为3,与人战斗为1,前端似乎未使用) - // @UInt long Status uint32 `fieldDesc:"战斗类型ID 但前端好像没有用到 与野怪战斗为3,与人战斗似乎是1" ` //Mode uint32 `struc:"skip"` // 我方信息 @@ -80,7 +79,7 @@ type NoteReadyToFightInfo struct { OpponentPetList []ReadyFightPetInfo `fieldDesc:"敌方的精灵信息 如果是野怪 那么再给客户端发送这个包体时就提前生成好了这只精灵的PetInfo,然后把从PetInfo中把部分信息写入到这个敌方的精灵信息中再发送这个包结构体" serialize:"lengthFirst,lengthType=uint16,type=structArray"` } type FightUserInfo struct { - // 用户ID(野怪为0),@UInt long + // 用户ID(野怪为0) UserID uint32 `fieldDesc:"userID 如果为野怪则为0" ` // 玩家名称(野怪为UTF-8的'-',固定16字节) @@ -90,37 +89,36 @@ type FightUserInfo struct { // ReadyFightPetInfo 准备战斗的精灵信息结构体,ReadyFightPetInfo类 type ReadyFightPetInfo struct { - // 精灵ID,@UInt long + // 精灵ID ID uint32 `fieldDesc:"精灵ID" ` - // 精灵等级,@UInt long + // 精灵等级 Level uint32 `fieldDesc:"精灵等级" ` - // 精灵当前HP,@UInt long + // 精灵当前HP Hp uint32 `fieldDesc:"精灵HP" ` - // 精灵最大HP,@UInt long + // 精灵最大HP MaxHp uint32 `fieldDesc:"最大HP" ` SkillListLen uint32 `struc:"sizeof=SkillList"` // 技能信息列表(固定4个元素,技能ID和剩余PP,无技能则为0) // List,初始化容量为4 SkillList []SkillInfo `fieldDesc:"技能信息 技能ID跟剩余PP 固定32字节 没有给0" serialize:"fixedLength=4,type=structArray"` - // 精灵捕获时间,@UInt long + // 精灵捕获时间 CatchTime uint32 `fieldDesc:"精灵捕获时间" ` - // 捕捉地图(固定给0),@UInt long + // 捕捉地图(固定给0) CatchMap uint32 `fieldDesc:"捕捉地图 给0" ` - // 固定给0,@UInt long + // 固定给0 CatchRect uint32 `fieldDesc:"给0" ` - // 固定给0,@UInt long - CatchLevel uint32 `fieldDesc:"给0" ` - SkinID uint32 `fieldDesc:"精灵皮肤ID" ` - // 是否闪光(@UInt long → uint32,0=否,1=是) - ShinyLen uint32 `json:"-" struc:"sizeof=ShinyInfo"` - ShinyInfo []data.GlowFilter `json:"ShinyInfo,omitempty"` + // 固定给0 + CatchLevel uint32 `fieldDesc:"给0" ` + SkinID uint32 `fieldDesc:"精灵皮肤ID" ` + ShinyLen uint32 `json:"-" struc:"sizeof=ShinyInfo"` + ShinyInfo []data.GlowFilter `json:"ShinyInfo,omitempty"` } type FightOverInfo struct { //0 正常结束