package gameserver import ( "os" "testing" "gac-hkrpg-go/internal/common" pb "gac-hkrpg-go/protocol/proto" "google.golang.org/protobuf/proto" ) func TestTrailblazeCatalog(t *testing.T) { cat, err := common.LoadCurrencyWarsTrailblaze() if err != nil { t.Fatalf("LoadCurrencyWarsTrailblaze: %v", err) } if len(cat.Goods) != 47 { t.Errorf("expected 47 goods, got %d", len(cat.Goods)) } if cat.Income(2) != 20 || cat.Income(4) != 45 || cat.Income(6) != 75 || cat.Income(8) != 125 || cat.Income(10) != 225 { t.Errorf("unexpected income per layer: %v", cat.LayerParams) } if cat.InitialGoodID != 101 { t.Errorf("expected initial good 101, got %d", cat.InitialGoodID) } if cat.RefreshGoodID != 999 { t.Errorf("expected refresh good 999, got %d", cat.RefreshGoodID) } if cat.PomGoodID != 507 { t.Errorf("expected pom good 507, got %d", cat.PomGoodID) } if cat.PomThreshold != 300 { t.Errorf("expected pom threshold 300, got %d", cat.PomThreshold) } } func TestTrailblazeNodeEnteredAndRoll(t *testing.T) { catalog, err := common.LoadCurrencyWarsCatalog() if err != nil { t.Fatalf("LoadCurrencyWarsCatalog: %v", err) } tbCat, err := common.LoadCurrencyWarsTrailblaze() if err != nil { t.Fatalf("LoadCurrencyWarsTrailblaze: %v", err) } // Deploy 2 Welt (100402) which has trait 100502 (Trailblaze Silver Rail) run := &pb.MPIMAEMCEFH{ UniqueId: 999, NAGDJGMMCBE: []*pb.GridFightGameInfo{ { LEOIAOFBBFA: &pb.GridFightGameInfo_KLCPAAHDPJF{ KLCPAAHDPJF: &pb.BEEFLEJAOCN{ DCAHJELNJNP: 1, SectionId: 1, }, }, }, { LEOIAOFBBFA: &pb.GridFightGameInfo_FAOCFBOFCJP{ FAOCFBOFCJP: &pb.NIHNGPKHEPC{ MICEOJBAKGN: 4, }, }, }, { LEOIAOFBBFA: &pb.GridFightGameInfo_EJIPINIKNCK{ EJIPINIKNCK: &pb.HKFECLCHBFJ{ GridGameRoleList: []*pb.CDEAABODKCP{ {Id: 100402, RoleStar: 1, Pos: 1, UniqueId: 101}, {Id: 100402, RoleStar: 1, Pos: 2, UniqueId: 102}, }, }, }, }, { LEOIAOFBBFA: &pb.GridFightGameInfo_GCKLIONKMJC{ GCKLIONKMJC: &pb.CONONEALNOF{}, }, }, }, } layer := cwGetTrailblazeLayer(catalog, run) if layer != 2 { t.Fatalf("expected Trailblaze layer 2, got %d", layer) } runtime := &common.CurrencyWarsRuntimeState{ RunID: 999, Rules: make(map[string]uint32), } cwTrailblazeNodeEntered(catalog, run, runtime) if runtime.Rules["TbOpened"] != 1 { t.Errorf("expected TbOpened=1, got %d", runtime.Rules["TbOpened"]) } if runtime.Rules["TbGood/0"] != tbCat.InitialGoodID { t.Errorf("expected slot 0 to be initial good %d, got %d", tbCat.InitialGoodID, runtime.Rules["TbGood/0"]) } shop := cwTrailblazeShopProto(tbCat, runtime) if len(shop.OGDKJPDFFAI) != 5 { t.Fatalf("expected 5 shop entries (4 slots + 1 refresh), got %d", len(shop.OGDKJPDFFAI)) } if shop.OGDKJPDFFAI[0].GoodsId != tbCat.InitialGoodID { t.Errorf("expected slot 0 good %d, got %d", tbCat.InitialGoodID, shop.OGDKJPDFFAI[0].GoodsId) } if shop.OGDKJPDFFAI[4].GoodsId != tbCat.RefreshGoodID { t.Errorf("expected slot 4 good %d, got %d", tbCat.RefreshGoodID, shop.OGDKJPDFFAI[4].GoodsId) } if shop.OGDKJPDFFAI[4].OICGFNGNLOE != 1 { t.Errorf("expected refresh cost 1, got %d", shop.OGDKJPDFFAI[4].OICGFNGNLOE) } } func TestTrailblazeBuyFreeInitialGood(t *testing.T) { catalog, err := common.LoadCurrencyWarsCatalog() if err != nil { t.Fatalf("LoadCurrencyWarsCatalog: %v", err) } tbCat, err := common.LoadCurrencyWarsTrailblaze() if err != nil { t.Fatalf("LoadCurrencyWarsTrailblaze: %v", err) } run := &pb.MPIMAEMCEFH{ UniqueId: 999, NAGDJGMMCBE: []*pb.GridFightGameInfo{ { LEOIAOFBBFA: &pb.GridFightGameInfo_KLCPAAHDPJF{ KLCPAAHDPJF: &pb.BEEFLEJAOCN{DCAHJELNJNP: 1, SectionId: 1}, }, }, { LEOIAOFBBFA: &pb.GridFightGameInfo_FAOCFBOFCJP{ FAOCFBOFCJP: &pb.NIHNGPKHEPC{MICEOJBAKGN: 4}, }, }, { LEOIAOFBBFA: &pb.GridFightGameInfo_EJIPINIKNCK{ EJIPINIKNCK: &pb.HKFECLCHBFJ{ GridGameRoleList: []*pb.CDEAABODKCP{ {Id: 100402, RoleStar: 1, Pos: 1, UniqueId: 101}, {Id: 100402, RoleStar: 1, Pos: 2, UniqueId: 102}, }, }, }, }, { LEOIAOFBBFA: &pb.GridFightGameInfo_GCKLIONKMJC{ GCKLIONKMJC: &pb.CONONEALNOF{}, }, }, }, } runtime := &common.CurrencyWarsRuntimeState{ RunID: 999, Rules: make(map[string]uint32), } cwTrailblazeNodeEntered(catalog, run, runtime) // Buy pos 0 (Good 101, cost 0) with 0 Trailblaze Power notify, err := cwTrailblazeBuy(catalog, run, runtime, 0) if err != nil { t.Fatalf("cwTrailblazeBuy pos 0: %v", err) } if notify == nil || len(notify.GCPNIHHBGGD) == 0 { t.Fatal("expected notify from buy") } if tbBoughtCount(runtime, tbCat.InitialGoodID) != 1 { t.Errorf("expected InitialGoodID bought count 1, got %d", tbBoughtCount(runtime, tbCat.InitialGoodID)) } // Buying unique maze_buff again must fail _, err = cwTrailblazeBuy(catalog, run, runtime, 0) if err == nil { t.Fatal("expected error buying already purchased maze_buff") } } func TestTrailblazeRefreshAndPomUnlock(t *testing.T) { catalog, err := common.LoadCurrencyWarsCatalog() if err != nil { t.Fatalf("LoadCurrencyWarsCatalog: %v", err) } tbCat, err := common.LoadCurrencyWarsTrailblaze() if err != nil { t.Fatalf("LoadCurrencyWarsTrailblaze: %v", err) } run := &pb.MPIMAEMCEFH{ UniqueId: 999, NAGDJGMMCBE: []*pb.GridFightGameInfo{ { LEOIAOFBBFA: &pb.GridFightGameInfo_KLCPAAHDPJF{ KLCPAAHDPJF: &pb.BEEFLEJAOCN{DCAHJELNJNP: 1, SectionId: 1}, }, }, { LEOIAOFBBFA: &pb.GridFightGameInfo_FAOCFBOFCJP{ FAOCFBOFCJP: &pb.NIHNGPKHEPC{MICEOJBAKGN: 8}, }, }, { LEOIAOFBBFA: &pb.GridFightGameInfo_EJIPINIKNCK{ EJIPINIKNCK: &pb.HKFECLCHBFJ{ GridGameRoleList: []*pb.CDEAABODKCP{ {Id: 100402, RoleStar: 1, Pos: 1, UniqueId: 101}, {Id: 100402, RoleStar: 1, Pos: 2, UniqueId: 102}, }, }, }, }, { LEOIAOFBBFA: &pb.GridFightGameInfo_GCKLIONKMJC{ GCKLIONKMJC: &pb.CONONEALNOF{}, }, }, }, } runtime := &common.CurrencyWarsRuntimeState{ RunID: 999, Rules: make(map[string]uint32), } cwTrailblazeNodeEntered(catalog, run, runtime) // Give power runtime.Rules["TbPower"] = 500 runtime.Rules["TbCosted"] = 299 // 1 below threshold (300) // Buy refresh at pos 4 (cost 1) _, err = cwTrailblazeBuy(catalog, run, runtime, 4) if err != nil { t.Fatalf("cwTrailblazeBuy refresh: %v", err) } if runtime.Rules["TbCosted"] != 300 { t.Errorf("expected TbCosted=300, got %d", runtime.Rules["TbCosted"]) } if runtime.Rules["TbRefreshCount"] != 1 { t.Errorf("expected TbRefreshCount=1, got %d", runtime.Rules["TbRefreshCount"]) } // King Pom-Pom should now be in the store (slot 0) if runtime.Rules["TbGood/0"] != tbCat.PomGoodID { t.Errorf("expected King Pom-Pom (%d) in slot 0, got %d", tbCat.PomGoodID, runtime.Rules["TbGood/0"]) } // Buy King Pom-Pom at pos 0 (cost 100) initialPower := runtime.Rules["TbPower"] _, err = cwTrailblazeBuy(catalog, run, runtime, 0) if err != nil { t.Fatalf("cwTrailblazeBuy King Pom: %v", err) } if runtime.Rules["TbPower"] != initialPower-100 { t.Errorf("expected power %d, got %d", initialPower-100, runtime.Rules["TbPower"]) } // Check if King Pom role 604202 is on the bench _, team, _ := cwComponents(run) foundPom := false for _, r := range team.GridGameRoleList { if r.Id == 604202 { foundPom = true if r.Pos < 14 { t.Errorf("expected King Pom to be on bench (>=14), got pos %d", r.Pos) } break } } if !foundPom { t.Error("King Pom-Pom role 604202 was not added to team") } } func TestTrailblazeSyncTraitComponent(t *testing.T) { catalog, err := common.LoadCurrencyWarsCatalog() if err != nil { t.Fatalf("LoadCurrencyWarsCatalog: %v", err) } run := &pb.MPIMAEMCEFH{ UniqueId: 999, NAGDJGMMCBE: []*pb.GridFightGameInfo{ { LEOIAOFBBFA: &pb.GridFightGameInfo_KLCPAAHDPJF{ KLCPAAHDPJF: &pb.BEEFLEJAOCN{DCAHJELNJNP: 1, SectionId: 1}, }, }, { LEOIAOFBBFA: &pb.GridFightGameInfo_FAOCFBOFCJP{ FAOCFBOFCJP: &pb.NIHNGPKHEPC{MICEOJBAKGN: 4}, }, }, { LEOIAOFBBFA: &pb.GridFightGameInfo_EJIPINIKNCK{ EJIPINIKNCK: &pb.HKFECLCHBFJ{ GridGameRoleList: []*pb.CDEAABODKCP{ {Id: 100402, RoleStar: 1, Pos: 1, UniqueId: 101}, {Id: 100402, RoleStar: 1, Pos: 2, UniqueId: 102}, }, }, }, }, }, } runtime := &common.CurrencyWarsRuntimeState{ RunID: 999, Rules: map[string]uint32{ "TbPower": 45, "TbCosted": 100, }, } cwSyncTraitComponent(catalog, run, runtime) // Check OAHOAPCIDMK component exists in run.NAGDJGMMCBE var traitComp *pb.FFOGFOBHDEK for _, c := range run.NAGDJGMMCBE { if c.GetOAHOAPCIDMK() != nil { traitComp = c.GetOAHOAPCIDMK() break } } if traitComp == nil { t.Fatal("expected OAHOAPCIDMK component in NAGDJGMMCBE") } foundTB := false for _, tr := range traitComp.GridFightTraitInfo { if tr.TraitId == cwTrailblazeTrait { foundTB = true if tr.KOJFHFAKKFO != 2 { t.Errorf("expected layer 2, got %d", tr.KOJFHFAKKFO) } if len(tr.TraitEffectList) == 0 { t.Fatal("expected TraitEffectList for Trailblaze trait") } eff := tr.TraitEffectList[0] if eff.EffectId != cwTrailblazeEffect { t.Errorf("expected effect ID %d, got %d", cwTrailblazeEffect, eff.EffectId) } shop := eff.GetKDBKIPPHMFI() if shop == nil { t.Fatal("expected shop proto KDBKIPPHMFI in effect") } if shop.MJIGJEGMCML != 45 { t.Errorf("expected shop power 45, got %d", shop.MJIGJEGMCML) } break } } if !foundTB { t.Error("Trailblaze trait 100502 not found in GridFightTraitInfo") } // Check modifier in run.CAAGABEPPPE if run.CAAGABEPPPE == nil || len(run.CAAGABEPPPE.KLCKAOJAMNH) == 0 { t.Fatal("expected CAAGABEPPPE modifier list on run") } mod := run.CAAGABEPPPE.KLCKAOJAMNH[0] if mod.UniqueId != cwTrailblazeModifierUID { t.Errorf("expected modifier UID %d, got %d", cwTrailblazeModifierUID, mod.UniqueId) } progress := mod.GetONKMJAGNECC() if progress == nil { t.Fatal("expected ONKMJAGNECC in modifier") } if progress.IANFMIJBKAF != 100 || progress.PLAIPMBIHGJ != 300 { t.Errorf("expected modifier costed=100/300, got %d/%d", progress.IANFMIJBKAF, progress.PLAIPMBIHGJ) } } func TestGridFightTraitUpdateHandler(t *testing.T) { origPersistent, _ := os.ReadFile("persistent") if origPersistent != nil { t.Cleanup(func() { _ = os.WriteFile("persistent", origPersistent, 0644) }) } session := &Session{Token: 88888} catalog, err := common.LoadCurrencyWarsCatalog() if err != nil { t.Fatalf("load catalog: %v", err) } data, rev, err := readCurrencyWarsData(catalog) if err != nil || data == nil || data.DHFOFLFCLAH == nil { data, err = newCurrencyWarsData(catalog) if err != nil { t.Fatalf("new data: %v", err) } data.DHFOFLFCLAH = &pb.MPIMAEMCEFH{ UniqueId: 1, DivisionId: catalog.CapturedStages[0].ID, LJNGPCKPJLF: catalog.ActiveSeasonID, NAGDJGMMCBE: []*pb.GridFightGameInfo{ {LEOIAOFBBFA: &pb.GridFightGameInfo_KLCPAAHDPJF{KLCPAAHDPJF: &pb.BEEFLEJAOCN{DCAHJELNJNP: 1, SectionId: 1}}}, {LEOIAOFBBFA: &pb.GridFightGameInfo_FAOCFBOFCJP{FAOCFBOFCJP: &pb.NIHNGPKHEPC{MICEOJBAKGN: 4}}}, {LEOIAOFBBFA: &pb.GridFightGameInfo_EJIPINIKNCK{EJIPINIKNCK: &pb.HKFECLCHBFJ{ GridGameRoleList: []*pb.CDEAABODKCP{ {Id: 100402, RoleStar: 1, Pos: 1, UniqueId: 101}, {Id: 100402, RoleStar: 1, Pos: 2, UniqueId: 102}, }, }}}, {LEOIAOFBBFA: &pb.GridFightGameInfo_GCKLIONKMJC{GCKLIONKMJC: &pb.CONONEALNOF{}}}, }, } rev = 0 } else { // Ensure run has Trailblaze roles on board for testing _, team, _ := cwComponents(data.DHFOFLFCLAH) if team != nil { team.GridGameRoleList = append(team.GridGameRoleList, &pb.CDEAABODKCP{Id: 100402, RoleStar: 1, Pos: 1, UniqueId: 801}, &pb.CDEAABODKCP{Id: 100402, RoleStar: 1, Pos: 2, UniqueId: 802}, ) } } if _, latestRev, err := readCurrencyWarsData(catalog); err == nil { session.currencyWarsRevision = latestRev } else { session.currencyWarsRevision = rev } runtime := &common.CurrencyWarsRuntimeState{ RunID: data.DHFOFLFCLAH.UniqueId, Rules: map[string]uint32{"TbPower": 10}, } if err := session.saveCurrencyWarsDataWithRuntime(data, catalog, runtime); err != nil { t.Fatalf("save initial data: %v", err) } cmdID, ok := pb.CmdIDByName["GridFightTraitUpdateCsReq"] if !ok || typedHandlers[uint16(cmdID)] == nil { t.Fatal("handler GridFightTraitUpdate not registered") } // Buy pos 0 (Good 101, cost 0) req := &pb.GridFightTraitUpdateCsReq{ TraitId: cwTrailblazeTrait, EffectId: cwTrailblazeEffect, NEBNJDMFELO: &pb.GridFightTraitUpdateCsReq_KDBKIPPHMFI{ KDBKIPPHMFI: &pb.KDGHLGHJDMC{Pos: 0}, }, } rawReq, err := proto.Marshal(req) if err != nil { t.Fatalf("marshal req: %v", err) } if err := typedHandlers[uint16(cmdID)](session, rawReq); err != nil { t.Fatalf("call GridFightTraitUpdate: %v", err) } } func TestCurrencyWarsTrailblazePowerCommand(t *testing.T) { catalog, err := common.LoadCurrencyWarsCatalog() if err != nil { t.Fatalf("load catalog: %v", err) } tbCat, err := common.LoadCurrencyWarsTrailblaze() if err != nil { t.Fatalf("load tb catalog: %v", err) } run := &pb.MPIMAEMCEFH{ UniqueId: 99, DivisionId: catalog.CapturedStages[0].ID, NAGDJGMMCBE: []*pb.GridFightGameInfo{ {LEOIAOFBBFA: &pb.GridFightGameInfo_KLCPAAHDPJF{KLCPAAHDPJF: &pb.BEEFLEJAOCN{DCAHJELNJNP: 1, SectionId: 1}}}, {LEOIAOFBBFA: &pb.GridFightGameInfo_FAOCFBOFCJP{FAOCFBOFCJP: &pb.NIHNGPKHEPC{MICEOJBAKGN: 4, GridFightLineupHp: 100, PPKKHHNEOHB: 100}}}, {LEOIAOFBBFA: &pb.GridFightGameInfo_EJIPINIKNCK{EJIPINIKNCK: &pb.HKFECLCHBFJ{}}}, {LEOIAOFBBFA: &pb.GridFightGameInfo_GCKLIONKMJC{GCKLIONKMJC: &pb.CONONEALNOF{}}}, }, } runtime := &common.CurrencyWarsRuntimeState{ RunID: run.UniqueId, Rules: make(map[string]uint32), } // 1. Test cwApplyCommand with "tbpower" cmd := common.CurrencyWarsCommand{Field: "tbpower", Value: 120, Quantity: 1} notify, err := cwApplyCommand(catalog, run, cmd, runtime) if err != nil { t.Fatalf("cwApplyCommand failed: %v", err) } if runtime.Rules["TbPower"] != 120 { t.Fatalf("expected TbPower=120, got %d", runtime.Rules["TbPower"]) } if runtime.Rules["TbOpened"] != 1 { t.Fatalf("expected TbOpened=1, got %d", runtime.Rules["TbOpened"]) } if notify == nil || len(notify.GCPNIHHBGGD) == 0 { t.Fatal("expected notification with trait bundle") } // 2. Test alias "tb" cmdAlias := common.CurrencyWarsCommand{Field: "tb", Value: 250, Quantity: 1} notifyAlias, err := cwApplyCommand(catalog, run, cmdAlias, runtime) if err != nil { t.Fatalf("cwApplyCommand with alias tb failed: %v", err) } if runtime.Rules["TbPower"] != 250 { t.Fatalf("expected TbPower=250, got %d", runtime.Rules["TbPower"]) } if notifyAlias == nil { t.Fatal("expected notification for tb alias") } // 3. Test QueueCurrencyWarsGrant validation cmdID, err := common.QueueCurrencyWarsGrant(1337, run.UniqueId, "tbpower", 300, 1, 0) if err != nil { t.Fatalf("QueueCurrencyWarsGrant tbpower failed: %v", err) } if cmdID == "" { t.Fatal("expected non-empty command ID") } _ = common.AcknowledgeCurrencyWarsCommand(cmdID) cmdID2, err := common.QueueCurrencyWarsGrant(1337, run.UniqueId, "tb", 50, 1, 0) if err != nil { t.Fatalf("QueueCurrencyWarsGrant tb failed: %v", err) } _ = common.AcknowledgeCurrencyWarsCommand(cmdID2) _ = tbCat } func TestTrailblazeConsumableItemPurchase(t *testing.T) { catalog, err := common.LoadCurrencyWarsCatalog() if err != nil { t.Fatalf("LoadCurrencyWarsCatalog: %v", err) } run := &pb.MPIMAEMCEFH{ UniqueId: 888, NAGDJGMMCBE: []*pb.GridFightGameInfo{ { LEOIAOFBBFA: &pb.GridFightGameInfo_KLCPAAHDPJF{ KLCPAAHDPJF: &pb.BEEFLEJAOCN{DCAHJELNJNP: 1, SectionId: 1}, }, }, { LEOIAOFBBFA: &pb.GridFightGameInfo_FAOCFBOFCJP{ FAOCFBOFCJP: &pb.NIHNGPKHEPC{MICEOJBAKGN: 8}, }, }, { LEOIAOFBBFA: &pb.GridFightGameInfo_EJIPINIKNCK{ EJIPINIKNCK: &pb.HKFECLCHBFJ{ GridGameRoleList: []*pb.CDEAABODKCP{ {Id: 100402, RoleStar: 1, Pos: 1, UniqueId: 101}, {Id: 100402, RoleStar: 1, Pos: 2, UniqueId: 102}, }, }, }, }, { LEOIAOFBBFA: &pb.GridFightGameInfo_GCKLIONKMJC{ GCKLIONKMJC: &pb.CONONEALNOF{}, }, }, }, } runtime := &common.CurrencyWarsRuntimeState{ RunID: 888, Rules: map[string]uint32{ "TbOpened": 1, "TbPower": 200, "TbGood/0": 401, // Item 350113 (consumable) }, } notify, err := cwTrailblazeBuy(catalog, run, runtime, 0) if err != nil { t.Fatalf("cwTrailblazeBuy good 401: %v", err) } if notify == nil { t.Fatal("expected notify from buy") } // Slot 0 must be cleared if runtime.Rules["TbGood/0"] != 0 { t.Errorf("expected slot 0 cleared, got %d", runtime.Rules["TbGood/0"]) } // Verify consumable is added, NOT added to equipment list bag := cwEquipmentBag(run) if len(bag.GridFightEquipmentList) != 0 { t.Errorf("expected equipment list empty, got %d items", len(bag.GridFightEquipmentList)) } if len(bag.IPMKOMEHBMP) != 1 || bag.IPMKOMEHBMP[0].ItemId != 350113 { t.Errorf("expected consumable item 350113 in bag, got %+v", bag.IPMKOMEHBMP) } } func TestTrailblazeBattleTraitsAndPowerSync(t *testing.T) { catalog, err := common.LoadCurrencyWarsCatalog() if err != nil { t.Fatalf("LoadCurrencyWarsCatalog: %v", err) } run := &pb.MPIMAEMCEFH{ UniqueId: 777, NAGDJGMMCBE: []*pb.GridFightGameInfo{ { LEOIAOFBBFA: &pb.GridFightGameInfo_EJIPINIKNCK{ EJIPINIKNCK: &pb.HKFECLCHBFJ{ GridGameRoleList: []*pb.CDEAABODKCP{ {Id: 100402, RoleStar: 1, Pos: 1, UniqueId: 101}, {Id: 604202, RoleStar: 2, Pos: 2, UniqueId: 102}, }, }, }, }, { LEOIAOFBBFA: &pb.GridFightGameInfo_GCKLIONKMJC{ GCKLIONKMJC: &pb.CONONEALNOF{}, }, }, }, } runtime := &common.CurrencyWarsRuntimeState{ RunID: 777, Rules: map[string]uint32{ "TbOpened": 1, "TbPower": 330, "TbCosted": 300, "TbBought/101": 1, "TbBought/201": 1, }, } // 1. Battle traits battleTraits := cwCalculateBattleTraits(catalog, run, runtime) var foundTb *pb.NIEGDAPHKGC for _, tr := range battleTraits { if tr.TraitId == cwTrailblazeTrait { foundTb = tr break } } if foundTb == nil { t.Fatal("expected Trailblaze trait in battle traits") } if len(foundTb.TraitEffectList) == 0 { t.Fatal("expected trait effects on Trailblaze trait") } effect := foundTb.TraitEffectList[0] if effect.EffectId != cwTrailblazeEffect { t.Errorf("expected effect ID %d, got %d", cwTrailblazeEffect, effect.EffectId) } effData := effect.GetKDBKIPPHMFI() if effData == nil || effData.MJIGJEGMCML != 330 { t.Errorf("expected MJIGJEGMCML=330, got %+v", effData) } // 2. Trial avatar for King Pom-Pom pomVariant, err := catalog.CapturedRoleVariant(604202, 2) if err != nil { t.Fatalf("CapturedRoleVariant 604202: %v", err) } avatar, err := cwTrialBattleAvatar(catalog, pomVariant, 1) if err != nil { t.Fatalf("cwTrialBattleAvatar: %v", err) } if avatar.Id != 6042 { t.Errorf("expected AvatarID 6042, got %d", avatar.Id) } if avatar.AvatarType != pb.AvatarType_AvatarType_AvatarGridFightType { t.Errorf("expected AvatarGridFightType, got %v", avatar.AvatarType) } } func TestClaimableRewardsAndWeeklyHandlers(t *testing.T) { s := &Session{Token: 12345} // 1. GridFightTakeWeeklyReward reqWeekly := &pb.GridFightTakeWeeklyRewardCsReq{JKCEBHFIENI: []uint32{1, 2}} rspWeekly := &pb.GridFightTakeWeeklyRewardScRsp{} cmdID, ok := pb.CmdIDByName["GridFightTakeWeeklyRewardCsReq"] if !ok { t.Fatal("CmdIDByName GridFightTakeWeeklyRewardCsReq missing") } handler, ok := typedHandlers[cmdID] if !ok { t.Fatal("handler GridFightTakeWeeklyRewardCsReq missing") } data, _ := proto.Marshal(reqWeekly) if err := handler(s, data); err != nil { t.Fatalf("call GridFightTakeWeeklyReward: %v", err) } _ = rspWeekly // 2. GridFightUpdateSpotLightTrack reqTrack := &pb.GridFightUpdateSpotLightTrackCsReq{} cmdIDTrack, ok := pb.CmdIDByName["GridFightUpdateSpotLightTrackCsReq"] if !ok { t.Fatal("CmdIDByName GridFightUpdateSpotLightTrackCsReq missing") } handlerTrack, ok := typedHandlers[cmdIDTrack] if !ok { t.Fatal("handler GridFightUpdateSpotLightTrackCsReq missing") } dataTrack, _ := proto.Marshal(reqTrack) if err := handlerTrack(s, dataTrack); err != nil { t.Fatalf("call GridFightUpdateSpotLightTrack: %v", err) } }