Files
YumeMichi 750c2cf3d0 Implement secretbox handlers and align gacha behavior
- Add secretbox API schemas, handlers, and routes for all/showDetail/pon/multi
- Load secretbox server data through the shared serverdata loader
- Fix rarity mapping and pool rules for SR/SSR/UR special boxes
- Implement thanks festival pool behavior, including UR guarantee and SSR/UR-only rates
- Correct animation-related fields such as is_hit and lowest_rarity, and add rare UR promotion animation

Signed-off-by: Sean Du <do4suki@gmail.com>
2026-06-05 21:57:04 +08:00

105 lines
2.7 KiB
Go

package secretbox
import (
"fmt"
unitmodel "honoka-chan/internal/model/unit"
secretboxapischema "honoka-chan/internal/schema/api/secretbox"
"honoka-chan/internal/session"
honokautils "honoka-chan/internal/utils"
"honoka-chan/pkg/db"
"sort"
"time"
)
const secretBoxDataFile = "secretbox_data.json"
func loadSecretBoxAllData() (secretboxapischema.AllResp, error) {
data, err := honokautils.LoadServerData[secretboxapischema.AllData](secretBoxDataFile)
if err != nil {
return secretboxapischema.AllResp{}, err
}
return secretboxapischema.AllResp{
Result: data,
Status: 200,
CommandNum: false,
TimeStamp: time.Now().Unix(),
}, nil
}
func findSecretBoxPage(config secretboxapischema.AllResp, secretBoxID int) (int, secretboxapischema.SecretBoxPage, error) {
for _, category := range config.Result.MemberCategoryList {
for _, page := range category.PageList {
if page.SecretBoxInfo.SecretBoxID == secretBoxID {
return category.MemberCategory, page, nil
}
}
}
return 0, secretboxapischema.SecretBoxPage{}, fmt.Errorf("secretbox not found: %d", secretBoxID)
}
func findSecretBoxCost(page secretboxapischema.SecretBoxPage, costID int) (secretboxapischema.SecretBoxButton, secretboxapischema.SecretBoxCost, error) {
for _, button := range page.ButtonList {
for _, cost := range button.CostList {
if cost.ID == costID {
return button, cost, nil
}
}
}
return secretboxapischema.SecretBoxButton{}, secretboxapischema.SecretBoxCost{}, fmt.Errorf("secretbox cost not found: %d", costID)
}
func queryUnitIDs(ss *session.Session, memberCategory int, supportOnly bool, rarity int) ([]int, error) {
var (
rows []struct {
UnitID int `xorm:"unit_id"`
}
err error
)
sql := `
SELECT u.unit_id
FROM unit_m u
LEFT JOIN unit_type_m ut ON ut.unit_type_id = u.unit_type_id
WHERE u.rarity = ?`
args := []any{rarity}
if supportOnly {
sql += ` AND u.disable_rank_up != 0`
} else if memberCategory >= 0 {
sql += ` AND ut.member_category = ?`
args = append(args, memberCategory)
}
if ss != nil {
err = ss.MainEng.SQL(sql, args...).Find(&rows)
} else {
err = db.MainEng.SQL(sql, args...).Find(&rows)
}
if err != nil {
return nil, err
}
result := make([]int, 0, len(rows))
for _, row := range rows {
result = append(result, row.UnitID)
}
sort.Ints(result)
return result, nil
}
func getUserUnitByUnitID(ss *session.Session, unitID int) (unitmodel.UnitDataMap, error) {
unitData := unitmodel.UnitDataMap{}
has, err := ss.GetBasicUnitInfo().
Where("a.user_id = ?", ss.UserID).
Where("a.unit_id = ?", unitID).
Get(&unitData)
if err != nil {
return unitmodel.UnitDataMap{}, err
}
if !has {
return unitmodel.UnitDataMap{}, fmt.Errorf("user %d does not own unit %d", ss.UserID, unitID)
}
return unitData, nil
}