Files
ZYZ/shared/domain/activityField/luckyField.ts
2023-10-19 14:58:56 +08:00

269 lines
8.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<number, number>();
for (let { id } of this.records) {
let num = (gidMap.get(id) || 0) + 1;
gidMap.set(id, num);
}
return gidMap;
}
// 奖池剔除numLimit限制
private getPoolByRecordNum() {
let gidMap = this.getGidMap();
let pool: LuckyPool[] = [];
for (let obj of this.pool) {
let { id, numLimit } = obj;
if (numLimit == -1 || numLimit > (gidMap.get(id) || 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 && pool.numLimit != -1)) 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, id: randResult.id };
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.id) || 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)
}
}