Files
ZYZ/shared/pubUtils/util.ts
T
2020-12-02 00:16:07 +08:00

394 lines
12 KiB
TypeScript

import { STATUS } from './../consts/statusCode';
import { getGamedata } from './gamedata';
import { HeroModel } from '../db/Hero';
import { RoleModel } from '../db/Role';
import { PvpDefenseModel } from '../db/PvpDefense';
import Actor from './actor';
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 [gid, count] = arr;
if(isNaN(gid) || isNaN(count)) throw new Error('data table format wrong');
result = { gid: parseInt(gid), count: parseInt(count)};
break;
}
case 'conditionReward': {
let [gid, count, condition] = arr;
if(isNaN(gid) || isNaN(count)) throw new Error('data table format wrong');
result = { gid: parseInt(gid), count: parseInt(count), condition: parseInt(condition) };
break;
}
case 'randomReward': {
let [gid, count, frequency] = arr;
if(isNaN(gid) || isNaN(count)) throw new Error('data table format wrong');
result = { gid: parseInt(gid), 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;
console.log(min, max)
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 [gid, count] = arr;
if(isNaN(gid) || isNaN(count)) throw new Error('data table format wrong');
result = { gid: parseInt(gid), 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;
}
}
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 []
} else {
return str.split(splitForm);
}
}
/**
* 将 | 和 & 分隔的字符串解析为 Map,,如:a&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 calculateCE(heroInfo: {hid: number, lv: number }) {
let { hid, lv } = heroInfo;
// 假设所有属性和等级的关系是简单的线性关系
let dicHero = getGamedata('dic_zyz_hero');
let curDicHero = dicHero.find(cur => cur.heroId == hid);
let { atk, matk, def, mdef, agi, luk, atk_up, matk_up, def_up, mdef_up, agi_up, luk_up } = curDicHero;
atk += lv * atk_up;
matk += lv * matk_up;
def += lv * def_up;
mdef += lv * mdef_up;
agi += lv * agi_up;
luk += lv * luk_up;
// 假设战力为所有属性的简单加法
let ce = atk + matk + def + mdef + agi + luk;
return ce;
}
export function getRandomByLen(arr: Array<number>):number
export function getRandomByLen(arr: Array<any>): any {
let len = arr.length;
return arr[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);
console.log(refeshTime - preTime.getTime(), (deltaDay>=1?deltaDay-1:0) * 24 * 60 * 60 * 1000, curTime.getTime(), refeshTime)
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) 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));
}
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 async function updateCe(roleId: string, hero: any ) {
let {hid, ce: oldCe, historyCe} = hero;
let actor = new Actor();
actor.initHero(hero);
let ce = actor.calculateCE();
if(ce != oldCe) {
// 更新总战力&最强五人战力
await RoleModel.updateSumCe(roleId, hid, ce, oldCe);
// 更新pvp防守阵容战力
await PvpDefenseModel.updateCe(roleId, hid, ce, oldCe);
// 更新武将战力,历史最高战力
await HeroModel.updateCe(roleId, hid, ce, oldCe, historyCe);
}
}
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);
}