Update AA synchronization, CW progression and diagnostics
This commit is contained in:
1 parent
67a819a4d3
commit
30bee81fe9
30 files changed
+1143
-55
No files matched your search
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand/v2"
|
||||
"sort"
|
||||
|
||||
"gac-hkrpg-go/internal/common"
|
||||
pb "gac-hkrpg-go/protocol/proto"
|
||||
@@ -19,18 +20,19 @@ type cwReferenceEnemies struct {
|
||||
Reference string `json:"reference_executable_sha256"`
|
||||
Excel string `json:"excel_dump_sha256"`
|
||||
Policy struct {
|
||||
FirstChapter uint32 `json:"first_chapter"`
|
||||
FirstStar uint32 `json:"first_chapter_boss_star"`
|
||||
LaterStar uint32 `json:"later_chapter_boss_star"`
|
||||
BaseElite uint32 `json:"base_elite_group"`
|
||||
AlternateThreshold uint32 `json:"alternate_route_threshold"`
|
||||
AlternateElite uint32 `json:"alternate_base_elite_group"`
|
||||
CampMaxTier uint32 `json:"camp_monster_max_tier"`
|
||||
MonsterMaxTier uint32 `json:"monster_max_tier"`
|
||||
FirstMonsterCount uint32 `json:"first_monster_count"`
|
||||
LaterMonsterCount uint32 `json:"later_monster_count"`
|
||||
CampWaveCounts [][]uint32 `json:"camp_wave_counts"`
|
||||
ChapterStarWeights [][]uint32 `json:"chapter_star_weights"`
|
||||
NeutralCampCompatibility string `json:"neutral_camp_compatibility"`
|
||||
FirstChapter uint32 `json:"first_chapter"`
|
||||
FirstStar uint32 `json:"first_chapter_boss_star"`
|
||||
LaterStar uint32 `json:"later_chapter_boss_star"`
|
||||
BaseElite uint32 `json:"base_elite_group"`
|
||||
AlternateThreshold uint32 `json:"alternate_route_threshold"`
|
||||
AlternateElite uint32 `json:"alternate_base_elite_group"`
|
||||
CampMaxTier uint32 `json:"camp_monster_max_tier"`
|
||||
MonsterMaxTier uint32 `json:"monster_max_tier"`
|
||||
FirstMonsterCount uint32 `json:"first_monster_count"`
|
||||
LaterMonsterCount uint32 `json:"later_monster_count"`
|
||||
CampWaveCounts [][]uint32 `json:"camp_wave_counts"`
|
||||
ChapterStarWeights [][]uint32 `json:"chapter_star_weights"`
|
||||
} `json:"policy"`
|
||||
MonsterTiers map[uint32]uint32 `json:"monster_tiers"`
|
||||
EliteGroups []uint32 `json:"elite_groups"`
|
||||
@@ -89,7 +91,7 @@ func cwGenerateReferenceEnemyLayer(c *common.CurrencyWarsCatalog, run *pb.MPIMAE
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
if display == nil || (t.NodeType != "Boss" && t.NodeType != "CampMonster") || display.StageId != t.StageID {
|
||||
if display == nil || (t.NodeType != "Boss" && t.NodeType != "CampMonster" && t.NodeType != "Monster") || display.StageId != t.StageID {
|
||||
return nil, fmt.Errorf("CW reference enemy factory does not support node type %s", t.NodeType)
|
||||
}
|
||||
r, e := cwLoadReferenceEnemies(c)
|
||||
@@ -99,6 +101,9 @@ func cwGenerateReferenceEnemyLayer(c *common.CurrencyWarsCatalog, run *pb.MPIMAE
|
||||
if t.NodeType == "CampMonster" {
|
||||
return cwGenerateReferenceCampLayer(c, run, s, t, r)
|
||||
}
|
||||
if t.NodeType == "Monster" {
|
||||
return cwGenerateReferenceMonsterLayer(c, run, s, t, r)
|
||||
}
|
||||
if s.DCAHJELNJNP == 0 || s.BossInfo == nil || len(s.BossInfo.NCGHKPEMPDP) == 0 || len(s.HEKMEJLMGFF) == 0 {
|
||||
return nil, fmt.Errorf("CW saved chapter boss/camp selection missing")
|
||||
}
|
||||
@@ -140,6 +145,84 @@ func cwGenerateReferenceEnemyLayer(c *common.CurrencyWarsCatalog, run *pb.MPIMAE
|
||||
return &pb.NCKOKDHNJDC{EFECLPJFOCM: &pb.NCKOKDHNJDC_MPOBBIPMNNJ{MPOBBIPMNNJ: layer}}, nil
|
||||
}
|
||||
|
||||
// The original server's neutral camp is a run-owned field absent from our
|
||||
// captured wire. Until that identity can be restored from the Client, select
|
||||
// one eligible captured season camp deterministically per run. This is the
|
||||
// declared compatibility policy, not a claim about the original camp roll.
|
||||
func cwGenerateReferenceMonsterLayer(c *common.CurrencyWarsCatalog, run *pb.MPIMAEMCEFH, s *pb.BEEFLEJAOCN, t common.CurrencyWarsReferenceNodeTemplate, r *cwReferenceEnemies) (*pb.NCKOKDHNJDC, error) {
|
||||
if run == nil || run.UniqueId == 0 || s == nil || s.DCAHJELNJNP == 0 || r.Policy.NeutralCampCompatibility != "stable_random_enabled_season_camp_by_run_id" {
|
||||
return nil, fmt.Errorf("CW neutral camp compatibility policy or run identity missing")
|
||||
}
|
||||
type eligible struct {
|
||||
id uint32
|
||||
monsters []uint32
|
||||
}
|
||||
var camps []eligible
|
||||
for _, camp := range c.MonsterCamps {
|
||||
if camp.SeasonID != run.LJNGPCKPJLF || camp.Common.IfRandomEnabled == 0 {
|
||||
continue
|
||||
}
|
||||
var monsters []uint32
|
||||
for _, id := range camp.Season.MonsterList {
|
||||
if tier, ok := r.MonsterTiers[id]; ok && tier > 0 && tier <= r.Policy.MonsterMaxTier {
|
||||
monsters = append(monsters, id)
|
||||
}
|
||||
}
|
||||
if len(monsters) != 0 {
|
||||
camps = append(camps, eligible{camp.ID, monsters})
|
||||
}
|
||||
}
|
||||
if len(camps) == 0 {
|
||||
return nil, fmt.Errorf("CW no captured neutral camp with eligible monsters")
|
||||
}
|
||||
sort.Slice(camps, func(i, j int) bool { return camps[i].id < camps[j].id })
|
||||
chosen := camps[uint64(run.UniqueId)%uint64(len(camps))]
|
||||
previous, err := cwReferenceEarlierCount(c, s, "Monster", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
count := r.Policy.LaterMonsterCount
|
||||
if previous == 0 {
|
||||
count = r.Policy.FirstMonsterCount
|
||||
}
|
||||
if count == 0 || len(r.Policy.ChapterStarWeights) == 0 {
|
||||
return nil, fmt.Errorf("CW neutral monster policy incomplete")
|
||||
}
|
||||
chapter := int(s.DCAHJELNJNP) - 1
|
||||
if chapter >= len(r.Policy.ChapterStarWeights) {
|
||||
chapter = len(r.Policy.ChapterStarWeights) - 1
|
||||
}
|
||||
weights := r.Policy.ChapterStarWeights[chapter]
|
||||
var total uint32
|
||||
for _, weight := range weights {
|
||||
if ^uint32(0)-total < weight {
|
||||
return nil, fmt.Errorf("CW monster star weights overflow")
|
||||
}
|
||||
total += weight
|
||||
}
|
||||
if total == 0 {
|
||||
return nil, fmt.Errorf("CW monster star weights empty")
|
||||
}
|
||||
wave := &pb.PNAKHANCNGK{OCPEPEMNNEK: 1}
|
||||
for i := uint32(0); i < count; i++ {
|
||||
roll := rand.Uint32N(total)
|
||||
var star uint32
|
||||
for j, weight := range weights {
|
||||
if roll < weight {
|
||||
star = uint32(j + 1)
|
||||
break
|
||||
}
|
||||
roll -= weight
|
||||
}
|
||||
if star == 0 {
|
||||
return nil, fmt.Errorf("CW monster star roll unresolved")
|
||||
}
|
||||
wave.PBLBBDBDLEK = append(wave.PBLBBDBDLEK, &pb.AHKDPCIIELA{MonsterId: chosen.monsters[rand.IntN(len(chosen.monsters))], RoleStar: star})
|
||||
}
|
||||
branch := &pb.KKBGIPCAGGH{IFIIOIIKJHO: t.PenaltyBonusRuleID, MonsterWaveList: []*pb.PNAKHANCNGK{wave}}
|
||||
return &pb.NCKOKDHNJDC{EFECLPJFOCM: &pb.NCKOKDHNJDC_MPOBBIPMNNJ{MPOBBIPMNNJ: &pb.MDJBBILMHLC{LNDKCPBJDKH: chosen.id, MOADBALHMFD: 1, BPDABHGFBFO: []*pb.KKBGIPCAGGH{branch}}}}, nil
|
||||
}
|
||||
|
||||
func cwReferenceEarlierCount(c *common.CurrencyWarsCatalog, s *pb.BEEFLEJAOCN, kind string, sameChapter bool) (uint32, error) {
|
||||
rows, e := c.RouteNodes(s.EMOHLJHPOPC)
|
||||
if e != nil {
|
||||
|
||||
Reference in new issue
Block a user