mirror of
https://github.com/Walter-Sparrow/lunar-tear.git
synced 2026-07-02 13:53:41 +03:00
226 lines
8.2 KiB
Go
226 lines
8.2 KiB
Go
package masterdata
|
|
|
|
import (
|
|
"log"
|
|
"sort"
|
|
|
|
"lunar-tear/server/internal/utils"
|
|
)
|
|
|
|
type LabyrinthChapter struct {
|
|
EventQuestChapterId int32
|
|
LatestSeasonNumber int32
|
|
StageOrders []int32
|
|
}
|
|
|
|
type LabyrinthStageTier struct {
|
|
QuestMissionClearCount int32
|
|
Rewards []RewardItem
|
|
}
|
|
|
|
type LabyrinthSeasonMilestone struct {
|
|
HeadQuestId int32
|
|
HeadStageOrder int32
|
|
Rewards []RewardItem
|
|
}
|
|
|
|
type labyrinthStageKey struct {
|
|
ChapterId int32
|
|
StageOrder int32
|
|
}
|
|
|
|
type LabyrinthCatalog struct {
|
|
ChaptersByOrder []LabyrinthChapter
|
|
ClearRewardsByStage map[labyrinthStageKey][]RewardItem
|
|
AccumTiersByStage map[labyrinthStageKey][]LabyrinthStageTier
|
|
SeasonMilestonesByChapter map[int32][]LabyrinthSeasonMilestone
|
|
}
|
|
|
|
func (c *LabyrinthCatalog) StageClearReward(chapterId, stageOrder int32) []RewardItem {
|
|
return c.ClearRewardsByStage[labyrinthStageKey{chapterId, stageOrder}]
|
|
}
|
|
|
|
func (c *LabyrinthCatalog) CollectAccumulationRewards(chapterId, stageOrder, oldCount, targetCount int32) ([]RewardItem, int32) {
|
|
var items []RewardItem
|
|
highest := int32(0)
|
|
for _, t := range c.AccumTiersByStage[labyrinthStageKey{chapterId, stageOrder}] {
|
|
if t.QuestMissionClearCount > oldCount && t.QuestMissionClearCount <= targetCount {
|
|
items = append(items, t.Rewards...)
|
|
if t.QuestMissionClearCount > highest {
|
|
highest = t.QuestMissionClearCount
|
|
}
|
|
}
|
|
}
|
|
return items, highest
|
|
}
|
|
|
|
func (c *LabyrinthCatalog) SeasonMilestones(chapterId int32) []LabyrinthSeasonMilestone {
|
|
return c.SeasonMilestonesByChapter[chapterId]
|
|
}
|
|
|
|
func LoadLabyrinthCatalog() *LabyrinthCatalog {
|
|
seasonRows, err := utils.ReadTable[EntityMEventQuestLabyrinthSeason]("m_event_quest_labyrinth_season")
|
|
if err != nil {
|
|
log.Printf("[labyrinth] m_event_quest_labyrinth_season unavailable, labyrinth disabled: %v", err)
|
|
return &LabyrinthCatalog{}
|
|
}
|
|
stageRows, err := utils.ReadTable[EntityMEventQuestLabyrinthStage]("m_event_quest_labyrinth_stage")
|
|
if err != nil {
|
|
log.Printf("[labyrinth] m_event_quest_labyrinth_stage unavailable, labyrinth disabled: %v", err)
|
|
return &LabyrinthCatalog{}
|
|
}
|
|
|
|
// chapterId -> highest SeasonNumber
|
|
latestSeason := make(map[int32]int32)
|
|
for _, r := range seasonRows {
|
|
if r.SeasonNumber > latestSeason[r.EventQuestChapterId] {
|
|
latestSeason[r.EventQuestChapterId] = r.SeasonNumber
|
|
}
|
|
}
|
|
// chapterId -> stage orders
|
|
stagesByChapter := make(map[int32][]int32)
|
|
for _, r := range stageRows {
|
|
stagesByChapter[r.EventQuestChapterId] = append(stagesByChapter[r.EventQuestChapterId], r.StageOrder)
|
|
}
|
|
|
|
chapters := make([]LabyrinthChapter, 0, len(latestSeason))
|
|
for chapterId, season := range latestSeason {
|
|
stages := stagesByChapter[chapterId]
|
|
sort.Slice(stages, func(i, j int) bool { return stages[i] < stages[j] })
|
|
chapters = append(chapters, LabyrinthChapter{
|
|
EventQuestChapterId: chapterId,
|
|
LatestSeasonNumber: season,
|
|
StageOrders: stages,
|
|
})
|
|
}
|
|
sort.Slice(chapters, func(i, j int) bool {
|
|
return chapters[i].EventQuestChapterId < chapters[j].EventQuestChapterId
|
|
})
|
|
|
|
clearRewards, accumTiers, seasonMilestones := loadLabyrinthRewards(seasonRows, stageRows)
|
|
|
|
log.Printf("labyrinth catalog loaded: %d chapters, %d stages with clear rewards, %d with accumulation rewards, %d chapters with season rewards",
|
|
len(chapters), len(clearRewards), len(accumTiers), len(seasonMilestones))
|
|
return &LabyrinthCatalog{
|
|
ChaptersByOrder: chapters,
|
|
ClearRewardsByStage: clearRewards,
|
|
AccumTiersByStage: accumTiers,
|
|
SeasonMilestonesByChapter: seasonMilestones,
|
|
}
|
|
}
|
|
|
|
func loadLabyrinthRewards(seasonRows []EntityMEventQuestLabyrinthSeason, stageRows []EntityMEventQuestLabyrinthStage) (
|
|
clearRewards map[labyrinthStageKey][]RewardItem,
|
|
accumTiers map[labyrinthStageKey][]LabyrinthStageTier,
|
|
seasonMilestones map[int32][]LabyrinthSeasonMilestone,
|
|
) {
|
|
rewardGroupRows, err := utils.ReadTable[EntityMEventQuestLabyrinthRewardGroup]("m_event_quest_labyrinth_reward_group")
|
|
if err != nil {
|
|
log.Printf("[labyrinth] m_event_quest_labyrinth_reward_group unavailable, rewards disabled: %v", err)
|
|
return nil, nil, nil
|
|
}
|
|
|
|
// reward group id -> reward items
|
|
itemsByRewardGroup := make(map[int32][]RewardItem)
|
|
for _, r := range rewardGroupRows {
|
|
itemsByRewardGroup[r.EventQuestLabyrinthRewardGroupId] = append(itemsByRewardGroup[r.EventQuestLabyrinthRewardGroupId], RewardItem{
|
|
PossessionType: r.PossessionType,
|
|
PossessionId: r.PossessionId,
|
|
Count: r.Count,
|
|
})
|
|
}
|
|
|
|
// per-stage one-time clear reward
|
|
clearRewards = make(map[labyrinthStageKey][]RewardItem)
|
|
for _, r := range stageRows {
|
|
if r.StageClearRewardGroupId == 0 {
|
|
continue
|
|
}
|
|
if items := itemsByRewardGroup[r.StageClearRewardGroupId]; len(items) > 0 {
|
|
clearRewards[labyrinthStageKey{r.EventQuestChapterId, r.StageOrder}] = items
|
|
}
|
|
}
|
|
|
|
if accumGroupRows, err := utils.ReadTable[EntityMEventQuestLabyrinthStageAccumulationRewardGroup]("m_event_quest_labyrinth_stage_accumulation_reward_group"); err != nil {
|
|
log.Printf("[labyrinth] m_event_quest_labyrinth_stage_accumulation_reward_group unavailable, accumulation rewards disabled: %v", err)
|
|
} else {
|
|
// accumulation group id -> tiers (threshold + resolved reward items)
|
|
tiersByGroup := make(map[int32][]LabyrinthStageTier)
|
|
for _, r := range accumGroupRows {
|
|
tiersByGroup[r.EventQuestLabyrinthStageAccumulationRewardGroupId] = append(tiersByGroup[r.EventQuestLabyrinthStageAccumulationRewardGroupId], LabyrinthStageTier{
|
|
QuestMissionClearCount: r.QuestMissionClearCount,
|
|
Rewards: itemsByRewardGroup[r.EventQuestLabyrinthRewardGroupId],
|
|
})
|
|
}
|
|
accumTiers = make(map[labyrinthStageKey][]LabyrinthStageTier)
|
|
for _, r := range stageRows {
|
|
if r.StageAccumulationRewardGroupId == 0 {
|
|
continue
|
|
}
|
|
tiers := tiersByGroup[r.StageAccumulationRewardGroupId]
|
|
sort.Slice(tiers, func(i, j int) bool {
|
|
return tiers[i].QuestMissionClearCount < tiers[j].QuestMissionClearCount
|
|
})
|
|
accumTiers[labyrinthStageKey{r.EventQuestChapterId, r.StageOrder}] = tiers
|
|
}
|
|
}
|
|
|
|
// per-chapter season-reward milestones
|
|
if seasonRewardRows, err := utils.ReadTable[EntityMEventQuestLabyrinthSeasonRewardGroup]("m_event_quest_labyrinth_season_reward_group"); err != nil {
|
|
log.Printf("[labyrinth] m_event_quest_labyrinth_season_reward_group unavailable, season rewards disabled: %v", err)
|
|
} else {
|
|
seasonMilestones = buildLabyrinthSeasonMilestones(seasonRows, seasonRewardRows, itemsByRewardGroup)
|
|
}
|
|
|
|
return clearRewards, accumTiers, seasonMilestones
|
|
}
|
|
|
|
func buildLabyrinthSeasonMilestones(
|
|
seasonRows []EntityMEventQuestLabyrinthSeason,
|
|
seasonRewardRows []EntityMEventQuestLabyrinthSeasonRewardGroup,
|
|
itemsByRewardGroup map[int32][]RewardItem,
|
|
) map[int32][]LabyrinthSeasonMilestone {
|
|
// chapter -> SeasonRewardGroupId (all seasons of a chapter share one)
|
|
groupByChapter := make(map[int32]int32)
|
|
for _, r := range seasonRows {
|
|
groupByChapter[r.EventQuestChapterId] = r.SeasonRewardGroupId
|
|
}
|
|
// SeasonRewardGroupId -> its rows, in table order
|
|
rowsByGroup := make(map[int32][]EntityMEventQuestLabyrinthSeasonRewardGroup)
|
|
for _, r := range seasonRewardRows {
|
|
rowsByGroup[r.EventQuestLabyrinthSeasonRewardGroupId] = append(rowsByGroup[r.EventQuestLabyrinthSeasonRewardGroupId], r)
|
|
}
|
|
|
|
milestones := make(map[int32][]LabyrinthSeasonMilestone)
|
|
for chapterId, seasonGroupId := range groupByChapter {
|
|
rows := rowsByGroup[seasonGroupId]
|
|
if len(rows) == 0 {
|
|
continue
|
|
}
|
|
// rank distinct reward-group ids ascending -> 1-based head stage order
|
|
stageByRewardGroup := make(map[int32]int32)
|
|
var distinct []int32
|
|
for _, r := range rows {
|
|
if _, seen := stageByRewardGroup[r.EventQuestLabyrinthRewardGroupId]; !seen {
|
|
stageByRewardGroup[r.EventQuestLabyrinthRewardGroupId] = 0
|
|
distinct = append(distinct, r.EventQuestLabyrinthRewardGroupId)
|
|
}
|
|
}
|
|
sort.Slice(distinct, func(i, j int) bool { return distinct[i] < distinct[j] })
|
|
for i, gid := range distinct {
|
|
stageByRewardGroup[gid] = int32(i + 1)
|
|
}
|
|
|
|
list := make([]LabyrinthSeasonMilestone, 0, len(rows))
|
|
for _, r := range rows {
|
|
list = append(list, LabyrinthSeasonMilestone{
|
|
HeadQuestId: r.HeadQuestId,
|
|
HeadStageOrder: stageByRewardGroup[r.EventQuestLabyrinthRewardGroupId],
|
|
Rewards: itemsByRewardGroup[r.EventQuestLabyrinthRewardGroupId],
|
|
})
|
|
}
|
|
milestones[chapterId] = list
|
|
}
|
|
return milestones
|
|
}
|