Merge commit '5f5634d999893b23650cba92f2914be2cc895049'

This commit is contained in:
xinian
2026-04-11 11:21:58 +00:00
6 changed files with 122 additions and 52 deletions

View File

@@ -44,6 +44,7 @@ func (f *FightC) openActionWindow() {
f.actionMu.Lock() f.actionMu.Lock()
f.acceptActions = true f.acceptActions = true
f.pendingActions = f.pendingActions[:0] f.pendingActions = f.pendingActions[:0]
f.pendingHead = 0
f.actionRound.Store(uint32(f.Round)) f.actionRound.Store(uint32(f.Round))
f.actionMu.Unlock() f.actionMu.Unlock()
} }
@@ -52,6 +53,7 @@ func (f *FightC) closeActionWindow() {
f.actionMu.Lock() f.actionMu.Lock()
f.acceptActions = false f.acceptActions = false
f.pendingActions = f.pendingActions[:0] f.pendingActions = f.pendingActions[:0]
f.pendingHead = 0
f.actionRound.Store(0) f.actionRound.Store(0)
f.actionMu.Unlock() f.actionMu.Unlock()
@@ -73,8 +75,10 @@ func (f *FightC) submitAction(act action.BattleActionI) {
f.actionMu.Unlock() f.actionMu.Unlock()
return return
} }
f.compactPendingActionsLocked()
replaceIndex := -1 replaceIndex := -1
for i, pending := range f.pendingActions { for i := f.pendingHead; i < len(f.pendingActions); i++ {
pending := f.pendingActions[i]
if pending == nil || actionSlotKeyFromAction(pending) != actionSlotKeyFromAction(act) { if pending == nil || actionSlotKeyFromAction(pending) != actionSlotKeyFromAction(act) {
continue continue
} }
@@ -105,15 +109,23 @@ func (f *FightC) submitAction(act action.BattleActionI) {
func (f *FightC) nextAction() action.BattleActionI { func (f *FightC) nextAction() action.BattleActionI {
f.actionMu.Lock() f.actionMu.Lock()
if len(f.pendingActions) == 0 { if f.pendingHead >= len(f.pendingActions) {
f.pendingActions = f.pendingActions[:0]
f.pendingHead = 0
f.actionMu.Unlock() f.actionMu.Unlock()
return nil return nil
} }
act := f.pendingActions[0] act := f.pendingActions[f.pendingHead]
copy(f.pendingActions, f.pendingActions[1:]) f.pendingActions[f.pendingHead] = nil
f.pendingActions = f.pendingActions[:len(f.pendingActions)-1] f.pendingHead++
hasMore := len(f.pendingActions) > 0 hasMore := f.pendingHead < len(f.pendingActions)
if !hasMore {
f.pendingActions = f.pendingActions[:0]
f.pendingHead = 0
} else {
f.compactPendingActionsLocked()
}
notify := f.actionNotify notify := f.actionNotify
f.actionMu.Unlock() f.actionMu.Unlock()
@@ -127,6 +139,22 @@ func (f *FightC) nextAction() action.BattleActionI {
return act return act
} }
func (f *FightC) compactPendingActionsLocked() {
if f.pendingHead == 0 {
return
}
if f.pendingHead < len(f.pendingActions)/2 && len(f.pendingActions) < cap(f.pendingActions) {
return
}
remaining := len(f.pendingActions) - f.pendingHead
copy(f.pendingActions, f.pendingActions[f.pendingHead:])
for i := remaining; i < len(f.pendingActions); i++ {
f.pendingActions[i] = nil
}
f.pendingActions = f.pendingActions[:remaining]
f.pendingHead = 0
}
// 玩家逃跑/无响应/掉线 // 玩家逃跑/无响应/掉线
func (f *FightC) Over(c common.PlayerI, res model.EnumBattleOverReason) { func (f *FightC) Over(c common.PlayerI, res model.EnumBattleOverReason) {
if f.closefight { if f.closefight {

View File

@@ -467,12 +467,7 @@ func (f *FightC) TURNOVER(cur *input.Input) {
if cur == nil { if cur == nil {
return return
} }
for _, pet := range cur.BenchPets() { _hasBackup = cur.HasLivingBench()
if pet != nil && pet.Info.Hp > 0 {
_hasBackup = true
break
}
}
f.sendLegacySpriteDie(cur, _hasBackup) f.sendLegacySpriteDie(cur, _hasBackup)
f.Broadcast(func(ff *input.Input) { f.Broadcast(func(ff *input.Input) {

View File

@@ -39,6 +39,7 @@ type FightC struct {
actionNotify chan struct{} actionNotify chan struct{}
acceptActions bool acceptActions bool
pendingActions []action.BattleActionI // 待处理动作队列,同一战斗位最多保留一个动作 pendingActions []action.BattleActionI // 待处理动作队列,同一战斗位最多保留一个动作
pendingHead int
actionRound atomic.Uint32 actionRound atomic.Uint32
quit chan struct{} quit chan struct{}
@@ -250,20 +251,13 @@ func (f *FightC) sideHasActionableSlots(side int) bool {
} }
func (f *FightC) slotNeedsAction(in *input.Input) bool { func (f *FightC) slotNeedsAction(in *input.Input) bool {
var bench []*info.BattlePetEntity
if in == nil { if in == nil {
return false return false
} }
if current := in.CurrentPet(); current != nil && current.Info.Hp > 0 { if current := in.CurrentPet(); current != nil && current.Info.Hp > 0 {
return true return true
} }
bench = in.BenchPets() return in.HasLivingBench()
for _, pet := range bench {
if pet != nil && pet.Info.Hp > 0 {
return true
}
}
return false
} }
func (f *FightC) setActionAttackValue(act action.BattleActionI) { func (f *FightC) setActionAttackValue(act action.BattleActionI) {

View File

@@ -107,18 +107,14 @@ func (our *Input) GetProp(id int) alpacadecimal.Decimal {
} }
func (our *Input) GetEffect(etype EnumEffectType, id int) Effect { func (our *Input) GetEffect(etype EnumEffectType, id int) Effect {
var ret []Effect
pr := EffectIDCombiner{} pr := EffectIDCombiner{}
pr.Combine(etype, 0, gconv.Uint16(id)) pr.Combine(etype, 0, gconv.Uint16(id))
our.ensureEffectIndex()
for _, v := range our.Effects { bucket := our.effectsByBase[pr.Base]
if v.ID().Base == pr.Base && v.Alive() { for i := len(bucket) - 1; i >= 0; i-- {
ret = append(ret, v) if bucket[i] != nil && bucket[i].Alive() {
return bucket[i]
} }
}
if len(ret) > 0 {
return ret[len(ret)-1]
} }
return nil return nil
} }
@@ -178,6 +174,7 @@ func (our *Input) AddEffect(in *Input, e Effect) Effect {
if e == nil { if e == nil {
return nil return nil
} }
our.ensureEffectIndex()
ctx := e.Ctx() ctx := e.Ctx()
if ctx != nil { if ctx != nil {
if ctx.Source == nil { if ctx.Source == nil {
@@ -204,7 +201,7 @@ func (our *Input) AddEffect(in *Input, e Effect) Effect {
//TODO 先激活 //TODO 先激活
//fmt.Println("产生回合数", e.ID(), e.Duration()) //fmt.Println("产生回合数", e.ID(), e.Duration())
// 如果已有同 ID 的效果,尝试叠加 // 如果已有同 ID 的效果,尝试叠加
for _, v := range our.Effects { for _, v := range our.effectsByBase[e.ID().Base] {
if v == e { if v == e {
return nil //完全相同,跳过执行 return nil //完全相同,跳过执行
} }
@@ -219,7 +216,7 @@ func (our *Input) AddEffect(in *Input, e Effect) Effect {
if !v.CanStack() { //说明进行了替换 if !v.CanStack() { //说明进行了替换
v.Alive(false) //不允许叠层,取消效果 v.Alive(false) //不允许叠层,取消效果
e.Duration(utils.Max(e.Duration(), v.Duration())) e.Duration(utils.Max(e.Duration(), v.Duration()))
our.Effects = append(our.Effects, e) our.appendEffect(e)
return v //这里把V替换掉了 return v //这里把V替换掉了
} else { } else {
//默认给叠一层 //默认给叠一层
@@ -237,7 +234,7 @@ func (our *Input) AddEffect(in *Input, e Effect) Effect {
} }
//无限叠加比如能力提升类buff //无限叠加比如能力提升类buff
// 如果没有同 ID 的效果,直接添加 // 如果没有同 ID 的效果,直接添加
our.Effects = append(our.Effects, e) our.appendEffect(e)
return nil return nil
} }
@@ -309,6 +306,34 @@ func (our *Input) CancelTurn(in *Input) {
} }
func (our *Input) ensureEffectIndex() {
if our == nil {
return
}
if our.effectsByBase == nil {
our.effectsByBase = make(map[int64][]Effect, len(our.Effects))
}
if our.indexedEffects > len(our.Effects) {
our.effectsByBase = make(map[int64][]Effect, len(our.Effects))
our.indexedEffects = 0
}
for our.indexedEffects < len(our.Effects) {
effect := our.Effects[our.indexedEffects]
if effect != nil {
our.effectsByBase[effect.ID().Base] = append(our.effectsByBase[effect.ID().Base], effect)
}
our.indexedEffects++
}
}
func (our *Input) appendEffect(effect Effect) {
if our == nil || effect == nil {
return
}
our.Effects = append(our.Effects, effect)
our.ensureEffectIndex()
}
// // 消除全部 断回合效果,但是我放下场的时候应该断掉所有的回合类效果 // // 消除全部 断回合效果,但是我放下场的时候应该断掉所有的回合类效果
// func (our *Input) CancelAll() { // func (our *Input) CancelAll() {
// our.Effects = make([]Effect, 0) // our.Effects = make([]Effect, 0)

View File

@@ -15,6 +15,13 @@ import (
"github.com/jinzhu/copier" "github.com/jinzhu/copier"
) )
var statusBonuses = map[info.EnumPetStatus]float64{
info.PetStatus.Paralysis: 1.5,
info.PetStatus.Poisoned: 1.5,
info.PetStatus.Sleep: 2.0,
// /info.BattleStatus.Frozen: 2.0,
}
type Input struct { type Input struct {
CanChange uint32 //是否可以死亡切换CanChange CanChange uint32 //是否可以死亡切换CanChange
// CanAction bool //是否可以行动 // CanAction bool //是否可以行动
@@ -27,9 +34,11 @@ type Input struct {
CanCapture int CanCapture int
Finished bool //是否加载完成 Finished bool //是否加载完成
// info.BattleActionI // info.BattleActionI
Effects []Effect //effects 实际上全局就是effect无限回合 //effects容器 技能的 Effects []Effect //effects 实际上全局就是effect无限回合 //effects容器 技能的
EffectCache []Effect //这里是命中前执行的容器,也就是命中前执行的所有逻辑相关,理论上一个effect被激活,就应该同时将其他的effect取消激活 EffectCache []Effect //这里是命中前执行的容器,也就是命中前执行的所有逻辑相关,理论上一个effect被激活,就应该同时将其他的effect取消激活
EffectLost []Effect EffectLost []Effect
effectsByBase map[int64][]Effect
indexedEffects int
// 删掉伤害记录,可以在回调中记录,而不是每次调用记录 // 删掉伤害记录,可以在回调中记录,而不是每次调用记录
*model.AttackValue *model.AttackValue
FightC common.FightI FightC common.FightI
@@ -57,6 +66,7 @@ func NewInput(c common.FightI, p common.PlayerI) *Input {
ret := &Input{FightC: c, Player: p} ret := &Input{FightC: c, Player: p}
ret.Effects = make([]Effect, 0) ret.Effects = make([]Effect, 0)
ret.CurPet = make([]*info.BattlePetEntity, 0) ret.CurPet = make([]*info.BattlePetEntity, 0)
ret.effectsByBase = make(map[int64][]Effect)
// t := Geteffect(EffectType.Damage, 0) // t := Geteffect(EffectType.Damage, 0)
// t.Effect.SetArgs(ret) // t.Effect.SetArgs(ret)
@@ -115,6 +125,27 @@ func (our *Input) BenchPets() []*info.BattlePetEntity {
return bench return bench
} }
func (our *Input) HasLivingBench() bool {
if our == nil {
return false
}
current := our.CurrentPet()
currentCatchTime := uint32(0)
if current != nil {
currentCatchTime = current.Info.CatchTime
}
for _, pet := range our.AllPet {
if pet == nil || pet.Info.Hp == 0 {
continue
}
if current != nil && pet.Info.CatchTime == currentCatchTime {
continue
}
return true
}
return false
}
func (our *Input) OpponentSlots() []*Input { func (our *Input) OpponentSlots() []*Input {
if our == nil { if our == nil {
return nil return nil
@@ -299,20 +330,12 @@ func (our *Input) GetPet(id uint32) (ii *info.BattlePetEntity, Reason info.Chang
// GetStatusBonus 获取最高的状态倍率 // GetStatusBonus 获取最高的状态倍率
// 遍历状态数组返回存在的状态中最高的倍率无状态则返回1.0 // 遍历状态数组返回存在的状态中最高的倍率无状态则返回1.0
func (our *Input) GetStatusBonus() float64 { func (our *Input) GetStatusBonus() float64 {
// 异常状态倍率映射表(状态索引 -> 倍率)
var statusBonuses = map[info.EnumPetStatus]float64{
info.PetStatus.Paralysis: 1.5,
info.PetStatus.Poisoned: 1.5,
info.PetStatus.Sleep: 2.0,
// /info.BattleStatus.Frozen: 2.0,
}
maxBonus := 1.0 // 默认无状态倍率 maxBonus := 1.0 // 默认无状态倍率
for statusIdx := 0; statusIdx < 20; statusIdx++ { for statusIdx := 0; statusIdx < 20; statusIdx++ {
t := our.InitEffect(EffectType.Status, statusIdx) t := our.GetEffect(EffectType.Status, statusIdx)
// 检查状态是否存在数组中值为1表示存在该状态 if t != nil && t.Alive() {
if t != nil && t.Stack() > 0 {
if bonus, exists := statusBonuses[info.EnumPetStatus(statusIdx)]; exists && bonus > maxBonus { if bonus, exists := statusBonuses[info.EnumPetStatus(statusIdx)]; exists && bonus > maxBonus {
maxBonus = bonus maxBonus = bonus
} }

View File

@@ -24,6 +24,7 @@ type EffectNode struct {
canStack bool // 最大叠加层数 ,正常都是不允许叠加的,除了衰弱特殊效果 ,异常和能力的叠层 canStack bool // 最大叠加层数 ,正常都是不允许叠加的,除了衰弱特殊效果 ,异常和能力的叠层
isFirst bool isFirst bool
SideEffectArgs []int // 附加效果参数 SideEffectArgs []int // 附加效果参数
cachedArgs []alpacadecimal.Decimal
// owner bool //是否作用自身 // owner bool //是否作用自身
Success bool // 是否执行成功 成功XXX失败XXX Success bool // 是否执行成功 成功XXX失败XXX
arget bool // 传出作用对象,默认0是自身,1是作用于对面 arget bool // 传出作用对象,默认0是自身,1是作用于对面
@@ -240,18 +241,22 @@ func (e *EffectNode) SetArgs(t *input.Input, a ...int) {
e.Input = t e.Input = t
if len(a) > 0 { if len(a) > 0 {
e.SideEffectArgs = a e.SideEffectArgs = a
e.cachedArgs = e.cachedArgs[:0]
for _, v := range a {
e.cachedArgs = append(e.cachedArgs, alpacadecimal.NewFromInt(int64(v)))
}
} }
} }
func (e *EffectNode) Args() []alpacadecimal.Decimal { func (e *EffectNode) Args() []alpacadecimal.Decimal {
var ret []alpacadecimal.Decimal if len(e.cachedArgs) == len(e.SideEffectArgs) {
return e.cachedArgs
for _, v := range e.SideEffectArgs {
ret = append(ret, alpacadecimal.NewFromInt(int64(v)))
} }
e.cachedArgs = e.cachedArgs[:0]
return ret for _, v := range e.SideEffectArgs {
e.cachedArgs = append(e.cachedArgs, alpacadecimal.NewFromInt(int64(v)))
}
return e.cachedArgs
} }