feat(fight): 重构属性同步与反转效果逻辑

统一处理效果45、51、55、56的属性同步与反转逻辑,优化代码结构并提高可维护性。新增通用效果结构体 `EffectPropSyncReverse` 和操作类型定义,集中管理不同属性操作行为。

fix(controller): 修复玩家离开地图逻辑错误

修正 `FRESH_LEAVE_FIGHT_LEVEL` 接口中 defer 调用为进入地图,并发送角色信息包给客户端以确保状态一致。

feat(effect): 新增天敌机制核心逻辑占位

在 `NewSel14` 效果中添加 `Turn_Start` 方法,实现若遇到天敌则害怕多回合的核心逻辑框架。

chore(config): 更新Boss配置怪物ID及血量

调整Boss ID为2的怪物配置,替换原有Monster ID并设置血量为10,用于测试或平衡调整。

refactor(fight): 优化战斗循环和精灵切换逻辑

整理战斗主循环中的血量赋值语句格式,调整精灵切换时变量顺序以避免潜在问题,并修复死亡标记逻辑。

refactor(node): 恢复BoolisFalse方法实现

取消注释 `BoolisFalse` 方法内容,恢复其正常功能以便其他模块正确判断布尔条件。

style(logic): 格式化代码空行和缩进

清理多余空行,对齐导入语句与其他代码块格式,增强整体代码可读性。

debug(effect): 增加烧伤伤害调试打印

在持续伤害效果中加入println语句,输出实际造成的真实伤害数值便于排查问题。
This commit is contained in:
2025-12-18 23:57:17 +08:00
parent fb835a017f
commit 96b5dbb425
12 changed files with 155 additions and 273 deletions

View File

@@ -5,7 +5,10 @@ import (
"blazing/common/utils"
"blazing/logic/service/fight"
"blazing/logic/service/player"
"blazing/logic/service/space/info"
"sync/atomic"
"github.com/jinzhu/copier"
)
func (h Controller) FRESH_CHOICE_FIGHT_LEVEL(data *fight.C2S_FRESH_CHOICE_FIGHT_LEVEL, c *player.Player) (result *fight.S2C_FreshChoiceLevelRequestInfo, err errorcode.ErrorCode) {
@@ -38,7 +41,12 @@ func (h Controller) FRESH_LEAVE_FIGHT_LEVEL(data *fight.FRESH_LEAVE_FIGHT_LEVEL,
c.Info.MapID = 108
}
defer c.GetSpace().LeaveMap(c) //玩家离开地图
defer c.GetSpace().EnterMap(c)
out := info.NewOutInfo()
copier.CopyWithOption(out, c.GetInfo(), copier.Option{DeepCopy: true})
c.SendPackCmd(2001, out)
return result, 0
}

View File

@@ -1,6 +1,7 @@
package effect
import (
"blazing/logic/service/fight/action"
"blazing/logic/service/fight/input"
)
@@ -10,6 +11,12 @@ type NewSel14 struct {
NewSel0
}
func (e *NewSel14) Turn_Start(fattack *action.SelectSkillAction, sattack *action.SelectSkillAction) {
// TODO: 实现若遇到天敌, 则战斗开始时连续害怕 n 回合;a1: n的核心逻辑
if e.ID().GetCatchTime() != e.Ctx().Our.CurrentPet.Info.CatchTime {
return
}
}
func init() {
input.InitEffect(input.EffectType.NewSel, 14, &NewSel14{})
}

View File

@@ -1,52 +0,0 @@
package effect
import (
"blazing/logic/service/fight/action"
"blazing/logic/service/fight/input"
"blazing/logic/service/fight/node"
)
/**
* n回合防御力和对手相同
*/
type Effect45 struct {
node.EffectNode
oldtype uint32
}
func (e *Effect45) OnSkill() bool {
if !e.Hit() {
return true
}
return true
}
func (e *Effect45) Turn_Start(fattack *action.SelectSkillAction, sattack *action.SelectSkillAction) {
if !e.Hit() {
return
}
e.oldtype = e.Ctx().Opp.CurrentPet.Info.Prop[1]
e.Ctx().Our.CurrentPet.Info.Prop[1] = e.Ctx().Opp.CurrentPet.Info.Prop[1]
}
func init() {
ret := &Effect45{}
input.InitEffect(input.EffectType.Skill, 45, ret)
}
func (e *Effect45) SetArgs(t *input.Input, a ...int) {
e.EffectNode.SetArgs(t, a...)
e.EffectNode.Duration(e.EffectNode.SideEffectArgs[0])
}
func (e *Effect45) Alive(t ...bool) bool {
if e.BoolisFalse(t...) && e.Hit() { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
//还原属性
e.Ctx().Our.CurrentPet.Info.Prop[1] = e.oldtype
}
return e.EffectNode.Alive(t...)
}

View File

@@ -1,43 +0,0 @@
package effect
import (
"blazing/logic/service/fight/action"
"blazing/logic/service/fight/input"
"blazing/logic/service/fight/node"
)
/**
* n回合防御力和对手相同
*/
type Effect51 struct {
node.EffectNode
oldtype uint32
}
func (e *Effect51) Turn_Start(fattack *action.SelectSkillAction, sattack *action.SelectSkillAction) {
e.oldtype = e.Ctx().Opp.CurrentPet.Info.Prop[0]
e.Ctx().Our.CurrentPet.Info.Prop[0] = e.Ctx().Opp.CurrentPet.Info.Prop[0]
}
func init() {
ret := &Effect51{}
input.InitEffect(input.EffectType.Skill, 51, ret)
}
func (e *Effect51) SetArgs(t *input.Input, a ...int) {
e.EffectNode.SetArgs(t, a...)
e.EffectNode.Duration(e.EffectNode.SideEffectArgs[0])
}
func (e *Effect51) Alive(t ...bool) bool {
if e.BoolisFalse(t...) && e.Hit() { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
//还原属性
e.Ctx().Our.CurrentPet.Info.Prop[0] = e.oldtype
}
return e.EffectNode.Alive(t...)
}

View File

@@ -1,41 +0,0 @@
package effect
import (
"blazing/logic/service/fight/action"
"blazing/logic/service/fight/input"
"blazing/logic/service/fight/node"
)
/**
*n 回合内,自身与对方反转战斗时属性
*/
type Effect55 struct {
node.EffectNode
}
func (e *Effect55) Turn_Start(fattack *action.SelectSkillAction, sattack *action.SelectSkillAction) {
e.Ctx().Our.CurrentPet.PetInfo.Type, e.Ctx().Opp.CurrentPet.PetInfo.Type = e.Ctx().Opp.CurrentPet.PetInfo.Type, e.Ctx().Our.CurrentPet.PetInfo.Type
}
func init() {
ret := &Effect55{}
input.InitEffect(input.EffectType.Skill, 55, ret)
}
func (e *Effect55) SetArgs(t *input.Input, a ...int) {
e.EffectNode.SetArgs(t, a...)
e.EffectNode.Duration(e.EffectNode.SideEffectArgs[0])
}
func (e *Effect55) Alive(t ...bool) bool {
if e.BoolisFalse(t...) && e.Hit() { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
//还原属性
e.Ctx().Our.CurrentPet.PetInfo.Type, e.Ctx().Opp.CurrentPet.PetInfo.Type = e.Ctx().Opp.CurrentPet.PetInfo.Type, e.Ctx().Our.CurrentPet.PetInfo.Type
}
return e.EffectNode.Alive(t...)
}

View File

@@ -1,43 +0,0 @@
package effect
import (
"blazing/logic/service/fight/action"
"blazing/logic/service/fight/input"
"blazing/logic/service/fight/node"
)
/**
* n 回合内与对方战斗时属性相同
*/
type Effect56 struct {
node.EffectNode
oldtype int
}
func (e *Effect56) Turn_Start(fattack *action.SelectSkillAction, sattack *action.SelectSkillAction) {
e.oldtype = e.Ctx().Our.CurrentPet.PetInfo.Type
e.Ctx().Our.CurrentPet.PetInfo.Type = e.Ctx().Opp.CurrentPet.PetInfo.Type
}
func init() {
ret := &Effect56{}
input.InitEffect(input.EffectType.Skill, 56, ret)
}
func (e *Effect56) SetArgs(t *input.Input, a ...int) {
e.EffectNode.SetArgs(t, a...)
e.EffectNode.Duration(e.EffectNode.SideEffectArgs[0])
}
func (e *Effect56) Alive(t ...bool) bool {
if e.BoolisFalse(t...) && e.Hit() { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
//还原属性
e.Ctx().Our.CurrentPet.PetInfo.Type = e.oldtype
}
return e.EffectNode.Alive(t...)
}

View File

@@ -4,99 +4,143 @@ import (
"blazing/logic/service/fight/info"
"blazing/logic/service/fight/input"
"blazing/logic/service/fight/node"
"sync"
)
// -----------------------------------------------------------
// 降低对方最大体力效果
// 通用效果:属性同步/反转类效果45/51/55/56
// -----------------------------------------------------------
type Effect38 struct {
// 操作类型定义:区分不同的属性操作
type propOpType int
const (
opDefenseSync propOpType = iota // 同步防御力45
opAttackSync // 同步攻击力51
opTypeReverse // 反转属性类型55
opTypeSync // 同步属性类型56
)
// 效果上下文:存储属性修改前的原始值(用于还原)
type propOpContext struct {
oldOurProp uint32 // 我方原始属性值45/51
oldOurType int // 我方原始类型值56
oldOppType int // 对方原始类型值55
propIndex int // 属性索引0=攻击1=防御)
opType propOpType
}
// 全局映射关联效果ID与对应的操作配置
var propOpMap = make(map[int]func() propOpContext)
// EffectPropSyncReverse属性同步/反转效果核心结构体
type EffectPropSyncReverse struct {
node.EffectNode
ctx propOpContext // 操作上下文(存储原始值)
bindpet *info.BattlePetEntity
}
// 工厂函数
func newEffect38() *Effect38 {
return &Effect38{}
// 工厂函数:创建属性同步/反转效果实例
func newEffectPropSyncReverse() *EffectPropSyncReverse {
return &EffectPropSyncReverse{}
}
// 初始化:批量注册所有属性同步/反转类效果
func init() {
// 注册降低最大体力效果
input.InitEffect(input.EffectType.Skill, 38, newEffect38())
registerPropSyncReverseEffects()
}
// -----------------------------------------------------------
// 技能触发时调用
// -----------------------------------------------------------
func (e *Effect38) OnSkill() bool {
// 批量注册绑定效果ID与对应的操作配置
func registerPropSyncReverseEffects() {
// 效果ID与操作配置的映射
effectMap := map[int]func() propOpContext{
45: func() propOpContext { // n回合防御力和对手相同
return propOpContext{opType: opDefenseSync, propIndex: 1}
},
51: func() propOpContext { // n回合攻击力和对手相同
return propOpContext{opType: opAttackSync, propIndex: 0}
},
55: func() propOpContext { // n回合反转属性类型
return propOpContext{opType: opTypeReverse}
},
56: func() propOpContext { // n回合同步属性类型
return propOpContext{opType: opTypeSync}
},
}
// 注册到全局映射,并初始化效果
for effectID, ctxFunc := range effectMap {
propOpMap[effectID] = ctxFunc
input.InitEffect(input.EffectType.Skill, effectID, newEffectPropSyncReverse())
}
}
// SetArgs设置效果参数回合数
func (e *EffectPropSyncReverse) SetArgs(t *input.Input, a ...int) {
e.EffectNode.SetArgs(t, a...)
// 从SideEffectArgs[0]获取持续回合数
e.EffectNode.Duration(e.EffectNode.SideEffectArgs[0])
// 初始化操作上下文
e.ctx = propOpMap[int(e.ID().Suffix())]()
}
func (e *EffectPropSyncReverse) OnSkill() bool {
if !e.Hit() {
return true
}
if e.bindpet != nil {
return true
}
ourPet := e.Ctx().Our.CurrentPet
oppPet := e.Ctx().Opp.CurrentPet
switch e.ctx.opType {
case opDefenseSync, opAttackSync:
// 同步攻防属性:保存我方原始值,覆盖为对方值
e.ctx.oldOurProp = ourPet.Info.Prop[e.ctx.propIndex]
ourPet.Info.Prop[e.ctx.propIndex] = oppPet.Info.Prop[e.ctx.propIndex]
case opTypeReverse:
// 反转属性类型:保存双方原始值,交换类型
e.ctx.oldOurType = ourPet.PetInfo.Type
e.ctx.oldOppType = oppPet.PetInfo.Type
ourPet.PetInfo.Type, oppPet.PetInfo.Type = oppPet.PetInfo.Type, ourPet.PetInfo.Type
case opTypeSync:
// 同步属性类型:保存我方原始值,覆盖为对方值
e.ctx.oldOurType = ourPet.PetInfo.Type
ourPet.PetInfo.Type = oppPet.PetInfo.Type
}
//绑定对方精灵
e.bindpet = e.Ctx().Opp.CurrentPet
return true
}
// Alive效果存活判定结束时还原属性
func (e *EffectPropSyncReverse) Alive(t ...bool) bool {
if !e.Hit() {
return true
}
// 创建子效果实例
ee := &Effect38Sub{}
ee.EffectNode.Duration(-1) // 给对方挂3回合子buff
// 设置子效果ID和捕获时间
tt := e.ID()
tt.SetEffectType(input.EffectType.Sub)
tt.SetCatchTime(e.Ctx().Opp.CurrentPet.Info.CatchTime)
ee.ID(tt)
ee.SetArgs(e.Ctx().Our, e.SideEffectArgs...)
// 添加子效果到对方
e.Ctx().Opp.AddEffect(e.Ctx().Our, ee)
return true
}
// -----------------------------------------------------------
// 降低最大体力子效果
// -----------------------------------------------------------
type Effect38Sub struct {
node.EffectNode
oldMaxHP uint32 // 记录原始最大体力值
once sync.Once // 确保只执行一次体力修改
}
// 回合开始时触发
func (e *Effect38Sub) Turn_Start(fattack *action.SelectSkillAction, sattack *action.SelectSkillAction) {
// 魂印特性不在场判断:捕获时间不匹配则返回
if e.ID().GetCatchTime() != e.Ctx().Our.CurrentPet.Info.CatchTime {
return
}
// 确保只执行一次体力扣减
e.once.Do(func() {
// 获取要扣除的体力值和当前最大体力
reduceHP := e.Args()[0]
currentMaxHP := e.Ctx().Our.CurrentPet.GetMaxHP()
// 只在扣除值小于当前最大体力时执行
if reduceHP.Cmp(currentMaxHP) == -1 {
e.oldMaxHP = e.Ctx().Our.CurrentPet.Info.MaxHp
currentMaxHP.Sub(reduceHP)
}
})
}
// 精灵切换时触发
func (e *Effect38Sub) Switch(in *input.Input, at info.AttackValue, oldpet *info.BattlePetEntity) bool {
return true
}
// 效果存活状态判断(处理属性还原)
func (e *Effect38Sub) Alive(t ...bool) bool {
if len(t) > 0 {
if t[0] == false {
return true
}
return false
}
// 回合结束取消节点时还原属性
if e.BoolisFalse(t...) {
e.Ctx().Our.CurrentPet.Info.MaxHp = e.oldMaxHP
ourPet := e.Ctx().Our.CurrentPet
oppPet := e.bindpet
switch e.ctx.opType {
case opDefenseSync, opAttackSync:
// 还原攻防属性
ourPet.Info.Prop[e.ctx.propIndex] = e.ctx.oldOurProp
case opTypeReverse:
// 还原反转的属性类型(恢复双方原始值)
ourPet.PetInfo.Type = e.ctx.oldOurType
oppPet.PetInfo.Type = e.ctx.oldOppType
case opTypeSync:
// 还原同步的属性类型
ourPet.PetInfo.Type = e.ctx.oldOurType
}
}
return e.EffectNode.Alive(t...)
}

View File

@@ -68,6 +68,7 @@ type ContinuousDamage struct {
// 技能命中前触发伤害1/8最大生命值真实伤害
func (e *ContinuousDamage) Action_start(attacker, defender *action.SelectSkillAction) bool {
damage := e.calculateDamage()
println(damage.IntPart(), "烧伤")
e.Ctx().Our.Damage(e.Input, &info.DamageZone{
Type: info.DamageType.True,
Damage: damage,

View File

@@ -315,6 +315,7 @@ func (f *FightC) enterturn(fattack, sattack *action.SelectSkillAction) {
"对手剩余血量:", defender.CurrentPet.Info.Hp,
)
if attacker.CurrentPet.Info.Hp <= 0 {
defender.CurrentPet.NotAlive = true
if defender.CurrentPet.Info.Hp == 0 { //先手方死亡,触发反同归于尽
defender.CurrentPet.Info.Hp = 1
@@ -339,7 +340,7 @@ func (f *FightC) enterturn(fattack, sattack *action.SelectSkillAction) {
//defender.CanAction = true //被打死就可以切精灵了
// AI自动技能
defender.CurrentPet.NotAlive = true
if f.IsWin(attacker, defender.CurrentPet.Info.CatchTime) { //然后检查是否战斗结束
var WinnerId uint32
if i == 0 {

View File

@@ -63,8 +63,8 @@ func (f *FightC) battleLoop() {
}
}
ff.Player.GetInfo().PetList[j].Hp = utils.Max(ff.Player.GetInfo().PetList[j].MaxHp,ff.AllPet[i].Info.Hp)
ff.Player.GetInfo().PetList[j].Hp = utils.Max(ff.Player.GetInfo().PetList[j].MaxHp, ff.AllPet[i].Info.Hp)
ff.Player.GetInfo().PetList[j].SkillList = ff.AllPet[i].Info.SkillList
}
@@ -152,11 +152,11 @@ func (f *FightC) collectPlayerActions(ourID, oppID uint32) map[uint32]action.Bat
selfinput.CanChange = 2
}
oldpet := selfinput.CurrentPet
InitAttackValue := *selfinput.AttackValue
selfinput.CurrentPet, ret.Reason = selfinput.GetPet(ret.Cid)
selfinput.Player.SendPackCmd(2407, &ret.Reason)
InitAttackValue := *selfinput.AttackValue
oldpet := selfinput.CurrentPet
f.Switch[selfinput.UserID] = ret
selfinput.InitAttackValue() //切换精灵消除能力提升

View File

@@ -121,14 +121,14 @@ func (e *EffectNode) AttackTime(*input.Input, *input.Input) bool {
func (e *EffectNode) Prop_Befer(in *input.Input, prop int8, level int8, ptype info.EnumAbilityOpType) bool {
return true
}
// func (e *EffectNode) BoolisFalse(t ...bool) bool {
func (e *EffectNode) BoolisFalse(t ...bool) bool {
// if len(t) > 0 {
// if t[0] == false {
// return true
if len(t) > 0 {
if t[0] == false {
return true
// }
// return false
// }
// return false
// }
}
return false
}
return false
}

View File

@@ -448,9 +448,9 @@ eg:
</Boss>
<Boss Id="2" BossVisible="0"
BossFinTaskWay="2">
<BossMon MonID="1" Hp="68" Lv="25" />
<BossMon MonID="2" Hp="68" Lv="25" />
<BossMon MonID="3" Hp="68" Lv="25" />
<BossMon MonID="4" Hp="10" Lv="25" />
<BossMon MonID="5" Hp="10" Lv="25" />
<BossMon MonID="6" Hp="10" Lv="25" />
<!-- <BossMon MonID="806" Hp="68" Lv="25" />
<BossMon MonID="805" Hp="68" Lv="25" /> -->
</Boss>