import { STATUS } from './../consts/statusCode'; import { isNumber } from 'underscore'; const csprng = require('csprng'); const fs = require('fs'); const path = require('path'); import { ABI_STAGE, REFRESH_TIME, ROBOT_SYS_TYPE, ITEM_CHANGE_REASON, WAR_TYPE, SHOP_REFRESH_TYPE, GACHA_TYPE, GACHA_FLOOR_TYPE } from '../consts'; import { findIndex } from 'underscore'; import { getZeroPointD, getZeroPointOfTimeD } from './timeUtil'; import { Floor } from '../domain/activityField/gachaField'; import { RewardInter } from './interface'; import { gameData } from './data'; const randomName = require("chinese-random-name"); const moment = require('moment'); const crypto = require('crypto'); export function aesEncrypt(data, key, iv) { const cipher = crypto.createCipheriv('aes-192-cbc', key, iv); let crypted = cipher.update(data, 'utf8', 'hex'); crypted += cipher.final('hex'); return crypted; } export function aesDecrypt(data, key, iv) { const decipher = crypto.createDecipheriv('aes-192-cbc', key, iv); let decrypted = decipher.update(data, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; } export function aesEncryptcfb(data, key, iv) { const cipher = crypto.createCipheriv('aes-192-cfb', key, iv); let crypted = cipher.update(data, 'utf8', 'hex'); crypted += cipher.final('hex'); // console.log('****aesEncryptcfb', data, crypted) return crypted; } export function aesDecryptcfb(data, key, iv) { if (data) { const decipher = crypto.createDecipheriv('aes-192-cfb', key, iv); let decrypted = decipher.update(data, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; } else { return '' } } export function aes128Encrypt(input: string, key = '') { const cipher = crypto.createCipheriv('aes-128-ecb', key, null); let crypted = cipher.update(input, 'utf8', 'base64'); crypted += cipher.final('base64'); console.log('****aesEncryptecb', 'input: ', `"${input}"`, 'crypted:', `"${crypted}"`) return crypted; } // function pkcs5_pad(text: string, blocksize: number) { // const pad = blocksize - (text.length % blocksize); // return text + String.fromCharCode(pad).repeat(pad); // } export function aes128Decrypt(data: string, key = '') { const decipher = crypto.createDecipheriv('aes-128-ecb', key, null); let crypted = decipher.update(data, 'base64', 'utf8'); crypted += decipher.final('utf8'); const padding = crypted.charCodeAt(crypted.length - 1); return crypted.slice(0, -padding);; } 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; } /** * 生成 len 长度的随机字符串 * @param len 长度 * @param radix 基数 */ export function generateStr(len: number, radix = 36) { return `${csprng(len, radix)}`; } export function generateNum(len: number) { let code = ''; for (let i = 0; i < len; i++) { code += parseInt(`${Math.random() * 10}`); } return code; } /** * 将 | 分隔的字符串解析为数组,如: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() } else { return str.split(splitForm); } } /** * 将 | 和 & 分隔的字符串解析为 Map,,如:a&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, '&')); } /** * 将 | 和 & 分隔的字符串解析为 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) : parseInt(kv[1])); }); return strMap; } /** * 传入两个时间,返回按照时间差计算,第二个时间比第一个晚几天 * @param preTime 之前的时间 * @param proTime 之后的时间 */ export function deltaDays(preTime: Date, proTime: Date, useNaturalZero = false): number { let beginZeroPoint = getZeroPointOfTimeD(preTime, SHOP_REFRESH_TYPE.DAILY, useNaturalZero ? 0 : REFRESH_TIME); let endZeroPoint = getZeroPointOfTimeD(proTime, SHOP_REFRESH_TYPE.DAILY, useNaturalZero ? 0 : REFRESH_TIME); return moment(endZeroPoint).diff(moment(beginZeroPoint), "days"); } /** * 计算按照每 x 天 y 点刷新一次,是否应该刷新 * @param preTime 基准时间 * @param curTime 当前时间 * @param hour 几点刷新 * @param deltaDay 间隔几天刷新,默认每天刷新(deltaDay = 1) */ export function shouldRefresh(preTime: Date, now: Date, hour: number = REFRESH_TIME, deltaDay = 1): boolean { if (!preTime) return true; let curTime = new Date(now.getTime()); let refreshTime = getZeroPointD(SHOP_REFRESH_TYPE.DAILY, hour); let refeshTime = refreshTime.getTime(); if (refeshTime - preTime.getTime() > (deltaDay >= 1 ? deltaDay - 1 : 0) * 24 * 60 * 60 * 1000 && curTime.getTime() >= refeshTime) { return true; } return false; } /** * 计算按照每 x 天 y 点刷新一次,是否应该刷新 * @param preTime 基准时间 * @param curTime 当前时间 * @param day 周几刷新 * @param hour 几点刷新 * @param deltaDay 间隔几天刷新,默认每天刷新(deltaDay = 1) */ export function shouldRefreshWeek(preTime: Date, now: Date, hour: number = REFRESH_TIME, deltaWeek = 1): boolean { if (!preTime) return true; let curTime = new Date(now.getTime()); let refreshTime = getZeroPointD(SHOP_REFRESH_TYPE.WEEKLY, hour); let refeshTime = refreshTime.getTime(); if (refeshTime - preTime.getTime() > (deltaWeek >= 1 ? deltaWeek - 1 : 0) * 7 * 24 * 60 * 60 * 1000 && curTime.getTime() >= refeshTime) { return true; } return false; } /** * 从一个数组中随机返回不重复的 cnt 个元素数组 * @param source 原数组 * @param cnt 返回随机元素个数 */ export function getRandEelm(source: Array = [], cnt = 1): Array { if (cnt == 0) return []; if (cnt >= source.length) return sortArrRandom(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)); } /** * 从一个数组中随机返回1元素 * @param source */ export function getRandSingleEelm(source: Array): T { let len = source.length; return source[Math.floor(Math.random() * len)] } /** * 随机数组中一个index * @param len */ export function getRandSingleIndex(len: number) { return Math.floor(Math.random() * len); } /** * 从一个数组根据权重随机一个元素 * @param randomList */ export function getRandEelmWithWeight(randomList: T[]): { dic: T, index: number } { let len = randomList.reduce((pre, cur) => { return pre + (cur.weight || 0); }, 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 } export function getRandEelmWithWeightAndNum(randomList: T[], num: number): { dic: T, index: number }[] { let result: { dic: T, index: number }[] = []; let remainingList = randomList.slice(); // Make a copy of randomList to work with for (let n = 0; n < Math.min(num, randomList.length); n++) { if (remainingList.length === 0) { // If there are no more elements to choose from, exit the loop break; } let len = remainingList.reduce((pre, cur) => { return pre + (cur.weight || 0); }, 0); let index = Math.floor(Math.random() * len); let found = false; for (let i = 0; i < remainingList.length; i++) { let { weight = 0 } = remainingList[i]; if (index < weight) { result.push({ dic: remainingList[i], index: randomList.indexOf(remainingList[i]) }); remainingList.splice(i, 1); // Remove the selected element from the list found = true; break; } index -= weight; } if (!found) { // In case the index exceeds the weights, add a default value result.push({ dic: null, index: -1 }); } } return result; } /** * 不改变原数组长度,将内部元素打乱 * @param source */ export function sortArrRandom(source: T[] = []): T[] { let newArr: T[] = [...source]; return newArr.sort(() => { return Math.random() - 0.5; }); } /** * 在给定数值的浮动范围中随机一个值 * @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 { let pow = Math.pow(10, decimal); return Math.floor((min + (max - min) * Math.random()) * pow) / pow; } export function resResult(status: { code: number, simStr: string }, data: T = {}, customMsg = ''): { code: number, msg: string, data: T } { const { code, simStr } = status; if (code !== STATUS.SUCCESS.code) { console.log(`normal err, code: ${code}, des: ${customMsg || simStr}`); } return { code, msg: customMsg || simStr, data }; } export function getResStr(status: { code: number, simStr: string }) { return status.simStr; } // 消除 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 getDecimalCnt(num: number) { let str = num.toString(); return str.split('.')[1] ? str.split('.')[1].length : 0; } //计算公式 // 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 ratioReward(reward: { id: number, count: number }[], ratio: number): { id: number, count: number }[] { return reward.map(cur => { return { id: cur.id, count: cur.count * ratio } }); } 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 readFile(addr: string) { return fs.readFileSync(path.resolve(__dirname, `${addr}`)).toString('utf8').replace(/^\uFEFF/, ''); } export function writeFile(addr: string, data: string) { return fs.writeFileSync(addr, data); } export function readFileAndParseJson(path: string) { try { let readResult = readFile(path); return JSON.parse(readResult); } catch (e) { throw new Error(`connectors.json 格式错误:${(e).message}`); } } 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 { name: file, str: fs.readFileSync(path.resolve(__dirname, `../resource/${folder}/${file}`)).toString('utf8') } }); } export function readServerNameFileList() { const folder = 'serverName'; return fs.readdirSync(__dirname + `/../resource/${folder}`) .filter(cur => { return cur.indexOf('.') != 0 }) .map(file => { return { name: file, str: fs.readFileSync(path.resolve(__dirname, `../resource/${folder}/${file}`)).toString('utf8') } }); } export function readWordTxt(fileName: string) { try { let file = fs.readFileSync(path.resolve(__dirname, `../resource/${fileName}.txt`)).toString('utf8').replace(/^\uFEFF/, ''); return file; } catch (e) { console.log(e) return null } } export function writeWordTxt(fileName: string, words: string) { try { let file = fs.writeFileSync(path.resolve(__dirname, `../resource/${fileName}.txt`), words); return file; } catch (e) { return null } } export function readTsFile(fileName: string) { try { let file = fs.readFileSync(path.resolve(__dirname, `../pubUtils/${fileName}.js`)).toString('utf8').replace(/^\uFEFF/, ''); return file; } catch (e) { return null } } export function readFileAndParse(fileName: string) { try { let readResult = readJsonFile(fileName); return JSON.parse(readResult); } catch (e) { throw new Error(`${fileName}格式错误:${(e).message}`); } } export function readWarJsonFileAndParse() { let warJsons = readWarJsonFileList(); let result = []; for (let { name, str } of warJsons) { try { let json = JSON.parse(str); result.push(json); } catch (e) { throw new Error(`${name}格式错误:${(e).message}`); } } return result; } // 字典表常用解析方法 // 解析物品 {"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 } // 根据类型解析物品 {"type":number, "id": number, "count": number} 格式 //type 1.英雄,2.物品 export function parseGoodStrWithType(str: string) { let result = new Array<{ type: number, id: number, count: number }>(); if (!str) return result; let decodeArr = decodeArrayListStr(str); for (let [type, id, count] of decodeArr) { if (isNaN(parseInt(type)) || isNaN(parseInt(id)) || isNaN(parseInt(count))) { throw new Error('data table format wrong'); } result.push({ type: parseInt(type), id: parseInt(id), count: parseInt(count) }); } return result } // 根据类型解析物品 {"type":number, "hid": number, "count": number} 格式 //type 1.英雄,2.物品 export function parseHeroStrWithType(str: string) { let result = new Array<{ type: number, hid: number, count: number }>(); if (!str) return result; let decodeArr = decodeArrayListStr(str); for (let [type, hid, count] of decodeArr) { if (isNaN(parseInt(type)) || isNaN(parseInt(hid)) || isNaN(parseInt(count))) { throw new Error('data table format wrong'); } result.push({ type: parseInt(type), hid: parseInt(hid), count: parseInt(count) }); } return result } // 根据类型解析物品 {"type":number, "id": number, "count": number} 格式 //type 1.英雄,2.物品, 3.RMB export function parseResStr(str: string) { let result = new Array<{ type: number, id: number, count: number }>(); if (!str) return result; let decodeArr = decodeArrayListStr(str); for (let [type, id, count] of decodeArr) { if (isNaN(parseInt(type)) || isNaN(parseInt(id)) || isNaN(parseInt(count))) { throw new Error('data table format wrong'); } result.push({ type: parseInt(type), id: parseInt(id), count: parseInt(count) }); } return result } // 数字列表 export function parseNumberList(str: string) { let res = new Array(); if (!str) return res; let arr = decodeArrayStr(`${str}`, '&'); for (let g of arr) { if (g === "") continue; res.push(parseFloat(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 getAllAttrStage() { let attrs = new Array(); // 有升级的属性 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; } export function getChineseName() { return randomName.generate() } export function getRobotInfo(sysType?: ROBOT_SYS_TYPE) { return { robotRoleName: getChineseName(), robotRoleId: makeRobotId(genCode(8), sysType), } } // 根据roleId判断是不是机器人 export function checkRoleIsRobot(roleId: string) { return !!roleId.match(/_r/); } // 将一般的roleId转为带_r的 export function makeRobotId(roleId: string, sysType?: ROBOT_SYS_TYPE) { if (sysType) { return `${sysType}|${roleId}_r`; } else { return `${roleId}_r`; } } // 获取来源系统 export function getRobotSysType(roleId: string) { let type = roleId.split('|')[0]; if (isNaN(parseInt(type))) { return 0 } else { return parseInt(type); } } // 将一般的roleId去掉_r export function robotIdComBack(robotRoleId: string) { return robotRoleId.replace(/_r/, '') } export function splitString(dataString: string, key: string) { if (!dataString) { return []; } let array = dataString.split(key).filter(obj => { return obj && obj != '' }); let numberArray = []; for (let num of array) { numberArray.push(Number(num)); } return numberArray; } export function isTimestamp(time: number, len = 10) { if (!isNumber(time)) return false; if (time.toString().length != len) return false; return true; } export function getReasonByWarType(warType: number) { switch (warType) { case WAR_TYPE.NORMAL: return ITEM_CHANGE_REASON.NORMAL_BATTLE_END; case WAR_TYPE.VESTIGE: return ITEM_CHANGE_REASON.VESTIGE_BATTLE_END; case WAR_TYPE.EVENT: return ITEM_CHANGE_REASON.EVENT_BATTLE_END; case WAR_TYPE.DAILY: return ITEM_CHANGE_REASON.DAILY_BATTLE_END; case WAR_TYPE.EXPEDITION: return ITEM_CHANGE_REASON.EXPEDITION_BATTLE_END; case WAR_TYPE.MYSTERY: return ITEM_CHANGE_REASON.MYSTERY_BATTLE_END; case WAR_TYPE.COM_BATTLE: return ITEM_CHANGE_REASON.WARLOARDS_BATTLE_END; case WAR_TYPE.TOWER: return ITEM_CHANGE_REASON.TOWER_BATTLE_END; case WAR_TYPE.PVP: return ITEM_CHANGE_REASON.PVP_BATTLE_END; // case WAR_TYPE.GUILD_ACTIVITY: // return ITEM_CHANGE_REASON.GUILD_ACTIVITY_BATTLE_END; case WAR_TYPE.GUILD_TRAIN: return ITEM_CHANGE_REASON.TRAIN_BATTLE_END; case WAR_TYPE.MAIN_ELITE: return ITEM_CHANGE_REASON.MAIN_ELITE_BATTLE_END; // case WAR_TYPE.MYSTERY_ELITE: // return ITEM_CHANGE_REASON.MYSTERY_ELITE_BATTLE_END; case WAR_TYPE.BRANCH: case WAR_TYPE.BRANCH_ELITE: return ITEM_CHANGE_REASON.BRANCH_BATTLE_END; case WAR_TYPE.ACT_TREASURE_HUNT: return ITEM_CHANGE_REASON.ACT_TREASURE_HUNT_BATTLE_END; case WAR_TYPE.ACT_SELF_SHOP: return ITEM_CHANGE_REASON.ACT_SELF_SHOP_BATTLE_END; case WAR_TYPE.ACT_DAILY_GK: return ITEM_CHANGE_REASON.ACT_DAILY_GK_BATTLE_END; case WAR_TYPE.ACT_NEW_HERO_GK: return ITEM_CHANGE_REASON.ACT_NEW_HERO_GK_BATTLE_END; case WAR_TYPE.TRY: return ITEM_CHANGE_REASON.TRY_BATTLE_END; case WAR_TYPE.BOSS: return ITEM_CHANGE_REASON.BOSS_BATTLE_END; case WAR_TYPE.LADDER: return ITEM_CHANGE_REASON.LADDER_BATTLE_REWARD; default: return ITEM_CHANGE_REASON.NORMAL_BATTLE_END; } } export function getWarTypeName(warType: number) { switch (warType) { case WAR_TYPE.NORMAL: return '主线'; case WAR_TYPE.VESTIGE: return '支线'; case WAR_TYPE.EVENT: return '事件'; case WAR_TYPE.DAILY: return '每日'; case WAR_TYPE.EXPEDITION: return '远征'; case WAR_TYPE.MYSTERY: return '秘境'; case WAR_TYPE.COM_BATTLE: return '寻宝'; case WAR_TYPE.TOWER: return '镇念塔'; case WAR_TYPE.PVP: return '竞技'; case WAR_TYPE.GUILD_ACTIVITY: return '军团活动'; case WAR_TYPE.GUILD_TRAIN: return '训练场'; case WAR_TYPE.MAIN_ELITE: return '主线精英'; case WAR_TYPE.BRANCH_ELITE: return '梦魇支线'; case WAR_TYPE.BRANCH: return '支线'; case WAR_TYPE.ACT_TREASURE_HUNT: return '运营活动-神州探秘'; case WAR_TYPE.ACT_SELF_SHOP: return '运营活动-糜家商队'; case WAR_TYPE.ACT_DAILY_GK: return '运营活动-节日活动'; case WAR_TYPE.ACT_NEW_HERO_GK: return '新武将活动关卡'; case WAR_TYPE.TRY: return '试用关卡'; case WAR_TYPE.BOSS: return '演武台'; } } /** * 一群人分总数固定的东西 * @param total 总数 * @param max 每个人能拿到的最大数量 * @param memberCnt 人数 */ export function getRandResultByMember(total: number, max: number, memberCnt: number) { let arr: number[] = []; for (let i = 1; i <= memberCnt; i++) { let randMax = total > max ? max : total; let randMin = total - (memberCnt - i) * max; if (randMin < 0) randMin = 0; if (randMin > max) randMin = max; let rand = getRandValueByMinMax(randMin, randMax + 1, 0); arr.push(rand); total -= rand; } return { arr, remain: total } } //数据格式转换'id&数量|id&数量|' ->> Array 老资源格式 export function stringToRewardInter(rewardStr: string): Array { let result = new Array<{ id: number, count: number }>(); if (!rewardStr) return result; let decodeArr = decodeArrayListStr(rewardStr); 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 addToMap(map: Map, id: T, value: number) { if (!map.has(id)) { map.set(id, value); } else { map.set(id, map.get(id) + value); } } export function arrToMap(arr: T[], getKey: (obj: T) => number | string): Map { let map = new Map(); for (let obj of arr) { let key = getKey(obj); map.set(key, obj); } return map; } // /** // * 计算最强阵容战力 // * @param role // * @param hid // * @param ce // * @param heroId // */ // export async function calculatetopLineup(role: RoleType, hid?: number, ce?: number, heroId?: string) { // let topLineup = role?.topLineup || new Array(); // if(!hid) { // 直接重新排 // let heroes = await HeroModel.getTopHero(role.roleId, LINEUP_NUM); // topLineup = heroes.map(cur => { return { hid: cur.hid, ce: cur.ce, hero: cur._id } }); // } else { // topLineup.sort((a, b) => { return b.ce - a.ce }); // 0-6,最大-最小 // let index = topLineup.findIndex(cur => cur.hid == hid); // if(index != -1 && !heroId) { // let heroes = await HeroModel.getTopHero(role.roleId, LINEUP_NUM); // topLineup = heroes.map(cur => { return { hid: cur.hid, ce: cur.ce, hero: cur._id } }); // } else { // if (index == -1) { // 不在最强列表 // if (topLineup.length < LINEUP_NUM) { // 不满6人 // topLineup.push({ hid, ce, hero: heroId }); // } else if (topLineup.length == LINEUP_NUM) { // if (ce > topLineup[topLineup.length - 1].ce) { // 跻身最强6人 // topLineup.pop(); // topLineup.push({ hid, ce, hero: heroId }); // } // } else { // topLineup.splice(LINEUP_NUM, topLineup.length - LINEUP_NUM); // } // } else { // 原来就是最强6人 // if (ce < topLineup[topLineup.length - 1].ce) { // 滑出最强 // let heroes = await HeroModel.getTopHero(role.roleId, LINEUP_NUM); // topLineup = heroes.map(cur => { return { hid: cur.hid, ce: cur.ce, hero: cur._id } }); // } else { // topLineup[index].ce = ce; // } // } // } // } // let topLineupCe = topLineup.reduce((pre, cur) => { // return pre + cur.ce // }, 0); // return { topLineup, topLineupCe }; // } export function getGachaRemainFloor(gachaId: number, userFloor: Floor[]) { let dicGacha = gameData.gacha.get(gachaId); if(dicGacha.gachaType != GACHA_TYPE.NORMAL && dicGacha.gachaType != GACHA_TYPE.ACTIVITY && dicGacha.gachaType != GACHA_TYPE.TAUTOR) return 0; for (let floorId of dicGacha.floor) { let dicGachaFloor = gameData.gachaFloor.get(floorId); if (dicGachaFloor && dicGachaFloor.floorType == GACHA_FLOOR_TYPE.MAIN_FLOOR) { let myFloor = userFloor.find(cur => cur.id == floorId); return dicGachaFloor.param - (myFloor?.count || 0); } } return 0 } export function isDevelopEnv(env: string) { const envs = ['development', 'monitor', 'alpha', 'dev']; return envs.indexOf(env) != -1; } export function getArrayOfNumber(len: number) { let arr: number[] = []; for (let i = 1; i <= len; i++) arr.push(i); return arr; } // 比较以 . 分隔的版本号。返回 0 则版本号相等,返回正数则 versionA 大,返回负数则 versionB 大 export function compareVersion(versionA: string, versionB: string) { var vA = versionA.split('.'); var vB = versionB.split('.'); for (var i = 0; i < vA.length; ++i) { var a = parseInt(vA[i]); var b = parseInt(vB[i] || '0'); if (a === b) { } else { return a - b; } } if (vB.length > vA.length) { return -1; } else { return 0; } }; // 交换俩obj中的指定字段 export function swapFields(originObj: object, targetObj: object, fieldsToSwap: string[]) { for (const field of fieldsToSwap) { const temp = originObj[field]; originObj[field] = targetObj[field]; targetObj[field] = temp; } } export function compareNumberArray(arrA: number[], arrB: number[]) { if(arrA.length != arrB.length) return false; let sortArrA: number[] = [], sortArrB: number[] = []; for(let a of arrA) sortArrA.push(a); for(let b of arrB) sortArrB.push(b); sortArrA.sort(); sortArrB.sort(); for(let i = 0; i < sortArrA.length; i++) { if(sortArrA[i] != sortArrB[i]) return false; } return true; }