task-svr/src/services/game.svr.ts
2024-04-11 17:56:48 +08:00

116 lines
3.3 KiB
TypeScript

import { STEP_CHEST_RATE, STEP_SCORE_MAX, STEP_SCORE_MIN } from 'common/Constants'
import { ActivityChest, ActivityChestClass, ChestStatusEnum } from 'models/ActivityChest'
import { ZError, ZRedisClient } from 'zutils'
import { DocumentType } from '@typegoose/typegoose'
const chestCfg = require('../../configs/chest.json')
const chestBonusItems = require('../../configs/chest_bonus_item.json')
const chestLevelMap = new Map()
let STEP_CHEST_LEVEL = chestCfg.chests.map((cfg: any) => cfg.probability)
STEP_CHEST_LEVEL.sort((a: number, b: number) => a - b)
chestCfg.chests.forEach((cfg: any) => {
chestLevelMap.set(cfg.level, cfg)
})
const generateBounsCfg = (cfg: any) => {
let randoms = []
for (let i = 0; i < cfg.bounsCount; i++) {
randoms.push(Math.random())
}
let total = randoms.reduce((a: number, b: number) => a + b)
randoms = randoms.map((r: number) => r / total)
let ys = []
randoms.forEach((r: number) => {
let tmp = cfg.maxBounsScore * r
tmp = Math.min(1, Math.round(tmp))
ys.push(tmp)
})
ys.sort((a: number, b: number) => b - a)
return ys
}
export const generateNewChest = (uid: string, activity: string, level = 1, status = ChestStatusEnum.LOCKED) => {
let cfg = chestLevelMap.get(level)
if (!cfg) {
throw new ZError(11, 'chest cfg not found')
}
let scoreInit = Math.floor(Math.random() * (cfg.initScoreMax - cfg.initScoreMin + 1) + cfg.initScoreMin)
let chest = new ActivityChest({
user: uid,
activity: activity,
level: level,
maxBounsCount: cfg.maxBounsCount,
bounsCfg: generateBounsCfg(cfg),
scoreInit,
status,
})
return chest
}
export const generateChestLevel = function (): number {
const levelDefine = STEP_CHEST_LEVEL
let randomLevel = Math.floor(Math.random() * levelDefine[levelDefine.length - 1])
let level = 1
for (let i = 0; i < levelDefine.length; i++) {
if (randomLevel < levelDefine[i]) {
level = i + 1
break
}
}
return level
}
/**
* 生成步数奖励
* // TODO:: 增加白名单和特殊种类nft的奖励
* @param uid
* @param activity
* @param step
* @returns
*/
export const generateStepReward = (uid: string, activity: string, step: number) => {
let score = 0
let chests = []
for (let i = 0; i < step; i++) {
if (Math.random() < STEP_CHEST_RATE) {
let randomLevel = generateChestLevel()
let chest = generateNewChest(uid, activity, randomLevel, ChestStatusEnum.NORMAL)
chests.push(chest)
} else {
score += Math.floor(Math.random() * (STEP_SCORE_MAX - STEP_SCORE_MIN + 1) + STEP_SCORE_MIN)
}
}
return { score, chests }
}
export const generateChestBonus = async (chest: DocumentType<ActivityChestClass>) => {
let rewards = []
// 如果宝箱的助力用户数量小于最大助力次数, 则不生成奖励
if (chest.bonusUsers.length < chest.maxBounsCount) {
return []
}
let bonusItem
for (let i = 0; i < chestBonusItems.length; i++) {
let item = chestBonusItems[i]
if (Math.random() < item.probability / 100) {
bonusItem = item
break
}
}
if (!bonusItem) {
return []
}
const redisKey = `chest_bonus_${bonusItem.type}`
const itemId = await new ZRedisClient().spop(redisKey)
if (!itemId) {
return []
}
rewards.push({
id: itemId,
type: bonusItem.type,
name: bonusItem.name,
desc: bonusItem.desc,
amount: 1,
})
}