服务端(Go): - GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面 - GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新 - 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新) - 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍 - 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0) - 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算 启动器(Python/JS): - 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭 - GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐) - 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
61 lines
2.5 KiB
Go
61 lines
2.5 KiB
Go
package dnfbridge
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"time"
|
|
|
|
"longheng.io/server/internal/modules/dnf/alignedcmd"
|
|
"longheng.io/server/internal/modules/dnf/inventory"
|
|
dnfpvp "longheng.io/server/internal/modules/dnf/pvp"
|
|
repo "longheng.io/server/internal/modules/dnf/repository"
|
|
)
|
|
|
|
func (s *Service) grantCurrentPVPTotalTargets(ctx context.Context, repos repo.Group, catalog *dnfpvp.Catalog, session *gameSession) (dnfpvp.TotalRewards, error) {
|
|
place := func(record repo.InventoryRecord, id, count int64, now time.Time) (repo.InventoryRecord, error) {
|
|
items, err := s.currentPVFItemCatalog()
|
|
if err != nil {
|
|
return repo.InventoryRecord{}, err
|
|
}
|
|
definition, err := items.ResolveItem(uint32(id))
|
|
if err != nil {
|
|
return repo.InventoryRecord{}, err
|
|
}
|
|
definition, err = currentPVFItemDefinitionForGrantAt(definition, now)
|
|
if err != nil {
|
|
return repo.InventoryRecord{}, err
|
|
}
|
|
if definition.Kind != dungeonDropItemStackable {
|
|
return repo.InventoryRecord{}, fmt.Errorf("total target item %d is not stackable", id)
|
|
}
|
|
result, err := inventory.PlaceStackableReward(record, alignedcmd.MagicBoxRewardItem{
|
|
ItemID: id, Kind: string(definition.Kind), StackLimit: definition.StackLimit,
|
|
SlotStart: definition.SlotStart, SlotEnd: definition.SlotEnd, PVFPath: definition.PVFPath,
|
|
ExpireAt: definition.ExpirationDate, UsablePeriodDays: definition.UsablePeriodDays,
|
|
}, count)
|
|
if errors.Is(err, inventory.ErrRandomRewardInventoryFull) {
|
|
return repo.InventoryRecord{}, dnfpvp.ErrTotalRewardInventoryFull
|
|
}
|
|
if err != nil {
|
|
return repo.InventoryRecord{}, fmt.Errorf("total target reward item=%d: %w", id, err)
|
|
}
|
|
return result, err
|
|
}
|
|
result, err := dnfpvp.GrantTotalTargets(ctx, repos, catalog, session.accountID, strconv.Itoa(int(session.selectedCharacterID)), s.gameplayNow(), place)
|
|
if err == nil && (len(result.Granted) > 0 || len(result.Pending) > 0) {
|
|
s.logGameEvent(session, "game-pvp-total-target-rewards", "granted", result.Granted, "pending_inventory_space", result.Pending)
|
|
}
|
|
return result, err
|
|
}
|
|
|
|
func (s *Service) sendCurrentPVPTotalRewards(session *gameSession, rewards dnfpvp.TotalRewards) error {
|
|
entries := []currentItemListEntry{currentPVPEmblemWalletEntry(statU32(rewards.Character, dnfpvp.EmblemsKey, 0))}
|
|
for slot, stack := range rewards.Items {
|
|
entries = append(entries, currentItemListEntryFromStack(0, slot, stack))
|
|
}
|
|
sortCurrentItemListEntries(entries)
|
|
return s.sendGameUpperRawClass(session, 14, buildCurrentItemUpdateBody(0, entries), 0)
|
|
}
|