Files
GaCy-GO/internal/gameserver/currency_wars_experience.go
2026-10-28 18:54:43 +07:00

92 lines
3.7 KiB
Go

package gameserver
import (
"fmt"
"gac-hkrpg-go/internal/common"
pb "gac-hkrpg-go/protocol/proto"
)
// The current native BuyExp capture sends capacity, shop weights and level
// together. The native before/after capture does not rewrite individual role
// property maps. This does not implement all level-dependent combat effects.
func cwApplyBaseExperience(catalog *common.CurrencyWarsCatalog, player *pb.NIHNGPKHEPC, shop *pb.POCJDMMANBM, gain uint32) error {
previous, err := catalog.PlayerLevel(player.EHNJDIDABHD)
if err != nil {
return err
}
plan, err := catalog.PlanBaseExperience(player.EHNJDIDABHD, player.GridFightCurLevelExp, gain, player.NDAINFLOLPJ)
if err != nil {
return err
}
row, err := catalog.PlayerLevel(plan.Level)
if err != nil {
return err
}
// Preserve already resolved run bonuses, rather than resetting capacity
// to the unmodified level table when equipment/augments add slots.
capacity := int64(player.AFFCFLFIFPH) + int64(row.AvatarMaxNumber) - int64(previous.AvatarMaxNumber)
if capacity <= 0 || uint64(capacity) > uint64(^uint32(0)) {
return fmt.Errorf("CW level capacity is outside protocol range")
}
player.EHNJDIDABHD = plan.Level
player.GridFightCurLevelExp = plan.Exp
player.AFFCFLFIFPH = uint32(capacity)
shop.ABBNGCPECAI = &pb.MONJNCPINKN{}
for i, weight := range row.RarityWeights() {
shop.ABBNGCPECAI.FIJPICNPKIG = append(shop.ABBNGCPECAI.FIJPICNPKIG, &pb.BOPHDCKJMMN{CKKDAEMFDPA: uint32(i + 1), APAKCBFMCAB: weight})
}
return nil
}
func cwCapacitySync(player *pb.NIHNGPKHEPC) *pb.KFNCAIHIHCM {
return &pb.KFNCAIHIHCM{MNLCHEJKDHO: &pb.KFNCAIHIHCM_BPCFDPNHIEL{BPCFDPNHIEL: player.AFFCFLFIFPH}}
}
func init() {
cwHandle("GridFightBuyExp", func(s *Session, _ *pb.GridFightBuyExpCsReq, rsp *pb.GridFightBuyExpScRsp) error {
rsp.Retcode = uint32(pb.Retcode_RET_GRID_FIGHT_PARAM_NOT_MATCH)
catalog, data, err := cwPreparingData(s)
if err != nil {
PacketLog("CW_BUY_EXP rejected: " + err.Error())
return nil
}
player, _, shop := cwComponents(data.DHFOFLFCLAH)
if player == nil || shop == nil {
return nil
}
row, err := catalog.PlayerLevel(player.EHNJDIDABHD)
if err != nil || row.LevelUpExp == 0 || player.EHNJDIDABHD >= player.NDAINFLOLPJ {
return nil
}
cost := player.BEPMODICONA // The run's resolved quote, not a fixed gold price.
if player.Gold < cost {
rsp.Retcode = uint32(pb.Retcode_RET_GRID_FIGHT_COIN_NOT_ENOUGH)
return nil
}
gain, err := catalog.IntegerRule("GridFight_LevelUpExp")
if err != nil || gain <= 0 || uint64(gain) > uint64(^uint32(0)) {
PacketLog(fmt.Sprintf("CW_BUY_EXP rejected: missing or invalid GridFight_LevelUpExp rule value=%d error=%v", gain, err))
rsp.Retcode = uint32(pb.Retcode_RET_GRID_FIGHT_CONF_MISS)
return nil
}
if err = cwApplyBaseExperience(catalog, player, shop, uint32(gain)); err != nil {
PacketLog("CW_BUY_EXP rejected: " + err.Error())
return nil
}
player.Gold -= cost
if err = s.saveCurrencyWarsData(data, catalog); err != nil {
PacketLog("CW_BUY_EXP save failed: " + err.Error())
return nil
}
notify := cwNotify(cwGoldSync(player.Gold), cwCapacitySync(player), cwShopSync(shop), &pb.KFNCAIHIHCM{MNLCHEJKDHO: &pb.KFNCAIHIHCM_PLPHEIBLPDL{PLPHEIBLPDL: &pb.PIHKLPJGEPM{Level: player.EHNJDIDABHD, Exp: player.GridFightCurLevelExp, HFMKLAPEKFA: player.NDAINFLOLPJ}}})
notify.GCPNIHHBGGD[0].GridUpdateSrc = pb.JJDFGMMMCMI_JJDFGMMMCMI_IHEKGIGCGEC
if err = cwSend(s, notify); err != nil {
return err
}
rsp.Retcode = 0
PacketLog(fmt.Sprintf("CW_BUY_EXP saved cost=%d gain=%d level=%d exp=%d capacity=%d gold=%d revision=%d", cost, gain, player.EHNJDIDABHD, player.GridFightCurLevelExp, player.AFFCFLFIFPH, player.Gold, s.currencyWarsRevision))
return nil
})
}