716 lines
20 KiB
Go
716 lines
20 KiB
Go
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)
|
|
}
|
|
}
|