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) => { 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, }) }