增加探索时, 奖励的生成配置

This commit is contained in:
CounterFire2023 2024-03-26 14:43:51 +08:00
parent 4e48150c1e
commit c84fe2a8a4
7 changed files with 128 additions and 51 deletions

0
configs/game.json Normal file
View File

View File

@ -403,10 +403,16 @@ body:
```js ```js
{ {
score: 20, //获得积分数量 score: 20, //获得积分数量
chest: [{ chest: [{ // 结构同 18.宝箱列表
id: '1112323131', // 获得宝箱id id: 1, // 箱子id
level: 1, //宝箱品级 stat: 0, // 0: 锁定, 1: 正常
}] shareCode: '箱子的分享码',
level: 1, // 箱子品级
maxBonus: 10, // 最大可助力数量
scoreInit: 5, // 初始可获得积分
scoreBonus: 10, // 助力增加的分数
bonusCount: 2, // 已助力次数
}]
} }
``` ```

View File

@ -16,3 +16,14 @@ export const CONFIRM_MAIL_HTML = `
` `
// 是否需要手动开启游戏 // 是否需要手动开启游戏
export const MANUAL_OPEN_GAME = true 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

View File

@ -6,30 +6,7 @@ import { rankKey, rankLevel, updateRankScore } from 'services/rank.svr'
import { formatDate } from 'zutils/utils/date.util' import { formatDate } from 'zutils/utils/date.util'
import { ScoreRecord } from 'models/ScoreRecord' import { ScoreRecord } from 'models/ScoreRecord'
import { ChestRecord } from 'models/chain/ChestRecord' import { ChestRecord } from 'models/chain/ChestRecord'
const chestCfg = require('../../configs/chest.json') import { generateNewChest } from 'services/game.svr'
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
}
/** /**
* *

View File

@ -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 { ActivityGame } from 'models/ActivityGame'
import { DAILY_SIGN, SIGN_TOTAL, TicketRecord, USE_TICKET } from 'models/TicketRecord' import { DAILY_SIGN, SIGN_TOTAL, TicketRecord, USE_TICKET } from 'models/TicketRecord'
import { queryCheckInList } from 'services/chain.svr' import { queryCheckInList } from 'services/chain.svr'
import { checkInToday, seqSignCfg, seqSignScore, totalSignCfg, totalSignScore } from 'services/sign.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' 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') throw new ZError(11, 'invalid step')
} }
step = parseInt(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 }, {}) return { score, chests: chests.map(chest => chest.toJson()) }
if (MANUAL_OPEN_GAME && record.status === 0) { } catch (e) {
throw new ZError(12, 'map not open') 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
} }
} }

View File

@ -27,6 +27,10 @@ class ActivityGameClass extends BaseModule {
@prop() @prop()
public lastSignDay: string public lastSignDay: string
// 最大宝箱无宝箱步数
@prop()
public maxNoChestCount: number
public toJson() { public toJson() {
return { return {
// @ts-ignore // @ts-ignore

55
src/services/game.svr.ts Normal file
View File

@ -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 }
}