From c84fe2a8a44166ac62637770ff47c9ea7b5e1a90 Mon Sep 17 00:00:00 2001 From: CounterFire2023 <136581895+CounterFire2023@users.noreply.github.com> Date: Tue, 26 Mar 2024 14:43:51 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=8E=A2=E7=B4=A2=E6=97=B6,?= =?UTF-8?q?=20=E5=A5=96=E5=8A=B1=E7=9A=84=E7=94=9F=E6=88=90=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- configs/game.json | 0 docs/uaw.md | 14 ++++-- src/common/Constants.ts | 11 +++++ src/controllers/chest.controller.ts | 25 +---------- src/controllers/game.controller.ts | 70 +++++++++++++++++++---------- src/models/ActivityGame.ts | 4 ++ src/services/game.svr.ts | 55 +++++++++++++++++++++++ 7 files changed, 128 insertions(+), 51 deletions(-) create mode 100644 configs/game.json create mode 100644 src/services/game.svr.ts diff --git a/configs/game.json b/configs/game.json new file mode 100644 index 0000000..e69de29 diff --git a/docs/uaw.md b/docs/uaw.md index 8d4b198..871805e 100644 --- a/docs/uaw.md +++ b/docs/uaw.md @@ -403,10 +403,16 @@ body: ```js { score: 20, //获得积分数量 - chest: [{ - id: '1112323131', // 获得宝箱id - level: 1, //宝箱品级 - }] + chest: [{ // 结构同 18.宝箱列表 + id: 1, // 箱子id + stat: 0, // 0: 锁定, 1: 正常 + shareCode: '箱子的分享码', + level: 1, // 箱子品级 + maxBonus: 10, // 最大可助力数量 + scoreInit: 5, // 初始可获得积分 + scoreBonus: 10, // 助力增加的分数 + bonusCount: 2, // 已助力次数 + }] } ``` diff --git a/src/common/Constants.ts b/src/common/Constants.ts index b133fa0..ec0ae7c 100644 --- a/src/common/Constants.ts +++ b/src/common/Constants.ts @@ -16,3 +16,14 @@ export const CONFIRM_MAIL_HTML = ` ` // 是否需要手动开启游戏 export const MANUAL_OPEN_GAME = true + +// 每一步能获得的最小分数 +export const STEP_SCORE_MIN = 1 +// 每一步能获得的最大分数 +export const STEP_SCORE_MAX = 5 +// 每一步能获得的宝箱的概率 +export const STEP_CHEST_RATE = 0.1 +// 宝箱各等级的概率 +export const STEP_CHEST_LEVEL = [70, 85, 95, 100] +// 低保步数 +export const RESET_STEP = 10 diff --git a/src/controllers/chest.controller.ts b/src/controllers/chest.controller.ts index 9a6a027..85c4898 100644 --- a/src/controllers/chest.controller.ts +++ b/src/controllers/chest.controller.ts @@ -6,30 +6,7 @@ import { rankKey, rankLevel, updateRankScore } from 'services/rank.svr' import { formatDate } from 'zutils/utils/date.util' import { ScoreRecord } from 'models/ScoreRecord' import { ChestRecord } from 'models/chain/ChestRecord' -const chestCfg = require('../../configs/chest.json') -const chestLevelMap = new Map() - -for (let cfg of chestCfg.chests) { - chestLevelMap.set(cfg.level, cfg) -} - -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.scoreMax - cfg.scoreMin + 1) + cfg.scoreMin) - let chest = new ActivityChest({ - user: uid, - activity: activity, - level: level, - maxBounsCount: cfg.maxBounsCount, - bounsCfg: cfg.bounsCfg, - scoreInit, - status, - }) - return chest -} +import { generateNewChest } from 'services/game.svr' /** * 宝箱相关接口 diff --git a/src/controllers/game.controller.ts b/src/controllers/game.controller.ts index 9b6ba06..6a46eac 100644 --- a/src/controllers/game.controller.ts +++ b/src/controllers/game.controller.ts @@ -1,11 +1,14 @@ -import { MANUAL_OPEN_GAME } from 'common/Constants' +import { MANUAL_OPEN_GAME, RESET_STEP } from 'common/Constants' import { ActivityGame } from 'models/ActivityGame' import { DAILY_SIGN, SIGN_TOTAL, TicketRecord, USE_TICKET } from 'models/TicketRecord' import { queryCheckInList } from 'services/chain.svr' import { checkInToday, seqSignCfg, seqSignScore, totalSignCfg, totalSignScore } from 'services/sign.svr' -import { ZError, SyncLocker, ZRedisClient, BaseController, ROLE_ANON, role, router } from 'zutils' +import { ZError, SyncLocker, BaseController, router } from 'zutils' import { formatDate } from 'zutils/utils/date.util' -const chestCfg = require('../../configs/chest.json') +import { mongoose } from '@typegoose/typegoose' +import { generateChestLevel, generateNewChest, generateStepReward } from 'services/game.svr' +import { ChestStatusEnum } from 'models/ActivityChest' + /** * 探索游戏相关接口 */ @@ -193,27 +196,48 @@ class GameController extends BaseController { throw new ZError(11, 'invalid step') } step = parseInt(step) + const session = await mongoose.startSession() + session.startTransaction() + try { + const record = await ActivityGame.insertOrUpdate({ user: user.id, activity: user.activity }, {}).session(session) + if (MANUAL_OPEN_GAME && record.status === 0) { + throw new ZError(12, 'map not open') + } + if (record.tickets < step) { + throw new ZError(13, 'insufficient tickets') + } + record.tickets -= step + const ticketRecord = new TicketRecord({ + user: user.id, + activity: user.activity, + type: USE_TICKET, + data: {}, + score: -step, + }) + let { score, chests } = generateStepReward(user.id, user.activity, step) + if (chests.length > 0) { + record.maxNoChestCount = 0 + } else { + record.maxNoChestCount += step + if (record.maxNoChestCount >= RESET_STEP) { + record.maxNoChestCount = 0 + const level = generateChestLevel() + chests.push(generateNewChest(user.id, user.activity, level, ChestStatusEnum.NORMAL)) + } + } + for (let chest of chests) { + await chest.save({ session }) + } + await ticketRecord.save({ session }) + await record.save() + await session.commitTransaction() - const record = await ActivityGame.insertOrUpdate({ user: user.id, activity: user.activity }, {}) - if (MANUAL_OPEN_GAME && record.status === 0) { - throw new ZError(12, 'map not open') + return { score, chests: chests.map(chest => chest.toJson()) } + } catch (e) { + session.abortTransaction() + throw e + } finally { + session.endSession() } - if (record.tickets < step) { - throw new ZError(13, 'insufficient tickets') - } - record.tickets -= step - // TODO:: 生成奖励, 存入data, 并返回 - const ticketRecord = new TicketRecord({ - user: user.id, - activity: user.activity, - type: USE_TICKET, - data: {}, - score: -step, - }) - await ticketRecord.save() - await record.save() - let result = [] - - return result } } diff --git a/src/models/ActivityGame.ts b/src/models/ActivityGame.ts index 433a9c0..f76fccb 100644 --- a/src/models/ActivityGame.ts +++ b/src/models/ActivityGame.ts @@ -27,6 +27,10 @@ class ActivityGameClass extends BaseModule { @prop() public lastSignDay: string + // 最大宝箱无宝箱步数 + @prop() + public maxNoChestCount: number + public toJson() { return { // @ts-ignore diff --git a/src/services/game.svr.ts b/src/services/game.svr.ts new file mode 100644 index 0000000..669d6dc --- /dev/null +++ b/src/services/game.svr.ts @@ -0,0 +1,55 @@ +import { STEP_CHEST_LEVEL, STEP_CHEST_RATE, STEP_SCORE_MAX, STEP_SCORE_MIN } from 'common/Constants' +import { ActivityChest, ChestStatusEnum } from 'models/ActivityChest' +import { ZError } from 'zutils' + +const chestCfg = require('../../configs/chest.json') +const chestLevelMap = new Map() + +for (let cfg of chestCfg.chests) { + chestLevelMap.set(cfg.level, cfg) +} + +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.scoreMax - cfg.scoreMin + 1) + cfg.scoreMin) + let chest = new ActivityChest({ + user: uid, + activity: activity, + level: level, + maxBounsCount: cfg.maxBounsCount, + bounsCfg: cfg.bounsCfg, + 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 +} + +export const generateStepReward = (uid: string, activity: string, step: number) => { + let score = 0 + let chests = [] + for (let i = 0; i < step; i++) { + score += Math.floor(Math.random() * (STEP_SCORE_MAX - STEP_SCORE_MIN + 1) + STEP_SCORE_MIN) + if (Math.random() < STEP_CHEST_RATE) { + let randomLevel = generateChestLevel() + let chest = generateNewChest(uid, activity, randomLevel, ChestStatusEnum.NORMAL) + chests.push(chest) + } + } + return { score, chests } +}