diff --git a/game-server/app/servers/activity/handler/sevenDaysHandler.ts b/game-server/app/servers/activity/handler/sevenDaysHandler.ts index 8ac47fb5a..a1f1ed628 100644 --- a/game-server/app/servers/activity/handler/sevenDaysHandler.ts +++ b/game-server/app/servers/activity/handler/sevenDaysHandler.ts @@ -1,12 +1,15 @@ import { Application, BackendSession } from 'pinus'; import { resResult } from '../../../pubUtils/util'; -import { STATUS, } from '../../../consts'; +import { STATUS, ACTIVITY_RESOURCES_TYPE } from '../../../consts'; import { getPlayerGrowthData } from '../../../services/growthService'; import { getPlayerDailyChallengesData } from '../../../services/dailyChallengesService'; import { GrowthItem } from '../../../domain/activityField/growthField'; -import { addItems, createHeroes } from '../../../services/rewardService'; +import { addItems, createHeroes, handleCost } from '../../../services/rewardService'; import { ActivityGrowthModel } from '../../../db/ActivityGrowth'; import { DailyItem } from '../../../domain/activityField/dailyChallengesField'; +import { getPlayerDailyGiftsData } from '../../../services/dailyGiftsService'; +import { DailyGiftItem } from '../../../domain/activityField/DailyGiftsField'; +import { ActivityDailyGiftsModel } from '../../../db/ActivityDailyGifts'; export default function (app: Application) { @@ -17,6 +20,8 @@ export class SevenDaysHandler { constructor(private app: Application) { } + /************************成长任务****************************/ + /** * @description 获取七天乐活动数据 * @param {{ activityId: number}} msg @@ -184,4 +189,79 @@ export class SevenDaysHandler { return resResult(STATUS.SUCCESS, { goods, addHeros }); } + + + /************************每日特惠礼包****************************/ + + /** + * @description 获取每日特惠礼包活动数据 + * @param {{ activityId: number}} msg + * @param {BackendSession} session + * @memberof SevenDaysHandler + */ + async getSevenDayDailyGiftsActivity(msg: { activityId: number }, session: BackendSession) { + const { activityId } = msg; + const roleId = session.get('roleId'); + const serverId = session.get('serverId'); + + let playerData = await getPlayerDailyGiftsData(activityId, serverId, roleId) + + if (!playerData) return resResult(STATUS.ACTIVITY_MISSING); + + return resResult(STATUS.SUCCESS, playerData); + } + + /** + * @description 购买每日特惠礼包 + * @param {{ activityId: number, dayIndex: number, cellIndex: number}} msg + * @param {BackendSession} session + * @memberof SevenDaysHandler + */ + async buyDailyGiftsCell(msg: { activityId: number, dayIndex: number, cellIndex: number }, session: BackendSession) { + const { activityId, dayIndex, cellIndex } = msg; + const roleId = session.get('roleId'); + const serverId = session.get('serverId'); + const sid = session.get('sid'); + const roleName = session.get('roleName'); + const funcs = session.get('funcs'); + + let playerData = await getPlayerDailyGiftsData(activityId, serverId, roleId) + if (!playerData) return resResult(STATUS.ACTIVITY_MISSING); + + let dailyItemData: DailyGiftItem = playerData.findDailyGiftsItem(dayIndex, cellIndex); + if (!dailyItemData) { + return resResult(STATUS.ACTIVITY_DATA_ERROR); + } + if (!dailyItemData.canBuy()) {//最大次数 + return resResult(STATUS.ACTIVITY_MAX_COUNT); + } + if (dayIndex > playerData.today()) {//还未开启 + return resResult(STATUS.ACTIVITY_UNOPENED); + } + + //货币是否足够 + let consumeData = dailyItemData.consumeRes(); + let consumeType = consumeData.type;//购买类型 + + if (consumeType == ACTIVITY_RESOURCES_TYPE.GOODS) {//物品表,元宝、金币、体力 + let result = await handleCost(roleId, sid, [{ id: consumeData.id, count: consumeData.count }]); + if (!result) return resResult(STATUS.ACTIVITY_RES_NOT_ENOUGH); + } else if (consumeType == ACTIVITY_RESOURCES_TYPE.RMB) {//RMB购买 + + } + + await ActivityDailyGiftsModel.buyRecord(activityId, roleId, dayIndex, cellIndex, 1); + let reward = dailyItemData.goodReward(); + let goods = await addItems(roleId, roleName, sid, reward); + let heroReward = dailyItemData.heroReward(); + let addHeros = []; + if (heroReward.length > 0) { + let heroResult = await createHeroes(roleId, roleName, sid, serverId, funcs, heroReward); + goods = goods.concat(heroResult.goods) + addHeros = addHeros.concat(heroResult.heroes); + } + + return resResult(STATUS.SUCCESS, { goods, addHeros }); + } + } diff --git a/game-server/app/services/dailyGiftsService.ts b/game-server/app/services/dailyGiftsService.ts new file mode 100644 index 000000000..d07b25799 --- /dev/null +++ b/game-server/app/services/dailyGiftsService.ts @@ -0,0 +1,24 @@ +import { ActivityModel, ActivityModelType } from '../db/Activity'; +import { ActivityDailyGiftsModel, ActivityDailyGiftsModelType } from '../db/ActivityDailyGifts'; +import { DailyGiftsData, DailyGiftItem } from '../domain/activityField/DailyGiftsField'; + + +/** + * 玩家玩家活动数据 + * + * @param {number} serverId 区Id + * @param {number} activityId 活动Id + * @param {string} roleId 角色Id + * + */ +export async function getPlayerDailyGiftsData(activityId: number, serverId: number, roleId: string) { + let activityData: ActivityModelType = await ActivityModel.findActivity(activityId, true); + let playerRecords: ActivityDailyGiftsModelType[] = await ActivityDailyGiftsModel.findData(activityId, roleId); + + let playerData = new DailyGiftsData(activityData); + playerData.setPlayerRecords(playerRecords); + + return playerData; +} + + diff --git a/shared/consts/constModules/activityConst.ts b/shared/consts/constModules/activityConst.ts index e7b281872..1aab015e1 100644 --- a/shared/consts/constModules/activityConst.ts +++ b/shared/consts/constModules/activityConst.ts @@ -8,4 +8,13 @@ export enum ACTIVITY_TYPE { SEVEN_DAYS = 1, // 七天乐活动 TASK_GROWTH = 2, // 成长任务活动 TASK_DAILY_CHALLENGES = 3, // 今日挑战活动 +} + +/** + * 活动资源类型(消耗品、奖励内容) + */ +export enum ACTIVITY_RESOURCES_TYPE { + HERO = 1, // 英雄表 + GOODS = 2, // 物品表 + RMB = 3, // RMB } \ No newline at end of file diff --git a/shared/consts/index.ts b/shared/consts/index.ts index 8c2c5143c..aaf78e7a7 100644 --- a/shared/consts/index.ts +++ b/shared/consts/index.ts @@ -1,4 +1,5 @@ export * from './constModules/abilityConst'; +export * from './constModules/activityConst'; export * from './constModules/battleConst'; export * from './constModules/calcuConst'; export * from './constModules/heroConst'; diff --git a/shared/consts/statusCode.ts b/shared/consts/statusCode.ts index e3d221e79..7f342bd5e 100644 --- a/shared/consts/statusCode.ts +++ b/shared/consts/statusCode.ts @@ -338,7 +338,10 @@ export const STATUS = { ACTIVITY_TASK_UNCOMPLETED: { code: 50002, simStr: '任务还未完成' }, ACTIVITY_NO_POINT: { code: 50003, simStr: '奖章不足' }, ACTIVITY_REWARDED: { code: 50004, simStr: '已经领取过' }, - ACTIVITY_TIME_ERROR: { code: 50004, simStr: '时间错误' }, + ACTIVITY_TIME_ERROR: { code: 50005, simStr: '时间错误' }, + ACTIVITY_MAX_COUNT: { code: 50006, simStr: '已经到最大次数' }, + ACTIVITY_UNOPENED: { code: 50007, simStr: '还未开启,不能购买' }, + ACTIVITY_RES_NOT_ENOUGH: { code: 50008, simStr: '资源不足' }, // GM后台相关状态 60000 - 69999 GM_ERR_PASSWORD: { code: 60001, simStr: '账号或密码错误' }, GM_MISS_API: { code: 60002, simStr: '未找到该接口' }, diff --git a/shared/db/ActivityDailyGifts.ts b/shared/db/ActivityDailyGifts.ts new file mode 100644 index 000000000..3f2a6fb94 --- /dev/null +++ b/shared/db/ActivityDailyGifts.ts @@ -0,0 +1,56 @@ +import BaseModel from './BaseModel'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; + +/** + * 活动系统 - 每日活动 + * 1.每日特惠礼包(游戏币) +*/ +@index({ roleId: 1 }) + +export default class ActivityDailyGifts extends BaseModel { + @prop({ required: true }) + acvitityId: number; // 活动Id + @prop({ required: true }) + roleId: string; // 用户Id + @prop({ required: true }) + dayIndex: number; // 第几天 + @prop({ required: true }) + cellIndex: number; // 第几天的第几个奖励 + @prop({ required: true }) + buyCount: number; // 购买次数 + + //购买记录 + public static async buyRecord(acvitityId: number, roleId: string, dayIndex: number, cellIndex: number, count: number, lean = true) { + let result: ActivityDailyGiftsModelType = await ActivityDailyGiftsModel.findOneAndUpdate({ roleId, acvitityId, dayIndex, cellIndex }, + { $inc: { receiveRewardCount: count } }, { upsert: true, new: true }).lean(lean); + return result; + } + + //根据活动id查询活动数据 + public static async findData(acvitityId: number, roleId: string, lean = true) { + let result: ActivityDailyGiftsModelType[] = await ActivityDailyGiftsModel.find({ roleId, acvitityId }).lean(lean); + return result; + } + + //查询第几天的活动数据 + public static async findDataByDayIndex(acvitityId: number, roleId: string, dayIndex: number, lean = true) { + let result: ActivityDailyGiftsModelType[] = await ActivityDailyGiftsModel.find({ roleId, acvitityId, dayIndex }).lean(lean); + return result; + } + + //查询第几天某个的活动数据 + public static async findDataByCellIndex(acvitityId: number, roleId: string, dayIndex: number, cellIndex: number, lean = true) { + let result: ActivityDailyGiftsModelType[] = await ActivityDailyGiftsModel.find({ roleId, acvitityId, dayIndex, cellIndex }).lean(lean); + return result; + } + + //删除活动领取记录 + public static async deleteActivity(acvitityId: number, roleId: string, dayIndex: number, cellIndex: number) { + await ActivityDailyGiftsModel.deleteMany({ roleId, acvitityId, dayIndex, cellIndex }); + } +} + +export const ActivityDailyGiftsModel = getModelForClass(ActivityDailyGifts); + +export interface ActivityDailyGiftsModelType extends Pick, keyof ActivityDailyGifts> { } +export type ActivityDailyGiftsModelTypeParam = Partial; // 将所有字段变成可选项 \ No newline at end of file diff --git a/shared/domain/activityField/consumeField.ts b/shared/domain/activityField/consumeField.ts new file mode 100644 index 000000000..bf63741ff --- /dev/null +++ b/shared/domain/activityField/consumeField.ts @@ -0,0 +1,6 @@ +//资源消耗 +export interface ConsumeResParam { + type: number; + id: number; + count: number; +} \ No newline at end of file diff --git a/shared/domain/activityField/dailyChallengesField.ts b/shared/domain/activityField/dailyChallengesField.ts index 734605916..a5c93895e 100644 --- a/shared/domain/activityField/dailyChallengesField.ts +++ b/shared/domain/activityField/dailyChallengesField.ts @@ -1,4 +1,4 @@ -import { TASK_TYPE } from '../../consts'; +import { TASK_TYPE, ACTIVITY_RESOURCES_TYPE } from '../../consts'; import { ActivityModelType } from '../../db/Activity'; import { ActivityDailyChallengesModelType } from '../../db/ActivityDailyChallenges'; import { RewardInter } from '../../pubUtils/interface'; @@ -38,7 +38,7 @@ export class DailyItem { let reward = parseHeroStrWithType(objStr); rewardArray.push(reward); } - return rewardArray.find(obj => { return obj && obj.type == 1 }) + return rewardArray.find(obj => { return obj && obj.type == ACTIVITY_RESOURCES_TYPE.HERO }) } public goodReward(): RewardInter[] { @@ -48,7 +48,7 @@ export class DailyItem { let reward = parseGoodStrWithType(objStr); rewardArray.push(reward); } - return rewardArray.find(obj => { return obj && obj.type == 2 }) + return rewardArray.find(obj => { return obj && obj.type == ACTIVITY_RESOURCES_TYPE.GOODS }) } public canReceive(): boolean { diff --git a/shared/domain/activityField/dailyGiftsField.ts b/shared/domain/activityField/dailyGiftsField.ts new file mode 100644 index 000000000..55e54df04 --- /dev/null +++ b/shared/domain/activityField/dailyGiftsField.ts @@ -0,0 +1,93 @@ +import { ACTIVITY_RESOURCES_TYPE } from '../../consts'; +import { ActivityModelType } from '../../db/Activity'; +import { ActivityDailyGiftsModelType } from '../../db/ActivityDailyGifts'; +import { RewardInter } from '../../pubUtils/interface'; +import { parseGoodStrWithType, parseHeroStrWithType, parseResStr } from '../../pubUtils/util'; +import { CreateHeroParam } from '../roleField/hero'; +import { ConsumeResParam } from '../activityField/consumeField'; +import { ActivityBase } from './activityField'; + + +// 每日礼包配置数据 +export class DailyGiftItem { + dayIndex: number; // 第几天,从1开始 + cellIndex: number; // 当天第几行,从1开始 + name: string; // 名称 + consume: string; // 购买的资源数据; 格式:type:id:count, type:ACTIVITY_RESOURCES_TYPE;RMB时id无效 + reward: string; // 任务奖励,格式:1&3&1(类型&id&数量) 类型定义:1.英雄,2.物品 + maxCount: number = 0; //最大可购买次数 + + buyCount: number = 0; //购买次数 + + constructor(data: any) { + this.dayIndex = data.dayIndex; + this.cellIndex = data.cellIndex; + this.name = data.name; + this.consume = data.consume; + this.reward = data.reward; + this.maxCount = data.maxCount; + } + + //消耗的资源 + public consumeRes(): ConsumeResParam { + let consumeArray = parseResStr(this.consume); + return consumeArray[0]; + } + + public heroReward(): CreateHeroParam[] { + let rewardArray = []; + let rewardData = this.reward.split('|').filter(obj => { return obj && obj != '' }); + for (let objStr of rewardData) { + let reward = parseHeroStrWithType(objStr); + rewardArray.push(reward); + } + return rewardArray.find(obj => { return obj && obj.type == ACTIVITY_RESOURCES_TYPE.HERO }) + } + + public goodReward(): RewardInter[] { + let rewardArray = []; + let rewardData = this.reward.split('|').filter(obj => { return obj && obj != '' }); + for (let objStr of rewardData) { + let reward = parseGoodStrWithType(objStr); + rewardArray.push(reward); + } + return rewardArray.find(obj => { return obj && obj.type == ACTIVITY_RESOURCES_TYPE.GOODS }) + } + + public canBuy(): boolean { + return this.buyCount < this.maxCount; + } + +} + + +// 今日挑战活动数据 +export class DailyGiftsData extends ActivityBase { + list: Array = []; + + public findDailyGiftsItem(dayIndex: number, cellIndex: number) { + let index = this.list.findIndex(obj => { return obj && obj.dayIndex == dayIndex && obj.cellIndex == cellIndex }) + return (index != -1) ? this.list[index] : null; + } + + //解析玩家购买记录 + public setPlayerRecords(data: ActivityDailyGiftsModelType[]) { + for (let obj of this.list) { + let index = data.findIndex(record => { return obj.dayIndex == record.dayIndex && obj.cellIndex == record.cellIndex }) + if (index != -1) { + obj.buyCount = data[index].buyCount; + } + } + } + + public initData(data: string) { + let arr = JSON.parse(data); + for (let obj of arr) { + this.list.push(new DailyGiftItem(obj)) + } + } + + constructor(activityData: ActivityModelType) { + super(activityData) + } +} \ No newline at end of file diff --git a/shared/domain/activityField/growthField.ts b/shared/domain/activityField/growthField.ts index 8bbdc8f8f..e49774bb5 100644 --- a/shared/domain/activityField/growthField.ts +++ b/shared/domain/activityField/growthField.ts @@ -1,4 +1,4 @@ -import { TASK_TYPE } from '../../consts'; +import { TASK_TYPE, ACTIVITY_RESOURCES_TYPE } from '../../consts'; import { ActivityModelType } from '../../db/Activity'; import { ActivityGrowthModelType } from '../../db/ActivityGrowth'; import { RewardInter } from '../../pubUtils/interface'; @@ -46,7 +46,7 @@ export class GrowthItem { let reward = parseHeroStrWithType(objStr); rewardArray.push(reward); } - return rewardArray.find(obj => { return obj && obj.type == 1 }) + return rewardArray.find(obj => { return obj && obj.type == ACTIVITY_RESOURCES_TYPE.HERO }) } public goodReward(): RewardInter[] { @@ -56,7 +56,7 @@ export class GrowthItem { let reward = parseGoodStrWithType(objStr); rewardArray.push(reward); } - return rewardArray.find(obj => { return obj && obj.type == 2 }) + return rewardArray.find(obj => { return obj && obj.type == ACTIVITY_RESOURCES_TYPE.GOODS }) } public canReceive(): boolean { diff --git a/shared/pubUtils/util.ts b/shared/pubUtils/util.ts index 69e35ce32..4a9edf097 100644 --- a/shared/pubUtils/util.ts +++ b/shared/pubUtils/util.ts @@ -556,6 +556,21 @@ export function parseHeroStrWithType(str: string) { return result } +// 根据类型解析物品 {"type":number, "id": number, "count": number} 格式 +//type 1.英雄,2.物品, 3.RMB +export function parseResStr(str: string) { + let result = new Array<{ type: number, id: number, count: number }>(); + if (!str) return result; + let decodeArr = decodeArrayListStr(str); + for (let [type, id, count] of decodeArr) { + if (isNaN(parseInt(type)) || isNaN(parseInt(id)) || isNaN(parseInt(count))) { + throw new Error('data table format wrong'); + } + result.push({ type: parseInt(type), id: parseInt(id), count: parseInt(count) }); + } + return result +} + // 数字列表 export function parseNumberList(str: string) { let res = new Array(); @@ -651,14 +666,14 @@ export function splitString(dataString: string, key: string) { */ export function getFloorStatus(gachaId: number, floor: Floor[]) { let floorMap = new Map(); - for(let { id, count } of floor) { + for (let { id, count } of floor) { floorMap.set(id, count); } let dicFloorType = GACHA_TO_FLOOR.get(gachaId); return dicFloorType.map(id => { return { id, - count: floorMap.get(id)||0 + count: floorMap.get(id) || 0 } }); } \ No newline at end of file