Files
ZYZ/shared/pubUtils/util.ts
liangtongchuan cdd889f1aa 寻宝掉落
2020-12-02 00:16:07 +08:00

394 lines
12 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 { 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);
}
}
/**
* 将 | 和 & 分隔的字符串解析为 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 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);
}