import { pick } from 'underscore'; import { ActivityModelType } from '../../db/Activity'; import { RewardInter } from '../../pubUtils/interface'; import { getRandEelmWithWeight, parseGoodStr } from '../../pubUtils/util'; import { ActivityBase } from './activityField'; import { ActivityLuckyModelType, FloorRecord, TurntableRecord } from '../../db/ActivityLuckyRec'; /************** 在数据库中的格式 ***********/ interface TurntablePoolInDb { id: number; // 奖池id gid: number; // 物品id count: number; // 道具数量 weight: number; // 权重 numLimit: number; // 次数上限 } interface TurntableFloorInDb { // 保底,每sum次必出count个头奖,头奖:权重最低的一项 sum: number; id: number; } interface TurntableBoxInDb { count: number; // 次数 rewards: string; // 奖励 type&id&count } interface TurntableInDb { cost: string; // 抽1次的消耗,id&count freeCount: number; // 免费次数 pool: TurntablePoolInDb[]; // 奖池 floor: TurntableFloorInDb[]; // 保底 box: TurntableBoxInDb[]; } /************** 给客户端返回的数据 ***********/ // 转盘数据 export class LuckyPool { id: number; // 奖池项唯一id gid: number; // 物品id count: number; // 物品数量 weight: number; // 权重-最好填写整数,会自动做加和,如weight为1,2,则他们的概率为1/3和2/3 numLimit: number; // 次数上限 getCnt: number constructor(data: TurntablePoolInDb) { this.id = data.id; this.gid = data.gid; this.count = data.count; this.weight = data.weight; this.numLimit = data.numLimit; // 次数上限 this.getCnt = 0; //对应numLimit已抽次数 } public getShowResult() { return pick(this, ['id', 'gid', 'count', 'numLimit', 'getCnt']); } } export class LuckyBox { count: number; // 次数 rewards: string; // 奖励 isReceived: boolean = false; // 是否已领取 constructor(data: TurntableBoxInDb) { this.count = data.count; this.rewards = data.rewards; } public setReceived(box: number[] = []) { if (box.indexOf(this.count) != -1) { this.isReceived = true; } } } // 新云转盘活动数据 export class LuckyData extends ActivityBase { cost: string; // 抽1次的消耗 freeCount: number; // 免费次数 pool: LuckyPool[] = []; box: LuckyBox[] = []; floor: { // 保底 sum: number; id: number; floorCount?: number; }[]; todayCount: number = 0; // 今天抽了几次 count: number = 0; // 一共抽了几次 records: TurntableRecord[] = []; // 奖励记录 floorRecord: FloorRecord[] = []; // public getCost(count: number) { if (this.todayCount < this.freeCount) { count -= this.freeCount - this.todayCount; } let cost = parseGoodStr(this.cost); return cost.map(cur => ({ ...cur, count: cur.count * count })); } private getGidMap() { let gidMap = new Map(); for (let { gid } of this.records) { let num = (gidMap.get(gid) || 0) + 1; gidMap.set(gid, num); } return gidMap; } // 奖池剔除numLimit限制 private getPoolByRecordNum() { let gidMap = this.getGidMap(); let pool: LuckyPool[] = []; for (let obj of this.pool) { let { gid, numLimit } = obj; if (numLimit == -1 || numLimit > (gidMap.get(gid) || 0)) pool.push(obj); } return pool; } // 保底 private getFloor(pool: LuckyPool[]) { let ret: TurntableFloorInDb = { sum: 0, id: 0 }; for (let { sum, id } of this.floor) { let floorRecord = this.floorRecord.find(cur => cur.id == id); let count = 0; if (floorRecord) count = floorRecord.count + 1; if ((count == sum || count % sum == 0) && count != 0) { if (sum > ret.sum) { ret = { sum, id }; if (floorRecord) floorRecord.count = 0; } } } if (ret && ret.id > 0) { let newPool = pool.find(cur => cur.id == ret.id) if (newPool) { return { newPool }; } } return {}; } //获取保底 public getFloorCount() { for (let obj of this.floor) { let { sum, id } = obj; let pool = this.pool.find(cur => cur.id == id) if (!pool || pool.numLimit <= pool.getCnt) obj.floorCount = 0; else { let count = this.floorRecord.find(cur => cur.id == id)?.count || 0; if (count % sum == 0) obj.floorCount = sum; else { obj.floorCount = sum - (count % sum); } } } return this.floor; } public pull(roleName: string, count: number) { let records: (string | number)[][] = []; let result: number[] = []; let goodResult: RewardInter[] = []; for (let i = 0; i < count; i++) { // 1.次数上限 let pool = this.getPoolByRecordNum(); // 2.保底 let { newPool } = this.getFloor(pool); let randResult = newPool; if (!newPool) { randResult = getRandEelmWithWeight(pool).dic; } if (randResult) { let tempPool = this.pool.find(cur => cur.id == randResult.id); if (tempPool) { tempPool.getCnt = (tempPool.getCnt || 0) + 1; } for (let obj of this.floor) { let floorRecord = this.floorRecord.find(cur => cur.id == obj.id); if (obj.id != randResult.id) { if (!floorRecord) this.floorRecord.push({ id: obj.id, count: 1 }); else floorRecord.count++; } else { if (floorRecord) floorRecord.count = 0; } } this.count++; this.todayCount++; let record = { roleName, gid: randResult.gid, count: randResult.count }; records.push([record.roleName, record.gid, record.count]); this.records.push(record); result.push(randResult.id); goodResult.push({ id: randResult.gid, count: randResult.count }); } } return { result, records, goodResult, pool: this.pool.map(pool => pool.getShowResult()), floor: this.getFloorCount() }; } // 宝箱是否可以领取 public canReceive(boxCount: number) { if (this.count < boxCount) return false; let box = this.box.find(cur => cur.count == boxCount); if (!box) return false if (box.isReceived) return false; return true; } public findBox(boxCount: number) { let box = this.box.find(cur => cur.count == boxCount); return box; } public setPlayerRecords(playerData: ActivityLuckyModelType) { if (!playerData) return null let { todayCount, count, records, box, floorRecord = [] } = playerData; this.todayCount = todayCount; this.count = count; this.records = records; for (let boxData of this.box) { boxData.setReceived(box); } let gidMap = this.getGidMap(); for (let obj of this.pool) { obj.getCnt = (gidMap.get(obj.gid) || 0); } this.floorRecord = floorRecord; } public initData(data: string) { let dataObj: TurntableInDb = JSON.parse(data); this.cost = dataObj.cost; this.freeCount = dataObj.freeCount; for (let pool of dataObj.pool) { let poolObj = new LuckyPool(pool); this.pool.push(poolObj); } for (let box of dataObj.box) { this.box.push(new LuckyBox(box)); } this.floor = dataObj.floor; } public getShowResult() { return { ...this.getBaseKeys(), cost: this.cost, freeCount: this.freeCount, todayCount: this.todayCount, count: this.count, box: this.box, pool: this.pool.map(pool => pool.getShowResult()), records: this.records.map(record => [record.roleName, record.gid, record.count]), floor: this.getFloorCount(), } } constructor(activityData: ActivityModelType, createTime: number, serverTime: number) { super(activityData, createTime, serverTime) this.initData(activityData.data) } }