feat(server): add special loot and data-driven gameplay rules

Generate equipment loot atomically, grant random boxes and prevent repeat claims.
Read gacha pools, pity, products, tickets, missions, presets, chapter rewards
and inventory costs from GameData; extend both collaboration UR ticket pools.
Sync owned recipes, configure startup state and calendars in versioned seeds,
and validate unlock tickets and revival talents.
This commit is contained in:
2026-10-04 19:15:59 +08:00
parent 64454e71a3
commit 5b5a219dc2
86 changed files with 3577 additions and 646 deletions
+29 -6
View File
@@ -76,7 +76,7 @@ func (s *Service) grantPurchaseRewards(identity string, rewards []gamedata.Rewar
}
var exchanges []gamedata.Reward
for _, x := range grant.Exchanges {
if x.ExchangeItemType != 20 {
if !purchaseCurrency(x.ExchangeItemType) || x.ExchangeItemID != 0 {
return nil, fmt.Errorf("world: unsupported purchase costume exchange")
}
exchanges = append(exchanges, gamedata.Reward{Type: x.ExchangeItemType, ID: x.ExchangeItemID, Count: x.ExchangeCount})
@@ -113,14 +113,29 @@ func (s *Service) purchaseStoryPack(id int, initial bool) ([]byte, error) {
if _, owned := s.collection.Grant(identity); owned {
return []byte{}, nil
}
if !initial && pack.BuyPrice != 0 {
return nil, fmt.Errorf("%w: paid pack purchase type %d is unsupported", ErrInvalidRequest, pack.BuyType)
}
for _, reward := range buyRewards {
if reward.Type != 3 && reward.Type != 4 && reward.Type != 12 && reward.Type != 19 && reward.Type != 11 {
if !purchaseCurrency(reward.Type) && reward.Type != 19 && reward.Type != 11 {
return nil, fmt.Errorf("world: unsupported pack purchase reward type %d", reward.Type)
}
}
if !initial && pack.BuyPrice != 0 {
var err error
switch pack.BuyType {
case 2:
_, err = s.wallet.SpendJewelryOnce(identity+":price", pack.BuyPrice)
case 3:
_, err = s.wallet.SpendFreeJewelryOnce(identity+":price", pack.BuyPrice)
case 4:
_, err = s.wallet.SpendGoldOnce(identity+":price", pack.BuyPrice)
case 12:
_, err = s.wallet.SpendCatalystOnce(identity+":price", pack.BuyPrice)
default:
return nil, fmt.Errorf("%w: unsupported pack purchase currency%d", ErrInvalidRequest, pack.BuyType)
}
if err != nil {
return nil, err
}
}
items, err := s.grantPurchaseRewards(identity, buyRewards)
if err != nil {
return nil, err
@@ -133,7 +148,7 @@ func (s *Service) purchaseStoryPack(id int, initial bool) ([]byte, error) {
bundle = append(bundle, player.CollectionRewardBundle(s.collection, grant)...)
}
for _, reward := range buyRewards {
if reward.Type == 3 || reward.Type == 4 || reward.Type == 12 {
if purchaseCurrency(reward.Type) {
currency := wire.AppendVarint(wire.AppendVarint(nil, 3, reward.Type), 4, reward.Count)
bundle = wire.AppendBytes(bundle, 1, currency)
}
@@ -143,3 +158,11 @@ func (s *Service) purchaseStoryPack(id int, initial bool) ([]byte, error) {
}
return bundle, nil
}
func purchaseCurrency(typ uint64) bool {
switch typ {
case 2, 3, 4, 12, 20:
return true
}
return false
}