feat(currency_wars): complete systems, settlement Rank SS, damage report, camera and recovery fixes
This commit is contained in:
1 parent
c008243f11
commit
0995055296
78 files changed
+33840
-9525
No files matched your search
@@ -53,6 +53,11 @@ func ApplyBattleReportContext(report *BattleReport, battle *goproto.SceneBattleI
|
||||
return
|
||||
}
|
||||
report.BattleID, report.StageID = battle.BattleId, battle.StageId
|
||||
if battle.EIGMKOJOEEI != nil {
|
||||
report.IsCurrencyWars = true
|
||||
applyCurrencyWarsBattleReportContext(report, battle)
|
||||
return
|
||||
}
|
||||
indices := make(map[uint32]uint32, len(battle.BattleAvatarList))
|
||||
metadata := make(map[uint32]*goproto.BattleAvatar, len(battle.BattleAvatarList))
|
||||
for _, a := range battle.BattleAvatarList {
|
||||
@@ -82,6 +87,108 @@ func ApplyBattleReportContext(report *BattleReport, battle *goproto.SceneBattleI
|
||||
})
|
||||
}
|
||||
|
||||
// In Currency Wars (GridFight), deployed avatars can exceed 4 (front + back rows).
|
||||
// All active board roles are registered in grid.GridGameRoleList and their damages
|
||||
// are tracked via stt.APAGMJNECCN.DOGMMGLBJIJ.
|
||||
func applyCurrencyWarsBattleReportContext(report *BattleReport, battle *goproto.SceneBattleInfo) {
|
||||
grid := battle.EIGMKOJOEEI
|
||||
if grid == nil {
|
||||
return
|
||||
}
|
||||
metadata := make(map[uint32]*goproto.BattleAvatar)
|
||||
for _, a := range battle.BattleAvatarList {
|
||||
if a != nil {
|
||||
metadata[a.Id] = a
|
||||
}
|
||||
}
|
||||
for _, a := range grid.OPHONCKPNMG {
|
||||
if a != nil {
|
||||
metadata[a.Id] = a
|
||||
}
|
||||
}
|
||||
|
||||
existingByAvatar := make(map[uint32]*BattleAvatarReport, len(report.Avatars))
|
||||
for _, a := range report.Avatars {
|
||||
if a != nil {
|
||||
existingByAvatar[a.AvatarID] = a
|
||||
}
|
||||
}
|
||||
|
||||
if len(grid.GridGameRoleList) > 0 {
|
||||
var cwTotalDamage float64
|
||||
for _, role := range grid.GridGameRoleList {
|
||||
if role == nil {
|
||||
continue
|
||||
}
|
||||
var dmg float64
|
||||
if report.CurrencyWarsRoleDamages != nil {
|
||||
dmg = report.CurrencyWarsRoleDamages[role.RoleId]
|
||||
} else if ex, ok := existingByAvatar[role.AvatarId]; ok {
|
||||
dmg = ex.TotalDamage
|
||||
}
|
||||
cwTotalDamage += dmg
|
||||
}
|
||||
if cwTotalDamage > 0 {
|
||||
report.TeamTotalDamage = cwTotalDamage
|
||||
}
|
||||
|
||||
newAvatars := make([]*BattleAvatarReport, 0, len(grid.GridGameRoleList))
|
||||
for _, role := range grid.GridGameRoleList {
|
||||
if role == nil {
|
||||
continue
|
||||
}
|
||||
avatarID := role.AvatarId
|
||||
if avatarID == 0 && role.RoleId > 100 {
|
||||
avatarID = role.RoleId / 100
|
||||
}
|
||||
ar := existingByAvatar[avatarID]
|
||||
if ar == nil {
|
||||
ar = &BattleAvatarReport{
|
||||
AvatarID: avatarID,
|
||||
AttackTypeDamage: make(map[string]float64),
|
||||
AttackTypeBreakDamage: make(map[string]float64),
|
||||
AttackTypeMaxDamage: make(map[string]float64),
|
||||
}
|
||||
}
|
||||
slot := role.Pos
|
||||
ar.Slot = &slot
|
||||
ar.AvatarRank = role.RoleStar
|
||||
if meta := metadata[avatarID]; meta != nil {
|
||||
ar.AvatarLevel = meta.Level
|
||||
if ar.AvatarRank == 0 && meta.Rank > 0 {
|
||||
ar.AvatarRank = meta.Rank
|
||||
}
|
||||
}
|
||||
if ar.AvatarLevel == 0 {
|
||||
ar.AvatarLevel = 80
|
||||
}
|
||||
if report.CurrencyWarsRoleDamages != nil {
|
||||
if dmg, ok := report.CurrencyWarsRoleDamages[role.RoleId]; ok {
|
||||
ar.TotalDamage = dmg
|
||||
}
|
||||
}
|
||||
if report.TeamTotalDamage > 0 {
|
||||
ar.DamagePercent = (ar.TotalDamage / report.TeamTotalDamage) * 100.0
|
||||
} else {
|
||||
ar.DamagePercent = 0
|
||||
}
|
||||
newAvatars = append(newAvatars, ar)
|
||||
}
|
||||
|
||||
sort.SliceStable(newAvatars, func(i, j int) bool {
|
||||
a, b := newAvatars[i], newAvatars[j]
|
||||
if a == nil || a.Slot == nil {
|
||||
return false
|
||||
}
|
||||
if b == nil || b.Slot == nil {
|
||||
return true
|
||||
}
|
||||
return *a.Slot < *b.Slot
|
||||
})
|
||||
report.Avatars = newAvatars
|
||||
}
|
||||
}
|
||||
|
||||
type BattleMonsterReport struct {
|
||||
EntityID uint32 `json:"entity_id"`
|
||||
MonsterID uint32 `json:"monster_id"`
|
||||
@@ -93,20 +200,22 @@ type BattleMonsterReport struct {
|
||||
}
|
||||
|
||||
type BattleReport struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
BattleID uint32 `json:"battle_id"`
|
||||
StageID uint32 `json:"stage_id"`
|
||||
EndStatus string `json:"end_status"` // "WIN", "FAIL", "QUIT"
|
||||
TotalBattleTurns uint32 `json:"total_battle_turns"`
|
||||
TotalAutoTurns uint32 `json:"total_auto_turns"`
|
||||
RoundCnt uint32 `json:"round_cnt"`
|
||||
CostTime float64 `json:"cost_time"`
|
||||
ChallengeScore uint32 `json:"challenge_score"`
|
||||
TeamTotalDamage float64 `json:"team_total_damage"`
|
||||
TeamTotalHeal float64 `json:"team_total_heal"`
|
||||
TeamTotalShield float64 `json:"team_total_shield"`
|
||||
Avatars []*BattleAvatarReport `json:"avatars"`
|
||||
Monsters []*BattleMonsterReport `json:"monsters"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
BattleID uint32 `json:"battle_id"`
|
||||
StageID uint32 `json:"stage_id"`
|
||||
EndStatus string `json:"end_status"` // "WIN", "FAIL", "QUIT"
|
||||
TotalBattleTurns uint32 `json:"total_battle_turns"`
|
||||
TotalAutoTurns uint32 `json:"total_auto_turns"`
|
||||
RoundCnt uint32 `json:"round_cnt"`
|
||||
CostTime float64 `json:"cost_time"`
|
||||
ChallengeScore uint32 `json:"challenge_score"`
|
||||
TeamTotalDamage float64 `json:"team_total_damage"`
|
||||
TeamTotalHeal float64 `json:"team_total_heal"`
|
||||
TeamTotalShield float64 `json:"team_total_shield"`
|
||||
Avatars []*BattleAvatarReport `json:"avatars"`
|
||||
Monsters []*BattleMonsterReport `json:"monsters"`
|
||||
IsCurrencyWars bool `json:"is_currency_wars,omitempty"`
|
||||
CurrencyWarsRoleDamages map[uint32]float64 `json:"currency_wars_role_damages,omitempty"`
|
||||
}
|
||||
|
||||
// BattleReportFromStatistics converts a protobuf BattleStatistics packet from the game client
|
||||
@@ -129,6 +238,24 @@ func BattleReportFromStatistics(stt *goproto.BattleStatistics, battleID uint32,
|
||||
Monsters: make([]*BattleMonsterReport, 0, len(stt.MonsterList)),
|
||||
}
|
||||
|
||||
// In Currency Wars (GridFight), per-role combat damage is explicitly recorded in
|
||||
// stt.APAGMJNECCN.DOGMMGLBJIJ (*pb.CPNCAPLOIHI).
|
||||
var cwRoleDamages map[uint32]float64
|
||||
var cwTotalRoleDamage float64
|
||||
if stt.APAGMJNECCN != nil && len(stt.APAGMJNECCN.DOGMMGLBJIJ) > 0 {
|
||||
cwRoleDamages = make(map[uint32]float64, len(stt.APAGMJNECCN.DOGMMGLBJIJ))
|
||||
for _, item := range stt.APAGMJNECCN.DOGMMGLBJIJ {
|
||||
if item != nil && item.RoleId != 0 {
|
||||
cwRoleDamages[item.RoleId] = item.Damage
|
||||
if item.Damage > 0 {
|
||||
cwTotalRoleDamage += item.Damage
|
||||
}
|
||||
}
|
||||
}
|
||||
report.CurrencyWarsRoleDamages = cwRoleDamages
|
||||
report.IsCurrencyWars = true
|
||||
}
|
||||
|
||||
// The 4.6.53 schema exposes OKFALMGFHMA entries with avatar_id and damage,
|
||||
// but the enclosing message and several fields remain obfuscated. Treating
|
||||
// these as per-avatar damage records is an inference that still needs a raw
|
||||
@@ -177,6 +304,14 @@ func BattleReportFromStatistics(stt *goproto.BattleStatistics, battleID uint32,
|
||||
if damage == 0 {
|
||||
damage = attackDamageByAvatar[a.Id]
|
||||
}
|
||||
if damage == 0 && cwRoleDamages != nil {
|
||||
for rID, rDmg := range cwRoleDamages {
|
||||
if rID == a.Id || rID/100 == a.Id {
|
||||
damage = rDmg
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
primaryAvatarDamage += damage
|
||||
if damage == 0 {
|
||||
damage = supplementalDamageByAvatar[a.Id]
|
||||
@@ -185,7 +320,9 @@ func BattleReportFromStatistics(stt *goproto.BattleStatistics, battleID uint32,
|
||||
teamHeal += a.TotalHeal
|
||||
teamShield += a.TotalShield
|
||||
}
|
||||
if primaryAvatarDamage == 0 && stt.MFOJKJGKDGD != nil && stt.MFOJKJGKDGD.TotalDamage > 0 {
|
||||
if cwTotalRoleDamage > 0 {
|
||||
teamDmg = cwTotalRoleDamage
|
||||
} else if primaryAvatarDamage == 0 && stt.MFOJKJGKDGD != nil && stt.MFOJKJGKDGD.TotalDamage > 0 {
|
||||
teamDmg = stt.MFOJKJGKDGD.TotalDamage
|
||||
}
|
||||
// If neither avatar aggregate source contains damage, enemy damage-taken
|
||||
@@ -216,6 +353,14 @@ func BattleReportFromStatistics(stt *goproto.BattleStatistics, battleID uint32,
|
||||
if damage == 0 {
|
||||
damage = attackDamageByAvatar[a.Id]
|
||||
}
|
||||
if damage == 0 && cwRoleDamages != nil {
|
||||
for rID, rDmg := range cwRoleDamages {
|
||||
if rID == a.Id || rID/100 == a.Id {
|
||||
damage = rDmg
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if damage == 0 {
|
||||
damage = supplementalDamageByAvatar[a.Id]
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user