From 5823a1b3eb0e77dfb0e51d9b445537dd7f65c56b Mon Sep 17 00:00:00 2001 From: luying Date: Thu, 14 Jan 2021 15:57:05 +0800 Subject: [PATCH] =?UTF-8?q?fix=20pvp=E5=88=B7=E6=96=B0=E5=AF=B9=E6=89=8B?= =?UTF-8?q?=E6=97=B6=E4=BF=9D=E5=AD=98=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/servers/battle/handler/pvpHandler.ts | 60 ++--- .../app/services/playerEventService.ts | 2 - game-server/app/services/pvpService.ts | 238 +++++++++--------- package.json | 1 + shared/db/ExpeditionWarRecord.ts | 40 +-- shared/db/PvpDefense.ts | 31 +-- shared/db/PvpHistoryOpp.ts | 67 +++++ shared/db/PvpRecord.ts | 12 + shared/db/generalField.ts | 124 +++++++++ shared/pubUtils/interface.ts | 12 +- shared/pubUtils/util.ts | 6 +- 11 files changed, 372 insertions(+), 221 deletions(-) create mode 100644 shared/db/PvpHistoryOpp.ts diff --git a/game-server/app/servers/battle/handler/pvpHandler.ts b/game-server/app/servers/battle/handler/pvpHandler.ts index aa3004c4b..60b7b2a70 100644 --- a/game-server/app/servers/battle/handler/pvpHandler.ts +++ b/game-server/app/servers/battle/handler/pvpHandler.ts @@ -1,26 +1,27 @@ import {Application, BackendSession, pinus} from 'pinus'; import { uniq, findWhere, findIndex } from 'underscore'; import { gameData, getPvpBoxs } from '../../../pubUtils/data'; -import { refreshEnemies, getEnemies, getLvByScore, defaultHeroes, comsumeChallengeCnt, refresh, findPvpDefByRoleId, checkRoleIsRobot, getRefOppCnt, findPvpDefAllByRoleId, generPVPOppRecInfo, generMyRecInfo, getRobotLineup, getPlayerLineup } from '../../../services/pvpService'; +import { refreshEnemies, getEnemies, getLvByScore, defaultHeroes, comsumeChallengeCnt, refresh, findPvpDefByRoleId, checkRoleIsRobot, getRefOppCnt, findPvpDefAllByRoleId, generPVPOppRecInfo, generMyRecInfo } from '../../../services/pvpService'; import { RoleModel, RoleType } from '../../../db/Role'; import { STATUS } from '../../../consts/statusCode'; import { resResult, genCode } from '../../../pubUtils/util'; -import { SystemConfigModel } from '../../../db/SystemConfig' import { PvpDefenseModel, OppPlayers } from '../../../db/PvpDefense'; -import { oppHeroesDefenseInter, pvpEndParamInter, RankParam, PlayerDetail, PlayerDetailHero } from '../../../pubUtils/interface'; +import { pvpEndParamInter, RankParam, PlayerDetail, PlayerDetailHero } from '../../../pubUtils/interface'; import { PVP_HERO_POS, REDIS_KEY } from '../../../consts'; import { PVP } from '../../../pubUtils/dicParam'; import { addItems } from '../../../services/rewardService'; import { HeroModel } from '../../../db/Hero'; import { checkBattleHeroesByHid } from '../../../services/normalBattleService'; import { BattleRecordModel } from '../../../db/BattleRecord'; -import { PvpRecordModel, HeroesRecord } from '../../../db/PvpRecord'; +import { PvpRecordModel } from '../../../db/PvpRecord'; import { existsRank, initRank, getRank, setRank, getMyRank } from '../../../services/redisService'; import { handleCost } from '../../../services/rewardService'; import { nowSeconds } from '../../../pubUtils/timeUtil'; import { setPvpSeasonResult, resetPvpWarId, resetPvpSeasonTime } from '../../../services/timeTaskService'; import { PvpSeasonResultModel } from '../../../db/PvpSeasonResult'; +import { PvpHistoryOppModel, PvpHistoryOppType } from '../../../db/PvpHistoryOpp'; + export default function(app: Application) { return new PvpHandler(app); } @@ -158,22 +159,13 @@ export class PvpHandler { let oppoRoleId = msg.roleId; let pvpDefense = await PvpDefenseModel.findByRoleIdIncludeAll(roleId); let { oppPlayers } = pvpDefense; - let role = pvpDefense.role; let curOpp = oppPlayers.find(cur => cur.roleId == oppoRoleId); if(!curOpp) return resResult(STATUS.PVP_ROLE_NOT_FOUND); - let system = await SystemConfigModel.findSystemConfig(); - let mapWarJson = gameData.warJson.get(system.warId); + let { oppRoleId, heroes } = curOpp.oppDef; - let heroes = new Array(); - if(curOpp.isRobot) { // 机器人 - heroes = await getRobotLineup(mapWarJson, curOpp, role.topFiveCe, role.lv); - } else { // 真人 - heroes = await getPlayerLineup(mapWarJson, curOpp); - } - - return resResult(STATUS.SUCCESS, { roleId: oppoRoleId, pos: curOpp.pos, heroes }); + return resResult(STATUS.SUCCESS, { roleId: oppRoleId, pos: curOpp.pos, heroes }); } // 开战 @@ -287,6 +279,9 @@ export class PvpHandler { await setRank(REDIS_KEY.PVP_RANK, 0, roleId, pvpDefense.score, pvpDefense.updatedAt.getTime(), params); let myRank = await getMyRank(REDIS_KEY.PVP_RANK, 0, roleId); + // 对手记录更新 + await PvpHistoryOppModel.setStatus(roleId, oppRoleId, 1); + return resResult(STATUS.SUCCESS, { battleCode, isSuccess, score, pLv, myRank, hisScore, @@ -386,34 +381,17 @@ export class PvpHandler { let result: PlayerDetail; if(isRobot) { // 如果是机器人,从自己的pvpDefense中寻找 - let role = await RoleModel.findByRoleId(roleId); - let pvpDefense = await PvpDefenseModel.findByRoleId(roleId); - let { oppPlayers } = pvpDefense; - let curOpp = oppPlayers.find(cur => cur.roleId == oppoRoleId); - if(!curOpp) return resResult(STATUS.PVP_ROLE_NOT_FOUND); - - let heroes = new Array(); - - let { robot } = curOpp; - let { warId } = robot; - let dicWarJson = gameData.warJson.get(warId); - - for(let json of dicWarJson) { - const { actorId, relation } = json; - if(relation == 2 && actorId > 0) { // 默认格子 - let dicHero = gameData.hero.get(actorId); - heroes.push({ - actorId, - star: dicHero.initialStars, - colorStar: 0, - quality: dicHero.quality, - score: 0, - lv: role.lv - }); - } + let pvpHistoryOpp = await PvpHistoryOppModel.findByRoleIdAndOppId(roleId, oppoRoleId); + if(!pvpHistoryOpp) { + return resResult(STATUS.PVP_ROLE_NOT_FOUND); } - result = new PlayerDetail({...robot, lv: role.lv, heroes}) + let heroes = pvpHistoryOpp.heroes.map(hero => { + let newHero = new PlayerDetailHero(); + newHero.setPvpHeroInfo(hero); + return newHero; + }) + result = new PlayerDetail({...pvpHistoryOpp, roleId: pvpHistoryOpp.oppRoleId, heroes}); } else { // 查询对方pvpDefense let pvpDefense = await PvpDefenseModel.findByRoleId(oppoRoleId); let dbHeroes = await HeroModel.findByRole(oppoRoleId); diff --git a/game-server/app/services/playerEventService.ts b/game-server/app/services/playerEventService.ts index 30bd327d8..7ccebffb7 100644 --- a/game-server/app/services/playerEventService.ts +++ b/game-server/app/services/playerEventService.ts @@ -1,10 +1,8 @@ -import { fromCallback } from 'bluebird'; import { checkPvp, findPvpDefByRoleId } from '../services/pvpService' import { getFuncsSwitch } from '../pubUtils/data'; import { FUNCS_ID, FUNC_OPT_TYPE } from '../consts/constModules/sysConst'; import { RoleModel } from '../db/Role'; -import { startEvent } from "./eventSercive"; export async function eventOnPlayerLvUp(roleId: string, lv: number, addFuncs: Array, dataFuncs: Array) { diff --git a/game-server/app/services/pvpService.ts b/game-server/app/services/pvpService.ts index 24cac0efa..b6644d35f 100644 --- a/game-server/app/services/pvpService.ts +++ b/game-server/app/services/pvpService.ts @@ -4,7 +4,7 @@ import { RoleType, RoleModel } from '../db/Role'; import { PVP_HERO_POS, ROBOT_NAME, REDIS_KEY, PVP_CONST } from '../consts'; import { setPvpDefResult } from '../services/timeTaskService'; import { dicPvpOpponent, DicPvpOpponent } from "../pubUtils/dictionary/DicPvpOpponent"; -import { getRandomIndexByLen, genCode, getRandomByLen, shouldRefresh, reduceCe } from '../pubUtils/util'; +import { getRandomIndexByLen, genCode, getRandomByLen, shouldRefresh, reduceCe, getChineseName } from '../pubUtils/util'; import { oppPlayersInter, RankParam, pvpEndParamInter, oppHeroesDefenseInter, Attributes } from '../pubUtils/interface'; import { gameData, getPLvByScore } from "../pubUtils/data"; import { PVP } from '../pubUtils/dicParam'; @@ -13,11 +13,11 @@ import { setRank, getMyRank, getFieldByRank } from './redisService'; import { nowSeconds, checkTodayTime } from '../pubUtils/timeUtil'; import { HeroesRecord } from '../db/PvpRecord'; import { HeroModel, HeroType } from '../db/Hero'; -import { CeAttrNumber, CeAttr, CeAttrRole } from '../db/generalField'; +import { CeAttrNumber, CeAttr, CeAttrRole, PvpEnemies, PvpHeroInfo } from '../db/generalField'; import { DicWarJson } from '../pubUtils/dictionary/DicWarJson'; import { findWhere, findIndex } from 'underscore'; import { pinus } from 'pinus'; - +import { PvpHistoryOppModel, PvpHistoryOppType } from '../db/PvpHistoryOpp'; export async function initPvpInfo(role: RoleType) { let heroes: Array = []; @@ -62,47 +62,39 @@ export async function checkPvp(role: RoleType) { * @param pLv 玩家本人的队伍等级 */ export async function getEnemies(oppPlayers: OppPlayers[], winStreakNum: number) { + let result = new Array(); - for(let {pos, isRobot, oppDef, robot} of oppPlayers) { - let dicOpponent = dicPvpOpponent.get(pos); - if(isRobot) { - let { roleId, roleName, headHid, sHid, pLv, defCe } = robot; - result.push({ - pos, roleId, roleName, headHid, sHid, pLv, defCe: reduceCe(defCe), - addScore: dicOpponent.score, - rankLv: 0, - plusScore: getPlusScore(winStreakNum) - }); - } else { - let opp = oppDef; - let role = opp.role; - let { roleId, roleName, headHid, sHid, lv } = role; - let { pLv, defCe } = opp; - let rankLv = await getMyRank(REDIS_KEY.PVP_RANK, 0, roleId); - result.push({ - pos, roleId, roleName, headHid, sHid, pLv, defCe: reduceCe(defCe), - addScore: dicOpponent.score, - rankLv, // 读取排名 - plusScore: getPlusScore(winStreakNum) - }); - } + for(let oppPlayer of oppPlayers) { + let dicOpponent = dicPvpOpponent.get(oppPlayer.pos); + let oppDef = oppPlayer.oppDef; // select 'oppRoleId pos roleName headHid sHid rankLv pLv defCe' + result.push({ + ...oppDef, + roleId: oppDef.oppRoleId, + defCe: reduceCe(oppDef.defCe), + addScore: dicOpponent.score, + rankLv: 0, + plusScore: getPlusScore(winStreakNum) + }); } return result } // 刷新对手 export async function refreshEnemies(role: RoleType, score: number, pLv: number) { - let { roleId, topFiveCe } = role; + let system = await SystemConfigModel.findSystemConfig(); + let mapWarJson = gameData.warJson.get(system.warId); + + let { roleId } = role; let oppPlayers = new Array(); let opp = dicPvpOpponent.values() for(let dicOpp of opp) { let flag = false; // 是否筛选成功 - if(score >= PVP_CONST.SCORE_LINE) { // TODO 将这个放到const - flag = await matchPlayer(oppPlayers, roleId, pLv, dicOpp); - if(!flag) flag = await matchPlayerByRank(oppPlayers, roleId, dicOpp.id); // 当前后分数段没有时,返回前一名的玩家 - if(!flag) flag = matchRobot(oppPlayers, topFiveCe, pLv, dicOpp); + if(score >= PVP_CONST.SCORE_LINE) { // 将这个放到const + flag = await matchPlayer(oppPlayers, mapWarJson, roleId, pLv, dicOpp); // 按照等级匹配对手 + if(!flag) flag = await matchPlayerByRank(oppPlayers, mapWarJson, roleId, dicOpp.id); // 当前后分数段没有时,返回前一名的玩家 + if(!flag) flag = await matchRobot(oppPlayers, mapWarJson, role, pLv, dicOpp); } else { - flag = matchRobot(oppPlayers, topFiveCe, pLv, dicOpp); + flag = await matchRobot(oppPlayers, mapWarJson, role, pLv, dicOpp); } if(!flag) continue; } @@ -110,7 +102,7 @@ export async function refreshEnemies(role: RoleType, score: number, pLv: number) return oppPlayers; } -export async function matchPlayerByRank(oppPlayers: OppPlayers[], roleId: string, pos: number) { +export async function matchPlayerByRank(oppPlayers: OppPlayers[], mapWarJson: DicWarJson[], roleId: string, pos: number) { let ridRanks = new Array(); // 已经被使用了的排名 for(let { roleId: curRoleId } of oppPlayers) { let rankLv = await getMyRank(REDIS_KEY.PVP_RANK, 0, curRoleId); @@ -146,17 +138,18 @@ export async function matchPlayerByRank(oppPlayers: OppPlayers[], roleId: string oppRoleId = result[0]; let pvpdefense = await PvpDefenseModel.findByRoleId(oppRoleId); + let pvpHistoryOpp = await generPlayerOppHis(pvpdefense, mapWarJson, roleId, pos); + oppPlayers.push({ roleId: pvpdefense.roleId, - oppDef: pvpdefense._id, + oppDef: pvpHistoryOpp._id, pos, isRobot: false, - robot: null }); return true } -async function matchPlayer(oppPlayers: OppPlayers[], roleId: string, pLv: number, dicOpp: DicPvpOpponent ) { +async function matchPlayer(oppPlayers: OppPlayers[], mapWarJson: DicWarJson[], roleId: string, pLv: number, dicOpp: DicPvpOpponent ) { let { id: pos, minLv, maxLv } = dicOpp let range = await PvpDefenseModel.findByTeamLv(pLv + minLv, pLv + maxLv); range = range.filter(cur => { @@ -165,7 +158,7 @@ async function matchPlayer(oppPlayers: OppPlayers[], roleId: string, pLv: number if(range.length <= 0) return false; let index = getRandomIndexByLen(range.length); - let result = range[index]; + let result = range[index]; // 本次匹配结果 pvpdefense if(!result) return false; if(result.roleId == roleId) { range.splice(index, 1); @@ -173,18 +166,54 @@ async function matchPlayer(oppPlayers: OppPlayers[], roleId: string, pLv: number index = getRandomIndexByLen(range.length); result = range[index]; } - + let pvpHistoryOpp = await generPlayerOppHis(result, mapWarJson, roleId, pos); oppPlayers.push({ roleId: result.roleId, - oppDef: result._id, + oppDef: pvpHistoryOpp._id, pos, isRobot: false, - robot: null }); return true; } -function matchRobot(oppPlayers: OppPlayers[], myCe: number, pLv: number, dicOpp: DicPvpOpponent) { +/** + * @description 对手是玩家时,生成并返回pvpHistoryOpp + * @param result 随机出的对手pvpDefense + * @param mapWarJson 本周地图出兵表 + * @param roleId 自己的玩家id + * @param pos 刷新这个对手的位置 + */ +async function generPlayerOppHis(result: PvpDefenseType, mapWarJson: DicWarJson[], roleId: string, pos: number) { + let heroScores = result.heroScores; + let role = result.role; + let rankLv = await getMyRank(REDIS_KEY.PVP_RANK, 0, role.roleId); + let heroes = new Array(); + for(let warJson of mapWarJson) { + if(warJson.relation == 1) continue; + let h = result.heroes.find(cur => cur.dataId == warJson.dataId); + if(h) { + let hs = heroScores.find(cur => cur.hid == warJson.actorId); // 这个武将的军功 + let hero = h.hero; + let heroInfo = new PvpHeroInfo(); + heroInfo.setHeroInfo(hero); + heroInfo.setOutIndex(h.order); + let attribute = getPlayerAttribute(hero.ceAttr, role.globalCeAttr); + heroInfo.setAttribute(attribute); + let enemy = new PvpEnemies(warJson, heroInfo, hs?hs.score: 0); + heroes.push(enemy); + } else { + let enemy = new PvpEnemies(warJson, new PvpHeroInfo(), 0); + heroes.push(enemy); + } + } + let pvpHistoryOpp = await PvpHistoryOppModel.createPvpOpp({ + ...result, ...role, pos, rankLv, heroes, roleId, oppRoleId: result.roleId + }); + return pvpHistoryOpp; +} + +async function matchRobot(oppPlayers: OppPlayers[], mapWarJson: DicWarJson[], role: RoleType, pLv: number, dicOpp: DicPvpOpponent) { + let { lv: myLv, topFiveCe: myCe, roleId } = role; let { id: pos, minLv, maxLv, ratio } = dicOpp; let range = gameData.pvpWar; if(range.length <= 0) return false; @@ -193,17 +222,41 @@ function matchRobot(oppPlayers: OppPlayers[], myCe: number, pLv: number, dicOpp: let result = range[index]; if(!result) return false; - let roleId = generateRobotRoleId(); - let roleName = getRandomByLen(ROBOT_NAME); + let robotWarjson = gameData.warJson.get(result.war_id); + if(!robotWarjson) { /* TODO 判空处理 */ } + let heroes = new Array(); + for(let warJson of mapWarJson) { + if(warJson.relation == 1) continue; + let h = robotWarjson.find(cur => cur.dataId == warJson.dataId); + if(h) { + let dicHero = gameData.hero.get(h.actorId); + if(!dicHero) continue; + let heroInfo = new PvpHeroInfo(); + heroInfo.setRobotInfo(h, myLv, dicHero.initialStars, dicHero.quality); + let attribute = getRobotAttribute(h.attribute, myCe, PVP_CONST.ENEMY_CE, ratio); + heroInfo.setAttribute(attribute); + let enemy = new PvpEnemies(warJson, heroInfo, 0); + heroes.push(enemy); + } else { + let enemy = new PvpEnemies(warJson, new PvpHeroInfo(), 0); + heroes.push(enemy); + } + } + + let oppRoleId = generateRobotRoleId(); + let roleName = getChineseName(); let hisPLv = Math.floor(pLv + (minLv + maxLv)/2); if(hisPLv < 1) hisPLv = 1 - let robot = new Robot(roleId, roleName, Math.floor(myCe * ratio), hisPLv, result.war_id) + + let pvpHistoryOpp = await PvpHistoryOppModel.createPvpOpp({ + roleId, oppRoleId, roleName, pos, defCe: Math.floor(myCe * ratio), pLv: hisPLv, lv: myLv, heroes + }); + oppPlayers.push({ - roleId, - oppDef: null, + roleId: oppRoleId, + oppDef: pvpHistoryOpp._id, pos, - isRobot: true, - robot + isRobot: true }); return true } @@ -386,10 +439,10 @@ export async function findPvpDefAllByRoleId(roleId: string) { let role = pvpDefense.role; let oppPlayers = await refreshEnemies(role, pvpDefense.score, pvpDefense.pLv); update.oppPlayers = oppPlayers; - pvpDefense.oppPlayers = oppPlayers; } - await PvpDefenseModel.updateInfo( roleId, update); + let updateResult = await PvpDefenseModel.updateInfoAndInclude( roleId, update); + pvpDefense.oppPlayers = updateResult.oppPlayers; pvpDefense.challengeCnt = challengeCnt; pvpDefense.challengeRefTime = challengeRefTime; pvpDefense.refOppCnt = refOppCnt; @@ -399,52 +452,13 @@ export async function findPvpDefAllByRoleId(roleId: string) { return {pvpDefense, warId, shouldRefOpp}; } -// 获取机器人阵容 -export async function getRobotLineup(mapWarJson: DicWarJson[], curOpp: OppPlayers, topFiveCe: number, lv: number) { - let heroes = new Array(); - let { pos, robot } = curOpp; - let { warId } = robot; - let dicWarJson = gameData.warJson.get(warId); - let dicOpp = gameData.pvpOpponent.get(pos); - for(let json of dicWarJson) { - let curDicMapJson = mapWarJson.find(cur => cur.dataId == json.dataId); - const { actorId, actorName, attribute, skill, seid, star, spine, relation } = json; - - if(relation == 2 && actorId > 0) { // 默认格子 - let newAttribute = getRobotAttribute(attribute, topFiveCe, PVP_CONST.ENEMY_CE, dicOpp.ratio); - let heroInfo = { actorId, actorName, skill, seid, star, spine, attribute: newAttribute, lv }; - heroes.push({ - ...curDicMapJson, ...heroInfo - }); - } - } - return heroes -} - -// 获取阵容阵容 -export async function getPlayerLineup(mapWarJson: DicWarJson[], curOpp: OppPlayers, ) { - let heroes = new Array(); - - let oppDef = curOpp.oppDef; - let role = oppDef.role; - let { globalCeAttr } = role; - for(let { actorId, hero, dataId, order } of oppDef.heroes) { - if(actorId > 0) { - let curDicMapJson = mapWarJson.find(cur => cur.dataId == dataId); - let dicHero = gameData.hero.get(actorId); - let h = hero; - let { ceAttr } = h; - let newAttribute = getPlayerAttribute(ceAttr, globalCeAttr); - let heroInfo = { outIndex: order, actorId, actorName: dicHero.name, skill:0, seid:'&', star: h.star, spine: 0, attribute: newAttribute, lv: h.lv }; - heroes.push({ - ...curDicMapJson, ...heroInfo - }); - } - } - return heroes -} - -// 按比例计算出兵表中的属性 +/** + * 根据比例计算机器人属性 + * @param attribute 出兵表中的属性字段 + * @param ce 我的战力 + * @param enemyCe 出兵表对手战力 + * @param ratio 系数 + */ export function getRobotAttribute(attribute: Attributes, ce: number, enemyCe: number, ratio: number) { let newAttribute = new CeAttrNumber(); @@ -457,7 +471,11 @@ export function getRobotAttribute(attribute: Attributes, ce: number, enemyCe: nu return newAttribute; } -// 计算玩家的属性 +/** + * @description 根据玩家数据获取到他的属性 + * @param ceAttr hero表的ceAttr + * @param globalCeAttr role表中的globalCeAttr + */ export function getPlayerAttribute(ceAttr: CeAttr, globalCeAttr: CeAttrRole) { let newAttribute = new CeAttrNumber(); for(let attrName in newAttribute) { @@ -529,27 +547,15 @@ export async function generMyRecInfo(heroScores: HeroScores[], winStreakNum: num // 获取对手战报记录 export async function generPVPOppRecInfo(isSuccess: boolean, curOpp: OppPlayers, oppRoleId: string, oppHeroes: pvpEndParamInter[], myLv: number) { let oppHeroRecords = new Array(); + let oppRole = curOpp.oppDef; + if(!oppRole) { /* TODO 判空处理 */ } for (let { hid, damage, heal, underDamage } of oppHeroes) { - if (curOpp.isRobot) { - let dicHero = gameData.hero.get(hid); - let { quality, initialStars: star } = dicHero; - oppHeroRecords.push({ - hid, quality, star, colorStar: 0, lv: 0, damage, heal, underDamage - }); - } else { - const myHero = await HeroModel.findByHidAndRole(hid, oppRoleId, 'quality star colorStar lv'); - let { quality, star, colorStar, lv } = myHero; - oppHeroRecords.push({ - hid, quality, star, colorStar, lv, damage, heal, underDamage - }); + let historyHero = oppRole.heroes.find(cur => cur.actorId == hid); + if(historyHero) { + let hs = new HeroesRecord(historyHero, damage, heal, underDamage); + oppHeroRecords.push(hs); } } - let oppRole; - if (curOpp.isRobot) { - oppRole = { ...curOpp.robot, title: 1, topFiveCe: curOpp.robot.defCe, lv: myLv }; - } else { - oppRole = await RoleModel.findByRoleId(oppRoleId); - } return { roleId: oppRole.roleId, roleName: oppRole.roleName, @@ -557,7 +563,7 @@ export async function generPVPOppRecInfo(isSuccess: boolean, curOpp: OppPlayers, sHid: oppRole.sHid, headHid: oppRole.headHid, title: oppRole.title, - ce: oppRole.topFiveCe, + ce: oppRole.defCe, heroes: oppHeroRecords, isSuccess: !isSuccess, score: 0 diff --git a/package.json b/package.json index f233c085c..0f799db7b 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "@typegoose/typegoose": "^7.3.5", "@types/mongoose": "^5.7.36", "bcrypt": "^5.0.0", + "chinese-random-name": "^1.0.0", "lodash": "^4.17.20", "moment": "^2.27.0", "mongoose": "^5.10.4", diff --git a/shared/db/ExpeditionWarRecord.ts b/shared/db/ExpeditionWarRecord.ts index 77097ad38..ac7b9e761 100644 --- a/shared/db/ExpeditionWarRecord.ts +++ b/shared/db/ExpeditionWarRecord.ts @@ -1,44 +1,8 @@ import BaseModel from './BaseModel'; import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; import { EXPEDITION_WAR_RECORD_STATUS } from '../consts'; +import { Enemies } from './generalField' -class Enemies { - @prop({ required: true }) - actorId: number; // 敌人id - @prop({ required: false }) - actorName: string; // 敌人名 - @prop({ required: false }) - dataId: number; // 战场中唯一指向武将的代码 - @prop({ required: false }) - relation: number; // 角色属于我方还是地方 - @prop({ required: false }) - outIndex: number; // 程序将信息存入数组顺序 - @prop({ required: false }) - x: number; // 战场x坐标 - @prop({ required: false }) - y: number; // 战场y坐标 - @prop({ required: false }) - direction: number; // 朝向 - @prop({ required: false }) - var: number; // 变量 - @prop({ required: false }) - lv: number; // 角色等级 - @prop({ required: false }) - hide: number; // 是否隐藏 - @prop({ required: false }) - initial_ai: number; // AI类型 - @prop({ required: true }) - attribute: {hp: number, atk: number, matk: number, def: number, mdef: number, agi: number, luk: number, speed: number, hit: number, cri: number, flee: number, antCri: number, damageIncrease: number, damageDecrease: number, defIgnore: number, bloodSuck: number, ap: number}; // 属性 - @prop({ required: false }) - skill: string; // 技能 - @prop({ required: false }) - seid: string; // 技能 - @prop({ required: false }) - star: number; // 角色星级 - @prop({ required: false }) - spine: string; // S动画 - -} class EnemiesCurHPAP { @prop({ required: true }) @@ -72,7 +36,7 @@ export default class ExpeditionWarRecord extends BaseModel { @prop({ required: true, default: '' }) enemyId: string; // 敌军队伍id或玩家id @prop({ required: true, type: Enemies, default: [], _id: false }) - enemies: Array; // 敌军数据 + enemies: Array; // 敌军数据 @prop({ required: true, type: EnemiesCurHPAP, default: [], _id: false }) enemiesCurHpAp: Array; // 敌军数据 @prop({ required: true, default: 0 }) diff --git a/shared/db/PvpDefense.ts b/shared/db/PvpDefense.ts index 33b68f925..2a52bccd4 100644 --- a/shared/db/PvpDefense.ts +++ b/shared/db/PvpDefense.ts @@ -2,8 +2,8 @@ import BaseModel from './BaseModel'; import { index, getModelForClass, prop, DocumentType, Ref, mongoose } from '@typegoose/typegoose'; import Hero, { } from './Hero'; import Role, { } from './Role'; -import PvpDef, { } from './PvpDefense'; import { PVP_PLAYER_POS, PVP_HERO_POS } from '../consts'; +import PvpHistoryOpp from './PvpHistoryOpp'; export interface pvpUpdateInter { _id?: string; @@ -91,14 +91,12 @@ export class Robot { export class OppPlayers { @prop({ required: true }) roleId: string; - @prop({ ref: 'PvpDefense', type: mongoose.Schema.Types.ObjectId }) - oppDef: Ref; + @prop({ ref: 'PvpHistoryOpp', type: mongoose.Schema.Types.ObjectId }) + oppDef: Ref; @prop({ required: true }) pos: number; @prop({ required: true }) isRobot: boolean; - @prop({ required: true, type: Robot, default: null, _id: false }) - robot: Robot } export class HeroScores { @@ -136,7 +134,7 @@ export default class PvpDefense extends BaseModel { isDefaultHero: boolean; @prop({ required: true, default: 0 }) refOppCnt: number; // 刷新对手总次数,消耗可根据消耗表算出 - @prop({ required: true, default: 0 }) + @prop({ required: true, default: new Date() }) refOppTime: Date; // 刷新对手时间 @prop({ required: true, default: 0 }) challengeCnt: number; // 可挑战次数 @@ -159,7 +157,7 @@ export default class PvpDefense extends BaseModel { public static async findByScale(roleId: string, min: number, max: number, lean = true) { const result: PvpDefenseType[] = await PvpDefenseModel.find({ roleId: { $ne: roleId }, defCe: { $lte: max, $gte: min } }) - .populate('role', 'headHid sHid topFiveCe roleId roleName') + .populate('role', 'headHid sHid topFiveCe roleId roleName lv') .populate('heroes.hero') .sort({ updatedAt: -1 }).limit(100).lean(lean); return result; @@ -203,15 +201,9 @@ export default class PvpDefense extends BaseModel { public static async findByRoleIdIncludeAll(roleId: string) { const result: PvpDefenseType = await PvpDefenseModel.findOne({ roleId }) - .populate('role', 'headHid sHid topFiveCe roleId roleName') + .populate('role', 'headHid sHid topFiveCe roleId roleName lv') .populate('heroes.hero') - .populate({ - path: 'oppPlayers.oppDef', - populate: { - path: 'role heroes.hero', - select: 'headHid sHid topFiveCe roleId roleName hid ceAttr globalCeAttr' - } - }).lean(); + .populate('oppPlayers.oppDef', 'oppRoleId pos roleName headHid sHid rankLv pLv defCe heroes').lean(); return result; } @@ -223,13 +215,8 @@ export default class PvpDefense extends BaseModel { public static async updateInfoAndInclude(roleId: string, update: pvpUpdateInter) { delete update._id; let result: PvpDefenseType = await PvpDefenseModel.findOneAndUpdate({roleId}, {$set:update}, {new: true}) - .populate({ - path: 'oppPlayers.oppDef', - populate: { - path: 'role', - select: 'headHid sHid topFiveCe roleId roleName' - } - }).lean(); + .populate('role', 'headHid sHid topFiveCe roleId roleName lv') + .populate('oppPlayers.oppDef', 'oppRoleId pos roleName headHid sHid rankLv pLv defCe').lean(); return result; } public static async updateInfo(roleId: string, update: pvpUpdateInter, lean = true) { diff --git a/shared/db/PvpHistoryOpp.ts b/shared/db/PvpHistoryOpp.ts new file mode 100644 index 000000000..3b4b9c7cb --- /dev/null +++ b/shared/db/PvpHistoryOpp.ts @@ -0,0 +1,67 @@ +import BaseModel from './BaseModel'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; + +import { PvpEnemies } from './generalField'; + +export class HeroScores { + @prop({ required: true }) + hid: number; + @prop({ required: true }) + score: number; +} + +@index({ roleId: 1 }) +export default class PvpHistoryOpp extends BaseModel { + @prop({ required: true }) + roleId: string; // 玩家id + @prop({ required: true }) + pos: number; // 对手位置 + @prop({ required: true }) + oppRoleId: string; // 对手角色 id + @prop({ required: true }) + roleName: string; // 角色名称 + @prop({ required: true, default: 19 }) + headHid: number; // 对手头像 + @prop({ required: true, default: 19 }) + sHid: number; // 对手形象 + @prop({ required: true, default: 0 }) + score: number; // 对手军功 + @prop({ required: true, default: 1 }) + pLv: number; // 对手等级 + @prop({ required: true, default: 1 }) + lv: number; // 对手角色等级 + @prop({ required: true, default: 1 }) + title: number; // 对手等级 + @prop({ required: true, default: 0 }) + defCe: number; // 防守战力 + @prop({ required: true, default: 0 }) + rankLv: number; // 对手排名 + @prop({ required: true, type: PvpEnemies, default: [] }) + heroes: PvpEnemies[]; // 对手阵容 + @prop({ required: true, default: 0 }) + status: number; // 状态 0-仅刷出 1-挑战过 + + public static async createPvpOpp(params: PvpOppCreateParam, lean = true) { + const doc = new PvpHistoryOppModel(); + const update = Object.assign(doc.toJSON(), params); + delete update._id; + const defense: PvpHistoryOppType = await PvpHistoryOppModel.findOneAndUpdate({ roleId: params.roleId, pos: params.pos }, update, { upsert: true, new: true }).lean(lean); + return defense; + } + + public static async findByRoleIdAndOppId(roleId: string, oppRoleId: string) { + const result: PvpHistoryOppType = await PvpHistoryOppModel.findOne({ roleId, oppRoleId, status: 0 }).lean(); + return result; + } + + public static async setStatus(roleId: string, oppRoleId: string, status: number) { + const result: PvpHistoryOppType = await PvpHistoryOppModel.findOneAndUpdate({ roleId, oppRoleId }, {status}, {new: true}).lean(); + return result; + } + +} + +export const PvpHistoryOppModel = getModelForClass(PvpHistoryOpp); + +export interface PvpHistoryOppType extends Pick, keyof PvpHistoryOpp> { }; +export type PvpOppCreateParam = Partial; // 将所有字段变成可选项 diff --git a/shared/db/PvpRecord.ts b/shared/db/PvpRecord.ts index 82d869d0d..7bdf6cc81 100644 --- a/shared/db/PvpRecord.ts +++ b/shared/db/PvpRecord.ts @@ -2,6 +2,7 @@ import BaseModel from './BaseModel'; import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; import { getBeforeDayDate } from '../pubUtils/timeUtil'; import { genCode } from '../pubUtils/util'; +import { PvpHeroInfo } from './generalField'; export class HeroesRecord { @prop({ required: true, default: 0 }) @@ -20,6 +21,17 @@ export class HeroesRecord { heal: number; // 治疗 @prop({ required: true, default: 0 }) underDamage: number; // 承伤 + + constructor(pvpHero: PvpHeroInfo, damage: number, heal: number, underDamage: number) { + this.hid = pvpHero.actorId; + this.quality = pvpHero.quality; + this.star = pvpHero.star; + this.colorStar = pvpHero.colorStar; + this.lv = pvpHero.lv; + this.damage = damage; + this.heal = heal; + this.underDamage = underDamage; + } } export class PlayerInfo { diff --git a/shared/db/generalField.ts b/shared/db/generalField.ts index c7c9b2830..cec5f67b5 100644 --- a/shared/db/generalField.ts +++ b/shared/db/generalField.ts @@ -1,4 +1,6 @@ import { prop } from '@typegoose/typegoose'; +import { DicWarJson } from '../pubUtils/dictionary/DicWarJson'; +import { HeroType } from './Hero'; export class CeAttrData { @prop({ required: true }) @@ -120,3 +122,125 @@ export class CeAttrNumber { bloodSuck?: number = 0; } +// 从玩家数据中覆盖warjson的部分字段 +export class PvpHeroInfo { + @prop({ required: true }) + actorId?: number = 0; // 敌人id + @prop({ required: false }) + actorName?: string = ""; // 敌人名 + @prop({ required: false }) + outIndex?: number = 0; // 程序将信息存入数组顺序 + @prop({ required: false }) + star?: number = 0; // 角色星级 + @prop({ required: false }) + lv?: number = 0; // 角色等级 + @prop({ required: false }) + skill?: string = "0"; // 技能 + @prop({ required: false }) + seid?: string = "&"; // 技能 + @prop({ required: false }) + spine?: string = "0"; // S动画 + @prop({ required: false }) + colorStar?: number = 0; // 觉醒 + @prop({ required: false }) + quality?: number = 0; // 品质 + + @prop({ required: true, _id: false, default: new CeAttrNumber() }) + attribute?: CeAttrNumber; // 属性 + + setHeroInfo(hero: HeroType) { + this.actorId = hero.hid; + this.actorName = hero.hName; + this.star = hero.star; + this.lv = hero.lv; + this.colorStar = hero.colorStar; + this.quality = hero.quality; + } + + setRobotInfo(warjson: DicWarJson, lv: number, initialStar: number, quality: number) { + this.actorId = warjson.actorId; + this.actorName = warjson.actorName; + this.star = initialStar; + this.lv = lv; + this.quality = quality; + } + + setAttribute(attribute: CeAttrNumber) { + this.attribute = attribute; + } + + setOutIndex(order: number) { + this.outIndex = order; + } +} + +// 远征敌军 +export class Enemies extends PvpHeroInfo { + @prop({ required: true }) + actorId: number; // 敌人id + @prop({ required: false }) + actorName: string; // 敌人名 + @prop({ required: false }) + dataId: number; // 战场中唯一指向武将的代码 + @prop({ required: false }) + relation: number; // 角色属于我方还是地方 + @prop({ required: false }) + x: number; // 战场x坐标 + @prop({ required: false }) + y: number; // 战场y坐标 + @prop({ required: false }) + direction: number; // 朝向 + @prop({ required: false }) + var: number; // 变量 + @prop({ required: false }) + hide: number; // 是否隐藏 + @prop({ required: false }) + initial_ai: number; // AI类型 + + // warjson 出兵表 + // heroInfo 覆盖掉出兵表的相应参数 + constructor(warjson: DicWarJson, heroInfo: PvpHeroInfo) { + super(); + this.actorId = heroInfo.actorId != undefined? heroInfo.actorId: warjson.actorId; + this.actorName = heroInfo.actorName != undefined? heroInfo.actorName: warjson.actorName; + this.dataId = warjson.dataId; + this.relation = warjson.relation; + this.outIndex = heroInfo.outIndex != undefined? heroInfo.outIndex: warjson.outIndex; + this.x = warjson.x; + this.y = warjson.y; + this.direction = warjson.direction; + this.var = warjson.var; + this.lv = heroInfo.lv != undefined? heroInfo.lv: warjson.lv; + this.hide = warjson.hide; + this.initial_ai = warjson.initial_ai; + this.attribute = heroInfo.attribute; + this.skill = heroInfo.skill != undefined? heroInfo.skill: warjson.skill; + this.seid = heroInfo.seid != undefined? heroInfo.seid: warjson.seid; + this.star = heroInfo.star != undefined? heroInfo.star: warjson.star; + this.spine = heroInfo.spine!= undefined? heroInfo.spine: warjson.spine; + } + +} + +export class PvpEnemies extends Enemies { + @prop({ required: true }) + star: number; + @prop({ required: true }) + colorStar: number; + @prop({ required: true }) + quality: number; + @prop({ required: true }) + lv: number; + @prop({ required: true }) + score: number; + + // score: 这个武将的军功 + constructor(warjson: DicWarJson, heroInfo: PvpHeroInfo, score: number) { + super(warjson, heroInfo); + this.star = heroInfo.star; + this.colorStar = heroInfo.colorStar; + this.quality = heroInfo.quality; + this.lv = heroInfo.lv; + this.score = score; + } +} \ No newline at end of file diff --git a/shared/pubUtils/interface.ts b/shared/pubUtils/interface.ts index a5193da44..d6f8885f1 100644 --- a/shared/pubUtils/interface.ts +++ b/shared/pubUtils/interface.ts @@ -3,6 +3,7 @@ import { RoleType } from "../db/Role"; import { Robot } from "../db/PvpDefense"; import { reduceCe } from "./util"; +import { PvpHeroInfo, PvpEnemies } from "../db/generalField"; export interface RewardInter { id: number; @@ -121,13 +122,22 @@ export class RankParam { } } -export interface PlayerDetailHero { +export class PlayerDetailHero { actorId: number; lv: number; star: number; colorStar: number; quality: number; score: number; + + setPvpHeroInfo?(hero: PvpEnemies) { + this.actorId = hero.actorId; + this.lv = hero.lv; + this.star = hero.star; + this.colorStar = hero.colorStar; + this.quality = hero.quality; + this.score = hero.score; + } } export class PlayerDetail { diff --git a/shared/pubUtils/util.ts b/shared/pubUtils/util.ts index 5cd76822d..40b5968cc 100644 --- a/shared/pubUtils/util.ts +++ b/shared/pubUtils/util.ts @@ -8,7 +8,7 @@ import { DicRandomEffectPool } from './dictionary/DicRandomEffectPool'; import { HERO_CE_RATIO, ABI_STAGE } from '../consts'; import { findIndex } from 'underscore'; - +const randomName = require("chinese-random-name"); const moment = require('moment'); export function genCode(len) { @@ -516,3 +516,7 @@ export function getAllAttrStage() { }; return attrs; } + +export function getChineseName() { + return randomName.generate() +} \ No newline at end of file