import { ExpeditionPointModel } from '../db/ExpeditionPoint'; import Role, { RoleModel } from '../db/Role'; import { shouldRefresh, getRandSingleEelm } from '../pubUtils/util'; import { EXPEDITION_WAR_RECORD_STATUS, SYSTEM_OPEN_ID } from '../consts'; import { ExpeditionWarRecordModel } from '../db/ExpeditionWarRecord'; import { HeroType } from '../db/Hero'; import { gameData } from '../pubUtils/data'; import { getTimeFunD } from '../pubUtils/timeUtil'; import { ExpeditionRecordModel } from '../db/ExpeditionRecord'; import { Attribute, AttributeCal } from '../domain/roleField/attribute'; import * as dicParam from '../pubUtils/dicParam'; import { getHeroesAttributes, getSumCe } from './playerCeService'; import { checkSystemIsOpen } from './roleService'; /** * 获取远征关卡列表 * @param roleId * @param roleName */ export async function getExpeditionStatus(roleId: string, roleName: string, isEntry = false) { // 重置次数 let role = await RoleModel.findByRoleId(roleId); if(!role.hasInit) return false; if(isEntry && !checkSystemIsOpen(role, SYSTEM_OPEN_ID.EXPEDITION)) return false // 获取远征关卡状态 let expeditionRecord = await ExpeditionRecordModel.getCurRecord(roleId); if (!expeditionRecord) { // 首次新建一条记录 // 我方战力 let myCe = await getSumCe(roleId); expeditionRecord = await ExpeditionRecordModel.createRecord({ roleId, roleName, heroes: [], myCe }); await findOrCreateEnemies(roleId, myCe, expeditionRecord.expeditionCode, 1, EXPEDITION_WAR_RECORD_STATUS.WAITING); } // 每一关的挑战状态 let { expeditionCode, heroes } = expeditionRecord; let expeditionWarRecord = await ExpeditionWarRecordModel.getRecordByCode(expeditionCode); let curLv = 0; if (expeditionWarRecord.length > 0) { curLv = expeditionWarRecord[expeditionWarRecord.length - 1].expeditionId; } let curTime = new Date(); let { resetCnt } = await getResetRemainCnt(curTime, roleId, role); // 点数,和宝箱领取状态 let pointRewards = await getPointRewardStatus(roleId, role); return { expeditionCode, curLv, expeditionWarRecord, pointRewards, heroes: heroes.map(cur => { return { "dataId": cur.seqId, "hp": cur.hp, "ap": cur.ap } }), resetCnt } } /** * 根据存下的战力获取当前远征关卡的对手 * @param roleId 我的id * @param myCe 存在expeditionRecord内的战力(缩过) * @param expeditionCode 远征批次id * @param expeditionId 该关卡id * @param battleStatus 该关卡的挑战状态 */ export async function findOrCreateEnemies(roleId: string, myCe: number, expeditionCode: string, expeditionId: number, battleStatus: number) { let expeditionWarRecord = await ExpeditionWarRecordModel.updateStatus(expeditionCode, expeditionId, battleStatus); if(!expeditionWarRecord) { // 如果没有信息 let curDicExpedition = gameData.expedition.get(expeditionId); if(curDicExpedition) { let enemyObj = { enemyFrom: 0, enemyId: '', enemies: new Array(), ce: 0 }; // 获取系数和步长 let { scale, range, lv } = await getCEScaleAndRange(roleId, curDicExpedition); // 优先匹配其他玩家 let flag = await matchPlayers(roleId, scale, range, myCe, curDicExpedition.json, enemyObj); // 当数量不够时使用机器人匹配 if(!flag) { flag = await matchRobots(scale, myCe, curDicExpedition.ce, curDicExpedition.json, lv, enemyObj); } if(flag) { // 保存 let { warId } = curDicExpedition; let { mapseid } = gameData.war.get(warId); expeditionWarRecord = await ExpeditionWarRecordModel.saveRecord(expeditionCode, expeditionId, { roleId, battleId: warId, mapseid: getRandSingleEelm(mapseid), ...enemyObj, battleStatus }); } } } // 处理当前血量 let {enemiesCurHpAp, enemies} = expeditionWarRecord; for(let enemy of enemies) { let cur = {"hp": 0, "ap": 0}; let getHp = enemiesCurHpAp && enemiesCurHpAp.find(cur => cur.dataId == enemy.dataId); if(getHp) { cur.hp = getHp.hp; cur.ap = getHp.ap; } else { let attr = new Attribute(); attr.setByStr(enemy.attribute); cur.hp = attr.hp; cur.ap = 0; } enemy["cur"] = cur; } return expeditionWarRecord; } /** * 远征关卡匹配玩家 * @param roleId 我的id * @param scale 己方战力和对方战力比 * @param range 浮动范围 * @param myCe 己方战力(已缩小) * @param warJsonIndex 模板出兵表id * @param enemyObj 返回的敌军数据 */ export async function matchPlayers(roleId: string, scale: number, range: number, myCe: number, warJsonIndex:any, enemyObj: {enemyFrom: number, enemyId: string, enemies: Array, ce: number }) { let dicWarJson = gameData.warJson.get(warJsonIndex); let min = myCe * scale * (1 - range/100); let max = myCe * scale * (1 + range/100); let resultRange = await RoleModel.findByCeScale(min, max); resultRange = resultRange.filter(cur => cur.roleId != roleId); if(resultRange.length > 0) { let index = Math.floor(Math.random() * resultRange.length); let role = resultRange[index]; let {roleId, topLineup, topLineupCe } = role; let attrByHid = await getHeroesAttributes(roleId); enemyObj.enemyFrom = 1; enemyObj.enemyId = roleId; enemyObj.ce = topLineupCe; let heroIndex = 0; for(let json of dicWarJson) { if(json.relation == 2) { let hero = topLineup[heroIndex]; if(hero) { let h = hero.hero; if(h) { let { star, lv, ce } = h; let dicHero = gameData.hero.get(hero.hid); let attr = attrByHid.get(hero.hid); let attribute = attr.getAttributesToString(); let heroInfo = { actorId: hero.hid, skinId: h.skinId, actorName: dicHero.name, skill:0, seid:'&', star, spine: 0, attribute, lv, ce }; enemyObj.enemies.push({...json, ...heroInfo}); heroIndex ++; } } } } if(enemyObj.enemies.length <= 0) return false return true; } else { return false } } /** * 匹配远征机器人 * @param scale 己方战力和出兵表配置战力比 * @param myCe 己方战力(已缩小) * @param robotCe 机器人战力(10000,相当于已缩小战力) * @param warJsonIndex 模板出兵表id * @param lv 我的主公等级 * @param enemyObj 返回的敌军数据 */ export async function matchRobots(scale: number, myCe: number, robotCe: number, warJsonIndex: number, lv: number, enemyObj: {enemyFrom: number, enemyId: string, enemies: Array, ce: number }) { let dicWarJson = gameData.warJson.get(warJsonIndex); if(dicWarJson) { enemyObj.enemyFrom = 2; enemyObj.enemyId = warJsonIndex + ''; let allCe = 0; let dicExpeditionSubAttr = gameData.expeditionSubAttr.get(lv); for(let json of dicWarJson) { if(json.relation == 2) { const { attribute, enemyCount } = json; let { attribute: newAttribute, ce } = getRobotAttribute(attribute, enemyCount, dicExpeditionSubAttr.attribute, dicExpeditionSubAttr.lv, myCe, robotCe, scale); enemyObj.enemies.push({...json, skinId: json.actorId, attribute: newAttribute, lv, ce}); allCe += ce; } } enemyObj.ce = Math.floor(allCe); return true } else { return false } } // 远征匹配系数表 export async function getCEScaleAndRange(roleId: string, curDicExpedition: any) { // 匹配,判断是不是新手期 const role = await RoleModel.findByRoleId(roleId); let timef = getTimeFunD(role.createdAt) let isNew = timef.getDayGap() <= 3; let scale = isNew?curDicExpedition.CEScaleNew:curDicExpedition.CEScale; let range = isNew?curDicExpedition.CERangeNew:curDicExpedition.CERange; return {scale, range, lv: role.lv} } // 远征累计点数获取 export async function getPointRewardStatus(roleId: string, role?: Role) { if(!role) { role = await RoleModel.findByRoleId(roleId); } let {expeditionPoint = 0} = role; let dicExpeditionPoint = gameData.expeditionPoint; let rewards: { point: number, received: boolean }[] = []; for(let [point] of dicExpeditionPoint) { rewards.push({ point, received: false }) } let pointRewards = { expeditionPoint, rewards }; let pointStatusInDatabase = await ExpeditionPointModel.getExpeditionPoint(roleId); if(pointStatusInDatabase) { let { rewards = [] } = pointStatusInDatabase; pointRewards.rewards.forEach(cur => { let obj = rewards.find(ccur => ccur.point == cur.point); if(obj) cur.received = obj.received; }); } return pointRewards } export async function getResetRemainCnt(curTime: Date, roleId: string, role?: Role, ) { if(!role) { role = await RoleModel.findByRoleId(roleId); } let { expeditionResetCnt, expeditionResetRefTime } = role; let needRefresh = !expeditionResetRefTime || shouldRefresh(expeditionResetRefTime, curTime); if(needRefresh) { expeditionResetCnt = 0; expeditionResetRefTime = curTime; } let maxCnt = dicParam.EXPEDITION_CONST.EXPEDITION_CONST_TIMES; return { resetCnt: maxCnt - expeditionResetCnt, needRefresh }; } /** * 根据比例计算机器人属性 * @param attribute 出兵表中的属性字段 * @param ce 我的战力 * @param enemyCe 出兵表对手战力 * @param ratio 系数 */ export function getRobotAttribute(mainAttrs: { id: number, val: number }[], enemyCount: number, subAttrs: {id: number, val: number}[], lv: number, ce: number, enemyCe: number, ratio: number) { let newAttribute = new AttributeCal(); newAttribute.setLv(lv); newAttribute.setByWarJson(subAttrs); // 次级属性 let subAttrCe = newAttribute.calSubAttrCe() * enemyCount; if(ce * ratio > subAttrCe) { let mainAttrCe = ce * ratio - subAttrCe; newAttribute.setByWarJson(mainAttrs, mainAttrCe / enemyCe); let attrArr = newAttribute.getAttributesToString(); let newCe = newAttribute.calCe(); return { attribute: attrArr, ce: newCe }; } else { newAttribute = new AttributeCal(); newAttribute.setByWarJson(mainAttrs, ce * ratio / enemyCe); let attrArr = newAttribute.getAttributesToString(); let newCe = newAttribute.calCe(); return { attribute: attrArr, ce: newCe }; } }