fix: restore battle entry and character profile initialization
This commit is contained in:
1 parent
cfbbc7b970
commit
5c4d0d4149
16 files changed
+888
-228
No files matched your search
@@ -0,0 +1,191 @@
|
||||
package gameserver
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"gac-hkrpg-go/internal/common"
|
||||
goproto "gac-hkrpg-go/protocol/proto"
|
||||
)
|
||||
|
||||
// Game IDs and character exceptions are resource data with an upstream revision,
|
||||
// not executable defaults. Missing or invalid rules must not silently produce a
|
||||
// different battle.
|
||||
type battleRules struct {
|
||||
EntryAttackBuffs map[string]uint32 `json:"entry_attack_buffs"`
|
||||
Source struct {
|
||||
Revision string `json:"revision"`
|
||||
} `json:"source"`
|
||||
TechniqueBuffs map[uint32][]struct {
|
||||
ID uint32 `json:"id"`
|
||||
Owner string `json:"owner"`
|
||||
DynamicValues map[string]float32 `json:"dynamic_values"`
|
||||
} `json:"technique_buffs"`
|
||||
GlobalPassives []struct {
|
||||
Setting string `json:"setting"`
|
||||
BuffID uint32 `json:"buff_id"`
|
||||
OwnerSlot uint32 `json:"owner_slot"`
|
||||
} `json:"global_passives"`
|
||||
IgnoreToughness struct {
|
||||
Avatars []uint32 `json:"avatars"`
|
||||
BuffID uint32 `json:"buff_id"`
|
||||
} `json:"ignore_toughness"`
|
||||
BattleTargets []struct {
|
||||
BattleType string `json:"battle_type"`
|
||||
Targets map[uint32][]struct {
|
||||
ID uint32 `json:"id"`
|
||||
Progress uint32 `json:"progress"`
|
||||
TotalProgress uint32 `json:"total_progress"`
|
||||
} `json:"targets"`
|
||||
} `json:"battle_targets"`
|
||||
InvasionBuffs map[uint32]uint32 `json:"invasion_buffs"`
|
||||
InvasionSupportBuff uint32 `json:"invasion_support_buff"`
|
||||
}
|
||||
|
||||
var battleRulesOnce sync.Once
|
||||
var loadedBattleRules battleRules
|
||||
var battleRulesErr error
|
||||
|
||||
func loadBattleRules() (*battleRules, error) {
|
||||
battleRulesOnce.Do(func() {
|
||||
raw, err := os.ReadFile("resources/BattleRules.json")
|
||||
if err != nil {
|
||||
battleRulesErr = err
|
||||
return
|
||||
}
|
||||
if err := json.Unmarshal(raw, &loadedBattleRules); err != nil {
|
||||
battleRulesErr = err
|
||||
return
|
||||
}
|
||||
if loadedBattleRules.Source.Revision == "" {
|
||||
battleRulesErr = fmt.Errorf("battle rules need a source revision")
|
||||
return
|
||||
}
|
||||
for _, rules := range loadedBattleRules.TechniqueBuffs {
|
||||
for _, rule := range rules {
|
||||
if rule.ID == 0 || (rule.Owner != "avatar" && rule.Owner != "leader") {
|
||||
battleRulesErr = fmt.Errorf("invalid technique buff rule: %+v", rule)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, rule := range loadedBattleRules.GlobalPassives {
|
||||
if rule.BuffID == 0 || rule.OwnerSlot >= 4 {
|
||||
battleRulesErr = fmt.Errorf("invalid global passive rule: %+v", rule)
|
||||
return
|
||||
}
|
||||
switch rule.Setting {
|
||||
case "enable_sw_global", "enable_castorice_global", "enable_aha_global":
|
||||
default:
|
||||
battleRulesErr = fmt.Errorf("unknown global passive setting %q", rule.Setting)
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
if battleRulesErr != nil {
|
||||
return nil, fmt.Errorf("load resources/BattleRules.json: %w", battleRulesErr)
|
||||
}
|
||||
return &loadedBattleRules, nil
|
||||
}
|
||||
|
||||
func battleBuff(id, owner uint32, dynamic map[string]float32) *goproto.BattleBuff {
|
||||
values := map[string]float32{"SkillIndex": 0}
|
||||
for key, value := range dynamic {
|
||||
values[key] = value
|
||||
}
|
||||
return &goproto.BattleBuff{Id: id, Level: 1, OwnerId: owner,
|
||||
WaveFlag: ^uint32(0), TargetIndexList: []uint32{0}, DynamicValues: values}
|
||||
}
|
||||
|
||||
func (r *battleRules) techniqueBuffs(a *common.AvatarJson, slot, leader uint32, imported []*goproto.BattleBuff) []*goproto.BattleBuff {
|
||||
if len(a.Techniques) == 0 {
|
||||
return nil
|
||||
}
|
||||
buffs := imported
|
||||
// Explicit character rules in PearlSR replace the generic technique. The
|
||||
// user's empty techniques array still disables techniques for that avatar.
|
||||
if rules, ok := r.TechniqueBuffs[a.AvatarID]; ok {
|
||||
buffs = nil
|
||||
for _, rule := range rules {
|
||||
owner := slot
|
||||
if rule.Owner == "leader" {
|
||||
owner = leader
|
||||
}
|
||||
buffs = append(buffs, battleBuff(rule.ID, owner, rule.DynamicValues))
|
||||
}
|
||||
}
|
||||
if containsU32(r.IgnoreToughness.Avatars, a.AvatarID) {
|
||||
found := false
|
||||
for _, buff := range buffs {
|
||||
if buff.Id == r.IgnoreToughness.BuffID {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
buffs = append(buffs, battleBuff(r.IgnoreToughness.BuffID, slot, nil))
|
||||
}
|
||||
}
|
||||
// Global passives are handled once, with their configured owner and setting.
|
||||
result := make([]*goproto.BattleBuff, 0, len(buffs))
|
||||
for _, buff := range buffs {
|
||||
global := false
|
||||
for _, rule := range r.GlobalPassives {
|
||||
if buff.Id == rule.BuffID {
|
||||
global = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !global {
|
||||
result = append(result, buff)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (r *battleRules) addGlobalPassives(battle *goproto.SceneBattleInfo, player *common.FreesrData) {
|
||||
for _, rule := range r.GlobalPassives {
|
||||
var enabled *bool
|
||||
switch rule.Setting {
|
||||
case "enable_sw_global":
|
||||
enabled = player.EnableSWGlobal
|
||||
case "enable_castorice_global":
|
||||
enabled = player.EnableCastoriceGlobal
|
||||
case "enable_aha_global":
|
||||
enabled = player.EnableAhaGlobal
|
||||
}
|
||||
if enabled != nil && !*enabled {
|
||||
continue
|
||||
}
|
||||
owner := rule.OwnerSlot
|
||||
// A shorter lineup must not refer to an absent actor.
|
||||
present := false
|
||||
for _, avatar := range battle.BattleAvatarList {
|
||||
if avatar.Index == owner {
|
||||
present = true
|
||||
}
|
||||
}
|
||||
if !present {
|
||||
owner = battle.BattleAvatarList[0].Index
|
||||
}
|
||||
battle.BuffList = append(battle.BuffList, battleBuff(rule.BuffID, owner, nil))
|
||||
}
|
||||
}
|
||||
|
||||
func (r *battleRules) addTargets(battle *goproto.SceneBattleInfo, kind common.BattleType) {
|
||||
for _, rule := range r.BattleTargets {
|
||||
if !strings.EqualFold(rule.BattleType, string(kind)) {
|
||||
continue
|
||||
}
|
||||
for key, targets := range rule.Targets {
|
||||
list := &goproto.BattleTargetList{}
|
||||
for _, target := range targets {
|
||||
list.BattleTargetList = append(list.BattleTargetList, &goproto.BattleTarget{
|
||||
Id: target.ID, Progress: target.Progress, TotalProgress: target.TotalProgress})
|
||||
}
|
||||
battle.BattleTargetInfo[key] = list
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user