refactor(fight): 重构战斗逻辑中技能实体传递方式

将战斗逻辑中使用的 action.SelectSkillAction 替换为 info.SkillEntity,
以统一技能数据结构。同时更新相关函数签名和字段引用。

此外,移除了未使用的 Attack 字段,并调整了部分逻辑实现以提高代码清晰度。
还修复了 effect_power_doblue.go 中对输入参数的错误引用问题。

最后,修改了通道命名规范(ActionChan -> actionChan, GetActionChan -> GetOverChan),
并引入 overchan 用于战斗结束通知,提升并发安全性与语义明确性。
```
This commit is contained in:
2025-11-10 02:29:00 +08:00
parent a4041aaa66
commit 4b34445dfc
12 changed files with 64 additions and 71 deletions

View File

@@ -1,7 +1,6 @@
package common
import (
"blazing/logic/service/fight/action"
"blazing/logic/service/fight/info"
"math/rand"
)
@@ -19,5 +18,5 @@ type FightI interface {
UseItem(c PlayerI, cacthid, itemid uint32)
CanEscape() bool
IsFirst(c PlayerI) bool
GetActionChan() chan action.BattleActionI
GetOverChan() chan struct{}
}

View File

@@ -33,7 +33,7 @@ type SelectSkillAction struct {
BaseAction
*info.SkillEntity // 使用的技能
//PetInfo *info.BattlePetEntity // 使用技能的宠物
Attack info.AttackValue
//Attack info.AttackValue
}
// Priority 返回动作优先级

View File

@@ -1,6 +1,8 @@
package action
func CanUse(s *SelectSkillAction) bool {
import "blazing/logic/service/fight/info"
func CanUse(s *info.SkillEntity) bool {
if s == nil {
return false

View File

@@ -47,7 +47,7 @@ func (e *Effect117) OnSkill(ctx input.Ctx) bool {
return true
}
duration := int(e.Input.FightC.GetRand().Int31n(2)) // 默认随机 1~3 回合
duration++
eff.Duration(duration)
ctx.AddEffect(eff)
}

View File

@@ -62,19 +62,19 @@ func init() {
return false
})
registerStatusFunc(96, func(i, o *input.Input) bool {
return i.StatEffect_Exist(int(info.PetStatus.Burned))
return o.StatEffect_Exist(int(info.PetStatus.Burned))
})
registerStatusFunc(97, func(i, o *input.Input) bool {
return i.StatEffect_Exist(int(info.PetStatus.Frozen))
return o.StatEffect_Exist(int(info.PetStatus.Frozen))
})
registerStatusFunc(102, func(i, o *input.Input) bool {
return i.StatEffect_Exist(int(info.PetStatus.Paralysis))
return o.StatEffect_Exist(int(info.PetStatus.Paralysis))
})
registerStatusFunc(132, func(i, o *input.Input) bool {
return i.CurrentPet.Info.Hp < o.CurrentPet.Info.MaxHp
return i.CurrentPet.Info.Hp < o.CurrentPet.Info.Hp
})
registerStatusFunc(168, func(i, o *input.Input) bool {
return i.StatEffect_Exist(int(info.PetStatus.Sleep))
return o.StatEffect_Exist(int(info.PetStatus.Sleep))
})
}

View File

@@ -28,9 +28,9 @@ type FightC struct {
rand *rand.Rand
StartTime time.Time
ActionChan chan action.BattleActionI // 所有操作统一从这里进入
actionChan chan action.BattleActionI // 所有操作统一从这里进入
Round int //回合数
overchan chan struct{}
First *input.Input
Second *input.Input
closefight bool
@@ -170,7 +170,7 @@ func (f *FightC) initplayer(c common.PlayerI, opp bool) bool {
func NewFight(mode, status info.EnumBattleMode, p1 common.PlayerI, p2 common.PlayerI) *FightC {
f := &FightC{}
f.ownerID = p1.GetInfo().UserID
f.overchan = make(chan struct{})
f.StartTime = time.Now()
seed := f.StartTime.UnixNano() ^ int64(p1.GetInfo().UserID) ^ int64(p2.GetInfo().UserID) // ^ int64(f.Round) // 用异或运算混合多维度信息
f.rand = rand.New(rand.NewSource(seed))
@@ -240,13 +240,13 @@ func (f *FightC) Broadcast(t func(ff *input.Input)) {
}
// 处理技能攻击逻辑
func (f *FightC) processSkillAttack(attacker, defender *input.Input, a *action.SelectSkillAction) {
func (f *FightC) processSkillAttack(attacker, defender *input.Input, a *info.SkillEntity) {
a.AttackTimeC(attacker.GetProp(5, true)) //计算命中
defender.Exec(func(t input.Effect) bool { //计算闪避 ,然后修改对方命中),同时相当于计算属性无效这种
t.Skill_Hit_to(input.Ctx{ //计算命中后,我方强制改命中效果
Input: attacker,
SelectSkillAction: a,
Input: attacker,
SkillEntity: a,
})
return true
@@ -256,8 +256,8 @@ func (f *FightC) processSkillAttack(attacker, defender *input.Input, a *action.S
attacker.Exec(func(t input.Effect) bool { //计算命中 miss改命中
t.Calculate_Pre(input.Ctx{ //计算视为效果
Input: defender,
SelectSkillAction: a,
Input: defender,
SkillEntity: a,
}) //相当于先调整基础命中,不光调整命中,这里还能调整技能属性,暴击率
return true
@@ -265,8 +265,8 @@ func (f *FightC) processSkillAttack(attacker, defender *input.Input, a *action.S
attacker.Exec(func(t input.Effect) bool { //计算命中 miss改命中
t.Skill_Hit(input.Ctx{ //计算变威力
Input: defender,
SelectSkillAction: a,
Input: defender,
SkillEntity: a,
}) //相当于先调整基础命中,不光调整命中,这里还能调整技能属性,暴击率
return true
@@ -281,15 +281,15 @@ func (f *FightC) processSkillAttack(attacker, defender *input.Input, a *action.S
attacker.CalculateCrit(defender, a) //暴击计算
attacker.AttackValue.IsCritical = a.Crit
attacker.DamageZone.Damage = attacker.CalculatePower(defender, a.SkillEntity)
attacker.DamageZone.Damage = attacker.CalculatePower(defender, a)
//睡眠受击消除
if attacker.AttackValue.IsCritical == 1 {
//暴击破防
if a.SkillEntity.Category() == info.Category.PHYSICAL && defender.Prop[1] > 0 {
if a.Category() == info.Category.PHYSICAL && defender.Prop[1] > 0 {
defender.Prop[1] = 0
} else if a.SkillEntity.Category() == info.Category.SPECIAL && defender.Prop[3] > 0 {
} else if a.Category() == info.Category.SPECIAL && defender.Prop[3] > 0 {
defender.Prop[3] = 0
}
@@ -313,9 +313,9 @@ func (f *FightC) processSkillAttack(attacker, defender *input.Input, a *action.S
attacker.Exec(func(t input.Effect) bool {
t.OnSkill(input.Ctx{
Input: defender,
SelectSkillAction: a,
DamageZone: &info.DamageZone{}, //给个空的,方便传递
Input: defender,
SkillEntity: a,
DamageZone: &info.DamageZone{}, //给个空的,方便传递
}) //调用伤害计算
return true
@@ -325,7 +325,7 @@ func (f *FightC) processSkillAttack(attacker, defender *input.Input, a *action.S
Input: attacker,
SelectSkillAction: a,
SkillEntity: a,
DamageZone: &info.DamageZone{
Type: info.DamageType.Red,
Damage: attacker.DamageZone.Damage,
@@ -342,11 +342,11 @@ func IsNil(x interface{}) bool {
rv := reflect.ValueOf(x)
return rv.Kind() == reflect.Ptr && rv.IsNil()
}
func copyskill(t *action.SelectSkillAction) *action.SelectSkillAction {
func copyskill(t *info.SkillEntity) *info.SkillEntity {
oldskill, _ := deepcopy.Anything(t) //备份技能
return oldskill.(*action.SelectSkillAction)
return oldskill.(*info.SkillEntity)
}
//回合有先手方和后手方,同时有攻击方和被攻击方
@@ -425,40 +425,37 @@ func (f *FightC) enterturn(fattack, sattack *action.SelectSkillAction) {
})
//开始回合操作
for i := 0; i < 2; i++ {
var oldskill *action.SelectSkillAction //原始技能
var currentskill *action.SelectSkillAction //当前技能
if i == 0 { //
var oldskill *info.SkillEntity //原始技能
var currentskill *info.SkillEntity //当前技能
if i == 0 { //
attacker, defender = f.First, f.Second
oldskill = copyskill(fattack)
currentskill = fattack
oldskill = copyskill(fattack.SkillEntity)
} else {
attacker, defender = f.Second, f.First
oldskill = copyskill(sattack)
currentskill = sattack
oldskill = copyskill(sattack.SkillEntity)
}
currentskill = oldskill
currentskill.Rand = f.rand
fmt.Println("开始攻击", oldskill.Power)
canuseskill := true
// 实际上攻击方 还有系统选择放弃出手的
if IsNil(currentskill) || attacker.CurrentPet.Info.Hp <= 0 {
if !action.CanUse(currentskill) || attacker.CurrentPet.Info.Hp <= 0 {
// attacker.AttackValue.SkillID = 0
canuseskill = false
} else {
if !action.CanUse(currentskill) {
// attacker.AttackValue.SkillID = 0
canuseskill = false
}
}
canuseskillok := attacker.Exec(func(t input.Effect) bool { //这个是能否使用技能
//结算状态
//然后这里还可以处理自爆类
return t.Skill_Hit_Pre(input.Ctx{
Input: defender,
SelectSkillAction: currentskill,
DamageZone: &info.DamageZone{},
Input: defender,
SkillEntity: currentskill,
DamageZone: &info.DamageZone{},
}) //返回本身结算,如果false,说明不能使用技能了
})
@@ -468,6 +465,8 @@ func (f *FightC) enterturn(fattack, sattack *action.SelectSkillAction) {
f.processSkillAttack(attacker, defender, currentskill)
currentskill = oldskill
fmt.Println("结束攻击1", oldskill.Power)
fmt.Println("结束攻击", currentskill.Power)
_, skill, ok := utils.FindWithIndex(attacker.CurrentPet.Info.SkillList, func(item model.SkillInfo) bool {
return item.ID == currentskill.Info.ID
})
@@ -480,7 +479,7 @@ func (f *FightC) enterturn(fattack, sattack *action.SelectSkillAction) {
//技能使用后
defender.Exec(func(t input.Effect) bool {
t.Skill_Use(input.Ctx{Input: attacker, SelectSkillAction: currentskill, DamageZone: &info.DamageZone{
t.Skill_Use(input.Ctx{Input: attacker, SkillEntity: currentskill, DamageZone: &info.DamageZone{
Type: info.DamageType.Red,
Damage: attacker.DamageZone.Damage,
}})
@@ -490,7 +489,7 @@ func (f *FightC) enterturn(fattack, sattack *action.SelectSkillAction) {
//技能使用后
attacker.Exec(func(t input.Effect) bool { //技能使用后的我方效果
t.Skill_Useed(input.Ctx{Input: defender, SelectSkillAction: currentskill, DamageZone: &info.DamageZone{
t.Skill_Useed(input.Ctx{Input: defender, SkillEntity: currentskill, DamageZone: &info.DamageZone{
Type: info.DamageType.Red,
Damage: attacker.DamageZone.Damage,
}})

View File

@@ -1,13 +1,12 @@
package input
import (
"blazing/logic/service/fight/action"
"blazing/logic/service/fight/info"
)
type Ctx struct {
*Input //施加方
*action.SelectSkillAction //action本身
*Input //施加方
*info.SkillEntity //action本身
*info.DamageZone //伤害
}

View File

@@ -14,7 +14,7 @@ import (
)
// 计算暴击
func (u *Input) CalculateCrit(opp *Input, skill *action.SelectSkillAction) {
func (u *Input) CalculateCrit(opp *Input, skill *info.SkillEntity) {
skill.Crit = 0
if skill.Category() == info.Category.STATUS { //属性技能不用算暴击

View File

@@ -84,14 +84,8 @@ func (c *Input) GetEffect(etype EnumEffectType, id int) Effect {
return nil
}
func (c *Input) StatEffect_Exist(id int) bool {
for _, v := range c.Effects {
if v.ID()+int(EffectType.Status) == id && v.Alive() {
return true
}
}
return false
return c.GetEffect(EffectType.Status, id-int(EffectType.Status)) != nil
}
func (c *Input) StatEffect_Exist_all() bool {
for _, v := range c.Effects {

View File

@@ -15,7 +15,7 @@ import (
)
func (f *FightC) battleLoop() {
f.ActionChan = make(chan action.BattleActionI, 2)
f.actionChan = make(chan action.BattleActionI, 2)
fmt.Println("战斗开始精灵", f.Our.Player.GetInfo().PetList[0].CatchTime)
ourID := f.Our.Player.GetInfo().UserID
@@ -30,7 +30,8 @@ func (f *FightC) battleLoop() {
ff.Player.SendFightEndInfo(f.FightOverInfo)
})
close(f.ActionChan)
close(f.actionChan)
close(f.overchan)
break
}
@@ -52,7 +53,7 @@ func (f *FightC) collectPlayerActions(ourID, oppID uint32) map[uint32]action.Bat
for len(actions) < 2 {
select {
case paction, ok := <-f.ActionChan:
case paction, ok := <-f.actionChan:
if !ok || f.closefight {
return actions
}
@@ -247,8 +248,7 @@ func (f *FightC) getPlayerByID(id uint32) common.PlayerI {
}
// 根据玩家ID返回对应对象
func (f *FightC) GetActionChan( ) chan action.BattleActionI {
return f.ActionChan
func (f *FightC) GetOverChan() chan struct{} {
return f.overchan
}

View File

@@ -40,7 +40,7 @@ func (f *FightC) Over(c common.PlayerI, res info.EnumBattleOverReason) {
Reason: res,
}
f.ActionChan <- ret
f.actionChan <- ret
}
// 切换精灵 主动和被驱逐
@@ -77,7 +77,7 @@ func (f *FightC) ChangePet(c common.PlayerI, id uint32) {
return true
})
f.ActionChan <- ret
f.actionChan <- ret
}
// 玩家使用技能
@@ -98,7 +98,7 @@ func (f *FightC) UseSkill(c common.PlayerI, id int32) {
}
}
f.ActionChan <- ret
f.actionChan <- ret
}
// 玩家使用技能
@@ -107,7 +107,7 @@ func (f *FightC) Capture(c common.PlayerI, id uint32) {
cool.Loger.Debug(context.Background(), " 战斗chan已关闭")
return
}
f.ActionChan <- &action.UseItemAction{BaseAction: action.NewBaseAction(c.GetInfo().UserID), ItemID: id}
f.actionChan <- &action.UseItemAction{BaseAction: action.NewBaseAction(c.GetInfo().UserID), ItemID: id}
}
func (f *FightC) UseItem(c common.PlayerI, cacthid, itemid uint32) {
@@ -115,7 +115,7 @@ func (f *FightC) UseItem(c common.PlayerI, cacthid, itemid uint32) {
cool.Loger.Debug(context.Background(), " 战斗chan已关闭")
return
}
f.ActionChan <- &action.UseItemAction{BaseAction: action.NewBaseAction(c.GetInfo().UserID), ItemID: itemid, CacthTime: cacthid}
f.actionChan <- &action.UseItemAction{BaseAction: action.NewBaseAction(c.GetInfo().UserID), ItemID: itemid, CacthTime: cacthid}
}
// 战斗准备

View File

@@ -331,7 +331,7 @@ func (p *Player) Save() {
}()
p.FightC.Over(p, info.BattleOverReason.PlayerOffline) //玩家逃跑,但是不能锁线程
}()
<-p.FightC.GetActionChan() //等待结束
<-p.FightC.GetOverChan() //等待结束
}
p.Info.TimeToday = p.Info.TimeToday + uint32(time.Now().Unix()) - uint32(p.Onlinetime) //保存电池时间
p.Onlinetime = uint32(time.Now().Unix())