Files
ZYZ/shared/pubUtils/util.ts
2021-01-07 12:25:40 +08:00

525 lines
17 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 { STATUS } from './../consts/statusCode';
import { HeroModel, HeroType } from '../db/Hero';
import fs = require('fs');
import path = require('path');
import { DicRandomEffectPool } from './dictionary/DicRandomEffectPool';
import { HERO_CE_RATIO, ABI_STAGE } from '../consts';
const _ = require('underscore');
const moment = require('moment');
export function genCode(len) {
const chars = '123456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijklmnopqrstuvwxyz';
const charArr = chars.split('');
let code = '';
for (let i = 0; i < len; i++) {
code += charArr[Math.floor(Math.random() * charArr.length)];
}
return code;
}
export function decodeStr(type, str, splitForm = '|') {
if (str == '&' || !str) {
return []
} else {
return str.split(splitForm).map(cur => {
return decodeStrSingle(type, cur);
});
};
}
export function decodeStrSingle(type, str) { //单层,返回对象而不是数组
let last = str.substr(str.length - 1, 1);
if (last == '&') str = str.substr(0, str.length - 1);
if (str == '&' || !str) {
return {}
} else {
let arr = str.split('&');
let result: any;
switch (type) {
case 'fixReward': {
let [id, count] = arr;
if (isNaN(id) || isNaN(count)) throw new Error('data table format wrong');
result = { id: parseInt(id), count: parseInt(count) };
break;
}
case 'conditionReward': {
let [id, count, condition] = arr;
if (isNaN(id) || isNaN(count)) throw new Error('data table format wrong');
result = { id: parseInt(id), count: parseInt(count), condition: parseInt(condition) };
break;
}
case 'randomReward': {
let [id, count, frequency] = arr;
if (isNaN(id) || isNaN(count)) throw new Error('data table format wrong');
result = { id: parseInt(id), count: parseInt(count), frequency: parseInt(frequency) };
break;
}
case 'suitLevel': {
let [min, max] = arr;
if (isNaN(min) || isNaN(max)) throw new Error('data table format wrong');
result = { min: parseInt(min), max: parseInt(max) };
break;
}
case 'suitLevelSingle': {
let [min, max] = arr;
if (max) {
if (isNaN(min) || isNaN(max)) throw new Error('data table format wrong');
result = { min: parseInt(min), max: parseInt(max) };
break;
} else {
if (isNaN(min)) throw new Error('data table format wrong');
result = { min: parseInt(min) };
break;
}
}
case 'attribute': {
let [id, value] = arr;
if (isNaN(id) || isNaN(value)) throw new Error('data table format wrong');
result = { id: parseInt(id), value: parseInt(value) };
break;
}
case 'point': {
let [x] = arr;
if (isNaN(x)) throw new Error('data table format wrong');
result = x;
break;
}
case 'decimalReward': {
let [id, count] = arr;
if (isNaN(id) || isNaN(count)) throw new Error('data table format wrong');
result = { id: parseInt(id), count: parseFloat(count) };
break;
}
case 'towerTaskCondition': {
let [type, param, cnt] = arr;
if (isNaN(type) || isNaN(param) || isNaN(cnt)) throw new Error('data table format wrong');
result = { type: parseInt(type), param: parseInt(param), cnt: parseInt(cnt) };
break;
}
case 'possibility': {
let [id, weight] = arr;
if (isNaN(id) || isNaN(weight)) throw new Error('data table format wrong');
result = { id: parseInt(id), weight: parseInt(weight) };
break;
}
case 'cost': {
let [id, count] = arr;
if (isNaN(id) || isNaN(count)) throw new Error('data table format wrong');
result = { id: parseInt(id), count: parseInt(count) };
break;
}
}
return result;
};
}
/**
* 将 | 分隔的字符串解析为数组a|b|c 解析为[a, b, c]
* @param str 要解析的字符串
*/
export function decodeArrayStr(str: string, splitForm = '|') {
let last = str.substr(str.length - 1, 1);
if (last == '&') str = str.substr(0, str.length - 1);
if (str == '') {
return new Array<string>()
} else {
return str.split(splitForm);
}
}
/**
* 将 | 和 & 分隔的字符串解析为 Mapa&b&c|c&d&f 解析为 [[a,b,c], [c,d,f]]
* @param str 要解析的字符串
*/
export function decodeArrayListStr(str: string) {
return decodeArrayStr(str).map(cur => decodeArrayStr(cur, '&'));
}
/**
* 将 | 和 & 分隔的字符串解析为 Mapa&b|c&d|e&f 解析为 Map {a=>b, c=>d, e=>f}
* @param str 要解析的字符串
*/
export function decodeIdCntArrayStr(str: string, multi: number) {
const strArr = decodeArrayStr(str);
console.log('decodeIdCntArrayStr: ', strArr);
const strMap = new Map();
strArr.forEach(item => {
const kv = item.split('&');
strMap.set(kv[0], multi ? Math.ceil(parseInt(kv[1]) * multi) : kv[1]);
});
return strMap;
}
// 计算当前武将战力
export async function calculateSumCE(roleId: string, type: number, param: { num?: number, heroes?: Array<number> }) {
let sum;
if (type == 1) { // 最高num人历史最高战力和
sum = await HeroModel.sumTopHeroCe(roleId, param.num || 0);
} else if (type == 2) { // 所有人战力和
sum = await HeroModel.sumHeroCe(roleId);
}
return sum;
}
export function getRandomByLen(arr: Array<number>): number
export function getRandomByLen(arr: Array<string>): string
export function getRandomByLen(arr: Array<DicRandomEffectPool>): DicRandomEffectPool
export function getRandomByLen(arr: Array<any>): any {
let len = arr.length;
return arr[Math.floor(Math.random() * len)]
}
export function getRandomIndexByLen(len: number) {
return Math.floor(Math.random() * len);
}
export function getRandomWithWeight(randomList: any) {
let len = randomList.reduce((pre, cur) => {
return pre + cur.weight || 1;
}, 0);
let index = Math.floor(Math.random() * len);
let result = { dic: null, index: -1 };
for (let i = 0; i < randomList.length; i++) {
let { weight = 0 } = randomList[i];
if (index < weight) {
result.dic = randomList[i];
result.index = i;
break;
}
index -= weight;
}
return result
}
/**
* 传入两个时间,返回按照时间差计算,第二个时间比第一个晚几天
* @param preTime 之前的时间
* @param proTime 之后的时间
*/
export function deltaDays(preTime: Date, proTime: Date): number {
return moment(proTime).diff(moment(preTime), "days");
}
/**
* 计算按照每 x 天 y 点刷新一次,是否应该刷新
* @param preTime 基准时间
* @param curTime 当前时间
* @param hour 几点刷新
* @param deltaDay 间隔几天刷新,默认每天刷新(deltaDay = 1)
*/
export function shouldRefresh(preTime: Date, now: Date, hour: number, deltaDay = 1): boolean {
if (!preTime) return true;
let curTime = new Date(now.getTime());
let refeshTime = setLocalHours(hour, curTime);
if (refeshTime - preTime.getTime() > (deltaDay >= 1 ? deltaDay - 1 : 0) * 24 * 60 * 60 * 1000 && curTime.getTime() >= refeshTime) {
return true;
}
return false;
}
/**
* 获取 x天后的y点
* @param curTime 现在时间
* @param hour 几点刷新
*/
export function getRefTime(now = new Date(), hour: number, day = 0) {
let curTime = new Date(now.getTime());
let offset = curTime.getTimezoneOffset(); // 时差,单位分
let checkHour = hour - 8 + offset / 60;
if (checkHour < 0) {
checkHour = 24 + checkHour;
if (curTime.getHours() >= checkHour) {
curTime.setDate(curTime.getDate() + 1);
}
} else {
if (curTime.getHours() < checkHour) {
curTime.setDate(curTime.getDate() - 1);
}
}
let today = setLocalHours(hour, curTime);
return new Date(today + day * 24 * 60 * 60 * 1000);
}
/**
* 从一个数组中随机返回不重复的 cnt 个元素数组
* @param source 原数组
* @param cnt 返回随机元素个数
*/
export function getRandEelm(source: Array<any> = [], cnt = 1): Array<any> {
if (cnt > source.length || cnt == 0) return [];
if (cnt === source.length) return source;
let idxs = new Set();
while (1) {
let rand = Math.floor(Math.random() * source.length);
idxs.add(rand);
if (idxs.size >= cnt) {
break;
}
}
return source.filter((_item, idx) => idxs.has(idx));
}
/**
* 在给定数值的浮动范围中随机一个值
* @param base 基础数值
* @param ratio 随机范围base 值上下浮动 ratio(小于 1 的整数)
* @param decimal 返回值保留的小数位数
*/
export function getRandValue(base: number, ratio: number, decimal = 2): number {
return parseFloat((base * (1 - ratio + Math.random() * ratio * 2)).toFixed(decimal));
}
/**
* 在给定最大最小值中随机一个值
* @param min 最小
* @param max 最大
* @param decimal 返回值保留的小数位数
*/
export function getRandValueByMinMax(min: number, max: number, decimal = 2): number {
return parseFloat((min + (max - min) * Math.random()).toFixed(decimal));
}
export function resResult(status: { code: number, simStr: string }, data = null, customMsg = '') {
const { code, simStr } = status;
if (code !== STATUS.SUCCESS.code) {
console.log(`normal err, code: ${code}, des: ${customMsg || simStr}`);
}
return { code, msg: customMsg || simStr, data };
}
// 消除 js 浮点计算bug
export const cal = {
add: function (a: number, b: number) {
var c: number, d: number, e: number;
try {
c = a.toString().split(".")[1].length;
} catch (f) {
c = 0;
}
try {
d = b.toString().split(".")[1].length;
} catch (f) {
d = 0;
}
e = Math.pow(10, Math.max(c, d));
return (this.mul(a, e) + this.mul(b, e)) / e;
},
sub: function sub(a: number, b: number) {
var c: number, d: number, e: number;
try {
c = a.toString().split(".")[1].length;
} catch (f) {
c = 0;
}
try {
d = b.toString().split(".")[1].length;
} catch (f) {
d = 0;
}
e = Math.pow(10, Math.max(c, d));
return (this.mul(a, e) - this.mul(b, e)) / e;
},
mul: function mul(a: number, b: number) {
var c = 0,
d = a.toString(),
e = b.toString();
try {
c += d.split(".")[1].length;
} catch (f) { }
try {
c += e.split(".")[1].length;
} catch (f) { }
return Number(d.replace(".", "")) * Number(e.replace(".", "")) / Math.pow(10, c);
},
div: function div(a: number, b: number) {
var c: number, d: number, e = 0,
f = 0;
try {
e = a.toString().split(".")[1].length;
} catch (g) { }
try {
f = b.toString().split(".")[1].length;
} catch (g) { }
c = Number(a.toString().replace(".", ""));
d = Number(b.toString().replace(".", ""));
return this.mul(c / d, Math.pow(10, f - e));
}
};
//计算公式
export function calculateNum(ratio: { A: number, B: number }, params: { num: number }, defaultVal = 0) {
// result = a * num + b
try {
let { A, B } = ratio;
let { num } = params;
let result = A * num + B;
if (isNaN(result)) {
console.error('calculate wrong: ', A, B, num)
return defaultVal;
} else {
return result;
}
} catch (e) {
console.error(e);
return defaultVal;
}
}
export function setLocalHours(hour: number, curTime = new Date()) {
// curTime: 格林威治时间
let offset = curTime.getTimezoneOffset(); // 格林威治时间和本地时间之间的时差(分)
let localTime = new Date(curTime.getTime() + offset * 60 * 1000 + 8 * 60 * 60 * 1000); // 中国时间
localTime.setUTCHours(hour, 0, 0, 0); // 中国的几点
return localTime.getTime() - 8 * 60 * 60 * 1000; // 回到格林威治时间
}
export function ratioReward(rewardStr: string, ratio: number): string {
let rewards = decodeIdCntArrayStr(rewardStr, ratio);
let res = '';
for (let [k, v] of rewards) {
res += `${k}&${v}|`;
}
return res.substring(0, res.length - 1);
}
export function getItems(str: string) {
let arr = new Array<{ id: number, count: number }>();
let strArr = str.split('|');
for (let item of strArr) {
var itemArr = item.split('&');
arr.push({
id: parseInt(itemArr[0]),
count: parseInt(itemArr[1])
});
}
return arr;
}
export function deepCopy(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
var target;
if (obj instanceof Array) {
target = [];
obj.forEach(element => {
target.push(deepCopy(element));
});
} else {
target = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const element = obj[key];
if (!!element || element == 0) {
target[key] = deepCopy(element);
}
}
}
}
return target;
};
export function readJsonFile(fileName: string) {
const folder = 'jsons';
return fs.readFileSync(path.resolve(__dirname, `../resource/${folder}/${fileName}.json`)).toString('utf8').replace(/^\uFEFF/, '');
}
export function readWarJsonFileList() {
const folder = 'warJsons';
return fs.readdirSync(__dirname + `/../resource/${folder}`)
.filter(cur => { return cur.indexOf('.') != 0 })
.map(file => {
return fs.readFileSync(path.resolve(__dirname, `../resource/${folder}/${file}`)).toString('utf8');
});
}
// 字典表常用解析方法
// 解析物品 {"id": number, "count": number} 格式
export function parseGoodStr(str: string) {
let result = new Array<{ id: number, count: number }>();
if (!str) return result;
let decodeArr = decodeArrayListStr(str);
for (let [id, count] of decodeArr) {
if (isNaN(parseInt(id)) || isNaN(parseInt(count))) {
throw new Error('data table format wrong');
}
result.push({ id: parseInt(id), count: parseInt(count) });
}
return result
}
// 数字列表
export function parseNumberList(str: string) {
let res = new Array<number>();
if (!str) return res;
let arr = decodeArrayStr(str, '&');
for (let g of arr) {
if (g === "") continue;
res.push(parseInt(g));
}
return res;
}
export function mergeSameGoods(goods: Array<{ id: number, count: number }>) {
let resGoods = [];
for (let { id, count } of goods) {
let index = _.findIndex(resGoods, { id });
if (index > -1) {
resGoods[index].count += count;
} else {
resGoods.push({ id, count });
}
}
return resGoods;
}
export function returnHeroCeRatio(hero: HeroType) {
let ce = reduceCe(hero.ce);
return Object.assign(hero, { ce });
}
// 缩小战力
export function reduceCe(ce: number = 0) {
return Math.floor(ce / HERO_CE_RATIO / HERO_CE_RATIO)
}
export function getRandNum(min, max) {
let randNum = min + Math.floor(Math.random()*(max - min + 1));
return randNum;
}
export function getRandomArr(allarr, ranNum) {
let arr = deepCopy(allarr);
var result = [];
if (arr.length <= ranNum) {
result = result.concat(arr);
return result;
}
for (var i = 0; i < ranNum; i++) {
var ran = Math.floor(Math.random() * arr.length);
result.push(arr.splice(ran, 1)[0]);
};
return result;
}
// 获取全部属性
export function getAllAttrStage () {
let attrs = new Array<number>(); // 有升级的属性 1-hp 2-atk 3-def 4-mdef 5-agi 6-luk
for(let stage = ABI_STAGE.START + 1; stage <= ABI_STAGE.END; stage++) {
attrs.push(stage)
};
return attrs;
}