Files
2026-10-28 18:54:43 +07:00

234 lines
6.7 KiB
Go

package sdkserver
import (
"fmt"
"gac-hkrpg-go/internal/common"
pb "gac-hkrpg-go/protocol/proto"
"google.golang.org/protobuf/proto"
"net/http"
"sort"
"strconv"
"strings"
)
func apiCurrencyWarsCommand(w http.ResponseWriter, command string) {
fail := func(err error) { writeJSON(w, map[string]any{"success": false, "output": err.Error()}) }
parts := strings.Fields(command)
usage := "Usage: /cw status | /cw list role|equip|orb|consumable|forge | /cw gold <total> | /cw hp <total> | /cw exp <gain> | /cw equip|orb|consumable|forge <itemID> [count] | /cw role <roleID> <star> [count]. Changes apply in CW Preparation."
if len(parts) < 2 {
fail(fmt.Errorf("%s", usage))
return
}
catalog, err := common.LoadCurrencyWarsCatalog()
if err != nil {
fail(err)
return
}
if strings.EqualFold(parts[1], "help") {
writeJSON(w, map[string]any{"success": true, "output": usage})
return
}
if strings.EqualFold(parts[1], "list") {
if len(parts) != 3 {
fail(fmt.Errorf("%s", usage))
return
}
var lines []string
switch strings.ToLower(parts[2]) {
case "role":
for _, v := range catalog.CapturedVariants {
lines = append(lines, fmt.Sprintf("role=%d star=%d avatar=%d rarity=%d", v.Config.ID, v.Star, v.Config.AvatarID, v.Config.Rarity))
}
case "equip":
rows, e := common.LoadCurrencyWarsEquipment(catalog)
if e != nil {
fail(e)
return
}
ids := make([]uint32, 0, len(rows))
for id := range rows {
ids = append(ids, id)
}
sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] })
for _, id := range ids {
v := rows[id]
lines = append(lines, fmt.Sprintf("equip=%d type=%d category=%d ability=%s", id, v.EquipType, v.EquipCategory, v.AbilityName))
}
case "orb", "consumable", "forge":
rows, e := common.LoadCurrencyWarsRewards(catalog)
if e != nil {
fail(e)
return
}
ids := []uint32{}
kind := strings.ToLower(parts[2])
switch kind {
case "orb":
for id := range rows.Orbs {
ids = append(ids, id)
}
case "consumable":
for id := range rows.Consumables {
ids = append(ids, id)
}
case "forge":
for id := range rows.Forges {
ids = append(ids, id)
}
}
sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] })
for _, id := range ids {
switch kind {
case "orb":
v := rows.Orbs[id]
lines = append(lines, fmt.Sprintf("orb=%d type=%d bonus=%d", id, v.Type, v.Bonus))
case "consumable":
v := rows.Consumables[id]
lines = append(lines, fmt.Sprintf("consumable=%d rule=%d stack=%t", id, v.ConsumableRule, v.IfStack))
case "forge":
v := rows.Forges[id]
lines = append(lines, fmt.Sprintf("forge=%d function=%d choices=%d parameters=%v", id, v.FuncType, v.EquipNum, v.ParamList))
}
}
default:
fail(fmt.Errorf("available catalogs: role, equip, orb, consumable, forge"))
return
}
writeJSON(w, map[string]any{"success": true, "output": strings.Join(lines, "\n")})
return
}
cfg, err := common.LoadRuntimeConfig()
if err != nil {
fail(err)
return
}
snapshot, err := common.ReadCurrencyWarsSnapshot(cfg.PlayerUID, catalog.ClientVersion, catalog.Provenance.GameAssemblySHA256)
if err != nil {
fail(err)
return
}
if snapshot == nil {
fail(fmt.Errorf("no saved CW run"))
return
}
var data pb.GridFightGetDataScRsp
if err = proto.Unmarshal(snapshot.WireData, &data); err != nil {
fail(err)
return
}
run := data.DHFOFLFCLAH
if run == nil {
fail(fmt.Errorf("no active CW run"))
return
}
var player *pb.NIHNGPKHEPC
for _, c := range run.NAGDJGMMCBE {
if v := c.GetFAOCFBOFCJP(); v != nil {
player = v
}
}
if player == nil {
fail(fmt.Errorf("CW player state missing"))
return
}
field := strings.ToLower(parts[1])
if field == "status" && len(parts) == 2 {
writeJSON(w, map[string]any{"success": true, "output": fmt.Sprintf("CW run=%d revision=%d gold=%d hp=%d/%d level=%d", run.UniqueId, snapshot.Revision, player.Gold, player.GridFightLineupHp, player.PPKKHHNEOHB, player.EHNJDIDABHD)})
return
}
if len(parts) < 3 || len(parts) > 5 || (field != "gold" && field != "hp" && field != "exp" && field != "equip" && field != "role" && field != "orb" && field != "consumable" && field != "forge") {
fail(fmt.Errorf("%s", usage))
return
}
value, err := strconv.ParseUint(parts[2], 10, 32)
if err != nil {
fail(fmt.Errorf("value must be a nonnegative uint32"))
return
}
if field == "hp" && (value == 0 || value > uint64(player.PPKKHHNEOHB)) {
fail(fmt.Errorf("HP must be 1..%d", player.PPKKHHNEOHB))
return
}
quantity, star := uint32(1), uint32(0)
parse := func(text string) (uint32, error) {
v, e := strconv.ParseUint(text, 10, 32)
if e != nil || v == 0 {
return 0, fmt.Errorf("star/count must be a positive uint32")
}
return uint32(v), nil
}
switch field {
case "role":
if len(parts) < 4 {
fail(fmt.Errorf("%s", usage))
return
}
star, err = parse(parts[3])
if err == nil && len(parts) == 5 {
quantity, err = parse(parts[4])
}
if err == nil {
_, err = catalog.CapturedRoleVariant(uint32(value), star)
}
case "orb", "consumable", "forge":
if len(parts) > 4 {
fail(fmt.Errorf("%s", usage))
return
}
if len(parts) == 4 {
quantity, err = parse(parts[3])
}
if err == nil {
var rows *common.CurrencyWarsRewards
rows, err = common.LoadCurrencyWarsRewards(catalog)
if err == nil {
if field == "forge" {
if _, ok := rows.Forges[uint32(value)]; !ok {
err = fmt.Errorf("unknown forge %d", value)
}
} else if field == "orb" {
if _, ok := rows.Orbs[uint32(value)]; !ok {
err = fmt.Errorf("unknown Orb %d", value)
}
} else {
if _, ok := rows.Consumables[uint32(value)]; !ok {
err = fmt.Errorf("unknown consumable %d", value)
}
}
}
}
case "equip":
if len(parts) > 4 {
fail(fmt.Errorf("%s", usage))
return
}
if len(parts) == 4 {
quantity, err = parse(parts[3])
}
if err == nil {
var rows map[uint32]common.CurrencyWarsEquipment
rows, err = common.LoadCurrencyWarsEquipment(catalog)
if err == nil {
if _, ok := rows[uint32(value)]; !ok {
err = fmt.Errorf("equipment %d not captured; use /cw list equip", value)
}
}
}
default:
if len(parts) != 3 {
fail(fmt.Errorf("%s", usage))
return
}
}
if err != nil {
fail(err)
return
}
id, err := common.QueueCurrencyWarsGrant(cfg.PlayerUID, run.UniqueId, field, uint32(value), quantity, star)
if err != nil {
fail(err)
return
}
writeJSON(w, map[string]any{"success": true, "state": "queued", "request_id": id, "output": fmt.Sprintf("Queued CW %s=%d star=%d count=%d for run %d. Applies at the next heartbeat in Preparation; check CW_GM log for the applied result.", field, value, star, quantity, run.UniqueId)})
}