test: cover legacy round broadcast handling
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful

This commit is contained in:
xinian
2026-04-16 10:25:56 +08:00
parent 3cfde577eb
commit a43a25c610
5 changed files with 80 additions and 50 deletions

View File

@@ -220,15 +220,6 @@ func (f *FightC) buildNoteUseSkillOutboundInfo() info.NoteUseSkillOutboundInfo {
return result
}
// normalizeMutualKO intentionally does not revive either side.
// Effects that need "survive at 1 HP" on mutual KO must cap damage in their
// own implementation instead of relying on a generic round fallback.
func normalizeMutualKO(attackerPet, defenderPet *info.BattlePetEntity) {
if attackerPet == nil || defenderPet == nil {
return
}
}
func (f *FightC) roundOpponentInput(attacker *input.Input) *input.Input {
if attacker == nil {
return nil
@@ -432,8 +423,8 @@ func (f *FightC) enterturn(firstAttack, secondAttack *action.SelectSkillAction)
return true
})
if defenderPet != nil && attackerPet != nil && defenderPet.Info.Hp <= 0 && attackerPet.Info.Hp <= 0 {
normalizeMutualKO(attackerPet, defenderPet)
if defenderPet != nil && attackerPet != nil && defenderPet.Info.Hp <= 0 && attackerPet.Info.Hp <= 0 { //先手方死亡,触发反同归于尽
attackerPet.Info.Hp = 1
}
if defenderPet != nil && defenderPet.Info.Hp <= 0 {

View File

@@ -1,32 +0,0 @@
package fight
import (
"testing"
fightinfo "blazing/logic/service/fight/info"
"blazing/modules/player/model"
)
func TestNormalizeMutualKODoesNotReviveAttacker(t *testing.T) {
attacker := fightinfo.CreateBattlePetEntity(model.PetInfo{
ID: 1,
Hp: 0,
MaxHp: 100,
CatchTime: 101,
})
defender := fightinfo.CreateBattlePetEntity(model.PetInfo{
ID: 2,
Hp: 0,
MaxHp: 100,
CatchTime: 202,
})
normalizeMutualKO(attacker, defender)
if attacker.Info.Hp != 0 {
t.Fatalf("expected attacker to remain defeated on mutual KO, got hp=%d", attacker.Info.Hp)
}
if defender.Info.Hp != 0 {
t.Fatalf("expected defender to remain defeated on mutual KO, got hp=%d", defender.Info.Hp)
}
}

View File

@@ -7,6 +7,7 @@ import (
"blazing/logic/service/fight/input"
"blazing/modules/player/model"
)
// <!--
// GBTL:
// 1. AtkNum:本技能同时攻击数量, 默认:1(不能为0)
@@ -496,15 +497,23 @@ func (f *FightC) sendLegacyRoundBroadcast(firstAttack, secondAttack *action.Sele
if f == nil || !f.LegacyGroupProtocol {
return
}
if firstAttack != nil {
if f.legacySkillExecuted(firstAttack) {
f.sendLegacyGroupSkillHurt(firstAttack)
}
if secondAttack != nil {
if f.legacySkillExecuted(secondAttack) {
f.sendLegacyGroupSkillHurt(secondAttack)
}
f.sendLegacyGroupBoutDone()
}
func (f *FightC) legacySkillExecuted(skillAction *action.SelectSkillAction) bool {
if f == nil || skillAction == nil {
return false
}
attacker := f.GetInputByAction(skillAction, false)
return attacker != nil && attacker.AttackValue != nil && attacker.AttackValue.SkillID != 0
}
func (f *FightC) sendLegacyGroupSkillHurt(skillAction *action.SelectSkillAction) {
if f == nil || !f.LegacyGroupProtocol || skillAction == nil {
return
@@ -584,10 +593,10 @@ func (f *FightC) buildLegacyGroupSkillAttackInfo(skillAction *action.SelectSkill
if attackValue == nil {
attackValue = info.NewAttackValue(self.UserID)
}
if skillAction != nil && skillAction.SkillEntity != nil {
result.MoveID = uint32(skillAction.SkillEntity.XML.ID)
} else {
if attackValue.SkillID != 0 {
result.MoveID = attackValue.SkillID
} else if skillAction != nil && skillAction.SkillEntity != nil {
result.MoveID = uint32(skillAction.SkillEntity.XML.ID)
}
result.IsCrit = attackValue.IsCritical
result.EffectName = attackValue.State

View File

@@ -0,0 +1,61 @@
package fight
import (
"testing"
"blazing/logic/service/fight/action"
fightinfo "blazing/logic/service/fight/info"
"blazing/logic/service/fight/input"
"blazing/modules/player/model"
)
func TestSendLegacyRoundBroadcastSkipsUnexecutedAction(t *testing.T) {
ourPlayer := &stubPlayer{info: model.PlayerInfo{UserID: 1001}}
oppPlayer := &stubPlayer{info: model.PlayerInfo{UserID: 2002}}
our := input.NewInput(nil, ourPlayer)
our.InitAttackValue()
our.AttackValue.SkillID = 111
our.SetCurPetAt(0, fightinfo.CreateBattlePetEntity(model.PetInfo{
ID: 11,
Hp: 80,
MaxHp: 100,
CatchTime: 101,
}))
opp := input.NewInput(nil, oppPlayer)
opp.InitAttackValue()
opp.SetCurPetAt(0, fightinfo.CreateBattlePetEntity(model.PetInfo{
ID: 22,
Hp: 0,
MaxHp: 100,
CatchTime: 202,
}))
fc := &FightC{
Our: []*input.Input{our},
Opp: []*input.Input{opp},
LegacyGroupProtocol: true,
}
firstAttack := &action.SelectSkillAction{
BaseAction: action.BaseAction{PlayerID: ourPlayer.info.UserID, ActorIndex: 0, TargetIndex: 0},
}
secondAttack := &action.SelectSkillAction{
BaseAction: action.BaseAction{PlayerID: oppPlayer.info.UserID, ActorIndex: 0, TargetIndex: 0},
}
fc.sendLegacyRoundBroadcast(firstAttack, secondAttack)
for _, player := range []*stubPlayer{ourPlayer, oppPlayer} {
if len(player.sentCmds) != 2 {
t.Fatalf("expected one skill packet plus bout done, got %v", player.sentCmds)
}
if player.sentCmds[0] != groupCmdSkillHurt {
t.Fatalf("expected first packet to be skill hurt, got %d", player.sentCmds[0])
}
if player.sentCmds[1] != groupCmdBoutDone {
t.Fatalf("expected second packet to be bout done, got %d", player.sentCmds[1])
}
}
}

View File

@@ -12,7 +12,8 @@ import (
)
type stubPlayer struct {
info model.PlayerInfo
info model.PlayerInfo
sentCmds []uint32
}
func (*stubPlayer) ApplyPetDisplayInfo(*spaceinfo.SimpleInfo) {}
@@ -26,7 +27,7 @@ func (*stubPlayer) SetFightC(common.FightI) {}
func (*stubPlayer) QuitFight() {}
func (*stubPlayer) MessWin(bool) {}
func (*stubPlayer) CanFight() errorcode.ErrorCode { return 0 }
func (*stubPlayer) SendPackCmd(uint32, any) {}
func (p *stubPlayer) SendPackCmd(cmd uint32, _ any) { p.sentCmds = append(p.sentCmds, cmd) }
func (*stubPlayer) GetPetInfo(uint32) []model.PetInfo { return nil }
func TestFightActionEnvelopeEncodedTargetIndex(t *testing.T) {