diff --git a/game-server/app/servers/battle/handler/pvpHandler.ts b/game-server/app/servers/battle/handler/pvpHandler.ts index 107fb9653..32c6c3eb1 100644 --- a/game-server/app/servers/battle/handler/pvpHandler.ts +++ b/game-server/app/servers/battle/handler/pvpHandler.ts @@ -1,25 +1,24 @@ import {Application, BackendSession} from 'pinus'; const _ = require('underscore'); import { gameData, getPvpBoxs } from '../../../pubUtils/data'; -import { refreshEnemies, getEnemies, getPlusScore, getLvByScore, defaultHeroes, comsumeChallengeCnt, refresh, findPvpDefByRoleId, checkRoleIsRobot, getRefOppCnt, findPvpDefAllByRoleId } from '../../../services/pvpService'; +import { refreshEnemies, getEnemies, getLvByScore, defaultHeroes, comsumeChallengeCnt, refresh, findPvpDefByRoleId, checkRoleIsRobot, getRefOppCnt, findPvpDefAllByRoleId, generPVPOppRecInfo, generMyRecInfo, getRobotLineup, getPlayerLineup } from '../../../services/pvpService'; import { RoleModel, RoleType } from '../../../db/Role'; import { STATUS } from '../../../consts/statusCode'; -import { resResult, reduceCe, genCode } from '../../../pubUtils/util'; +import { resResult, genCode } from '../../../pubUtils/util'; import { SystemConfigModel } from '../../../db/SystemConfig' -import { PvpDefenseModel, PvpDefenseType, OppPlayers } from '../../../db/PvpDefense'; +import { PvpDefenseModel, OppPlayers } from '../../../db/PvpDefense'; import { oppHeroesDefenseInter, pvpEndParamInter, RankParam, PlayerDetail, PlayerDetailHero } from '../../../pubUtils/interface'; import { PVP_HERO_POS, REDIS_KEY } from '../../../consts'; import { addItems } from '../../../services/rewardService'; -import { HeroType, HeroModel } from '../../../db/Hero'; -import { CeAttrNumber } from '../../../db/generalField'; +import { HeroModel } from '../../../db/Hero'; import { checkBattleHeroesByHid } from '../../../services/normalBattleService'; import { BattleRecordModel } from '../../../db/BattleRecord'; import { PvpRecordModel, HeroesRecord } from '../../../db/PvpRecord'; -import { setPvpDefResult } from '../../../services/timeTaskService'; import { existsRank, initRank, getRank, setRank, getMyRank } from '../../../services/redisService'; import { handleCost } from '../../../services/rewardService'; +import { matchPlayerByRank } from '../../../services/pvpService'; export default function(app: Application) { return new PvpHandler(app); @@ -90,52 +89,9 @@ export class PvpHandler { let heroes = new Array(); if(curOpp.isRobot) { // 机器人 - 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 = new CeAttrNumber(); - for(let attrName in newAttribute) { - newAttribute[attrName] = Math.floor(attribute[attrName] * role.topFiveCe / 10000 * dicOpp.ratio); - } - newAttribute['speed'] = 0; - newAttribute['ap'] = 0; - - let heroInfo = { actorId, actorName, skill, seid, star, spine, attribute: newAttribute, lv: role.lv }; - heroes.push({ - ...curDicMapJson, ...heroInfo - }); - } - } + heroes = await getRobotLineup(mapWarJson, curOpp, role.topFiveCe, role.lv); } else { // 真人 - let oppDef = curOpp.oppDef; - let role = oppDef.role; - let { globalCeAttr } = role; - for(let { actorId, hero, dataId, order } of oppDef.heroes) { - let curDicMapJson = mapWarJson.find(cur => cur.dataId == dataId); - let dicHero = gameData.hero.get(actorId); - let h = hero; - let { ceAttr } = h; - let newAttribute = new CeAttrNumber(); - for(let attrName in newAttribute) { - let { base, ratioUp, fixUp, equipUp } = ceAttr[attrName]; - let { ratioUp: ratioUp2, fixUp: fixUp2 } = globalCeAttr[attrName]; - let result = base * ( 1 + ratioUp + ratioUp2) + fixUp + fixUp2 + equipUp; - newAttribute[attrName] += reduceCe(result); - } - newAttribute['speed'] = 0; - newAttribute['ap'] = 0; - - 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 - }); - } - + heroes = await getPlayerLineup(mapWarJson, curOpp); } return resResult(STATUS.SUCCESS, { roleId: oppoRoleId, pos: curOpp.pos, heroes }); @@ -212,80 +168,22 @@ export class PvpHandler { let curOpp = oppPlayers.find(cur => cur.roleId == oppRoleId && cur.pos == pos); if(!curOpp) return resResult(STATUS.PVP_ROLE_NOT_FOUND); - const dicOpp = gameData.pvpOpponent.get(pos); - let plusScore = getPlusScore(winStreakNum); - - let myHeroRecords = new Array(); - let showHeroScores = new Array<{hid: number, addScore: number, plusScore: number, score: number}>(); - let addSumScore = 0; - for(let { hid, damage, heal, underDamage } of myHeroes) { - let curHeroScore = heroScores.find(cur => cur.hid == hid); - if(isSuccess) { - if(!curHeroScore) { - curHeroScore = { - hid, score: dicOpp.score + plusScore - }; - heroScores.push(curHeroScore); - } else { - curHeroScore.score += dicOpp.score + plusScore; - } - addSumScore += dicOpp.score + plusScore; - showHeroScores.push({ - hid, addScore: dicOpp.score, plusScore, score: curHeroScore.score - }); - winStreakNum ++; - } else { - showHeroScores.push({ - hid, addScore: 0, plusScore: 0, score: curHeroScore.score - }); - winStreakNum = 0; - } - const myHero = await HeroModel.findByHidAndRole(hid, roleId, 'quality star colorStar lv'); - let { quality, star, colorStar, lv} = myHero; - myHeroRecords.push({ - hid, quality, star, colorStar, lv, damage, heal, underDamage - }); - } - - let oppHeroRecords = new Array(); - 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, roleId, 'quality star colorStar lv'); - let { quality, star, colorStar, lv} = myHero; - oppHeroRecords.push({ - hid, quality, star, colorStar, lv, damage, heal, underDamage - }); - } - } + const role = await RoleModel.findByRoleId(roleId); + const myRecInfo = await generMyRecInfo(heroScores, winStreakNum, role, isSuccess, pos, myHeroes); + let { attackInfo, showHeroScores, addSumScore } = myRecInfo score += addSumScore; if(score > hisScore) hisScore = score; let pLv = getLvByScore(heroScores); + const defenseInfo = await generPVPOppRecInfo(isSuccess, curOpp, oppRoleId, oppHeroes); + + // 战报记录 + await PvpRecordModel.createRec({roleId1: roleId, roleId2: oppRoleId, warId: BattleRecord.battleId, attackInfo, defenseInfo}); + // 刷新对手 - const role = await RoleModel.findByRoleId(roleId); let newOppPlayers: Array = await refreshEnemies(role, score, pLv); - let oppRole; - if(curOpp.isRobot) { - oppRole = { ...curOpp.robot, title: 1, topFiveCe: curOpp.robot.defCe}; - } else { - oppRole = await RoleModel.findByRoleId(oppRoleId); - } - - // TODO 战报记录方法抽象 - await PvpRecordModel.createRec({roleId1: roleId, roleId2: oppRoleId, warId: BattleRecord.battleId, attackInfo: { - roleId, roleName, lv: role.lv, sHid: role.sHid, headHid: role.headHid, title: role.title, ce: role.topFiveCe, heroes: myHeroRecords, isSuccess, score: isSuccess?addSumScore:0 - }, defenseInfo: { - roleId: oppRole.roleId, roleName: oppRole.roleName, lv: oppRole.lv, sHid: oppRole.sHid, headHid: oppRole.headHid, title: oppRole.title, ce: oppRole.topFiveCe, heroes: myHeroRecords, isSuccess: !isSuccess, score: 0 - }}) - // 更新battleRecord await BattleRecordModel.updateBattleRecordByCode(battleCode, { $set: { status: isSuccess?1:2 } diff --git a/game-server/app/services/pvpService.ts b/game-server/app/services/pvpService.ts index 6009f7816..17394b01e 100644 --- a/game-server/app/services/pvpService.ts +++ b/game-server/app/services/pvpService.ts @@ -2,17 +2,21 @@ * 体力系统 */ import { PvpDefenseModel, Heroes, OppPlayers, Robot, PvpDefenseType, HeroScores } from '../db/PvpDefense'; -import { RoleType } from '../db/Role'; +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 } from '../pubUtils/util'; -import { oppPlayersInter, RankParam } from '../pubUtils/interface'; +import { getRandomIndexByLen, genCode, getRandomByLen, shouldRefresh, reduceCe } from '../pubUtils/util'; +import { oppPlayersInter, RankParam, pvpEndParamInter, oppHeroesDefenseInter } from '../pubUtils/interface'; import { gameData, getPLvByScore } from "../pubUtils/data"; import { PVP } from '../pubUtils/dicParam'; import { SystemConfigModel } from '../db/SystemConfig' -import { setRank, getMyRank } from './redisService'; +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 } from '../db/generalField'; +import { DicWarJson } from '../pubUtils/dictionary/DicWarJson'; const _ = require('underscore'); @@ -65,7 +69,7 @@ export async function getEnemies(oppPlayers: OppPlayers[], winStreakNum: number) if(isRobot) { let { roleId, roleName, headHid, sHid, pLv, defCe } = robot; result.push({ - pos, roleId, roleName, headHid, sHid, pLv, defCe, + pos, roleId, roleName, headHid, sHid, pLv, defCe: reduceCe(defCe), addScore: dicOpponent.score, rankLv: 0, plusScore: getPlusScore(winStreakNum) @@ -77,7 +81,7 @@ export async function getEnemies(oppPlayers: OppPlayers[], winStreakNum: number) let { pLv, defCe } = opp; let rankLv = await getMyRank(REDIS_KEY.PVP_RANK, 0, roleId); result.push({ - pos, roleId, roleName, headHid, sHid, pLv, defCe, + pos, roleId, roleName, headHid, sHid, pLv, defCe: reduceCe(defCe), addScore: dicOpponent.score, rankLv, // 读取排名 plusScore: getPlusScore(winStreakNum) @@ -87,7 +91,7 @@ export async function getEnemies(oppPlayers: OppPlayers[], winStreakNum: number) return result } -// TODO 刷新对手 +// 刷新对手 export async function refreshEnemies(role: RoleType, score: number, pLv: number) { let { roleId, topFiveCe } = role; let oppPlayers = new Array(); @@ -97,6 +101,7 @@ export async function refreshEnemies(role: RoleType, score: number, pLv: number) if(score > 3000) { // TODO 将这个放到const flag = await matchPlayer(oppPlayers, roleId, pLv, dicOpp); // TODO 当前后分数段没有时,返回前一名的玩家 + if(!flag) flag = await matchPlayerByRank(oppPlayers, roleId, dicOpp.id); if(!flag) flag = matchRobot(oppPlayers, topFiveCe, pLv, dicOpp); } else { flag = matchRobot(oppPlayers, topFiveCe, pLv, dicOpp); @@ -107,18 +112,53 @@ export async function refreshEnemies(role: RoleType, score: number, pLv: number) return oppPlayers; } +export async function matchPlayerByRank(oppPlayers: OppPlayers[], roleId: string, pos: number) { + let myRank = await getMyRank(REDIS_KEY.PVP_RANK, 0, roleId); + let oppRoleId = ''; + let oppRank = 0; + if(myRank == 1) { // 第一名 + if(pos == 1) { + oppRank = 2; + } else if(pos == 2) { + oppRank = 3; + } else { + oppRank = 4; + } + } else { + if(pos == 1 || pos == 2) { // 刷新我前一名 + oppRank = myRank - 1; + } else { // 刷新我后一名 + oppRank = myRank + 1; + } + } + let result = await getFieldByRank(REDIS_KEY.PVP_RANK, 0, oppRank); + if(result.length <= 0) return false; + oppRoleId = result[0]; + + let pvpdefense = await PvpDefenseModel.findByRoleId(oppRoleId); + oppPlayers.push({ + roleId: pvpdefense.roleId, + oppDef: pvpdefense._id, + pos, + isRobot: false, + robot: null + }); + return true +} + async function matchPlayer(oppPlayers: OppPlayers[], 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 => { + return oppPlayers.findIndex(ccur => ccur.roleId == cur.roleId) != -1; + }); if(range.length <= 0) return false; let index = getRandomIndexByLen(range.length); let result = range[index]; if(!result) return false; if(result.roleId == roleId) { - console.log(range.length) range.splice(index, 1); - console.log(JSON.stringify(range)) if(range.length <= 0) return false; index = getRandomIndexByLen(range.length); result = range[index]; @@ -308,3 +348,154 @@ export async function findPvpDefAllByRoleId(roleId: string) { return {pvpDefense, warId}; } +// 获取机器人阵容 +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; + console.log(JSON.stringify(json)) + if(relation == 2 && actorId > 0) { // 默认格子 + let newAttribute = new CeAttrNumber(); + for(let attrName in newAttribute) { + newAttribute[attrName] = Math.floor(attribute[attrName] * topFiveCe / 10000 * dicOpp.ratio); + } + newAttribute['speed'] = 0; + newAttribute['ap'] = 0; + + 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) { + let curDicMapJson = mapWarJson.find(cur => cur.dataId == dataId); + let dicHero = gameData.hero.get(actorId); + let h = hero; + let { ceAttr } = h; + let newAttribute = new CeAttrNumber(); + for(let attrName in newAttribute) { + let { base, ratioUp, fixUp, equipUp } = ceAttr[attrName]; + let { ratioUp: ratioUp2, fixUp: fixUp2 } = globalCeAttr[attrName]; + let result = base * ( 1 + ratioUp + ratioUp2) + fixUp + fixUp2 + equipUp; + newAttribute[attrName] += reduceCe(result); + } + newAttribute['speed'] = 0; + newAttribute['ap'] = 0; + + 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 +} + +// 获取我方战报记录 +export async function generMyRecInfo(heroScores: HeroScores[], winStreakNum: number, role: RoleType, isSuccess: boolean, pos: number, myHeroes: pvpEndParamInter[]) { + + let { roleId, roleName } = role; + + const dicOpp = gameData.pvpOpponent.get(pos); + const plusScore = getPlusScore(winStreakNum); + + let myHeroRecords = new Array(); + let showHeroScores = new Array<{ hid: number, addScore: number, plusScore: number, score: number }>(); + let addSumScore = 0; + for (let { hid, damage, heal, underDamage } of myHeroes) { + let curHeroScore = heroScores.find(cur => cur.hid == hid); + if (isSuccess) { + if (!curHeroScore) { + curHeroScore = { + hid, score: dicOpp.score + plusScore + }; + heroScores.push(curHeroScore); + } else { + curHeroScore.score += dicOpp.score + plusScore; + } + addSumScore += dicOpp.score + plusScore; + showHeroScores.push({ + hid, addScore: dicOpp.score, plusScore, score: curHeroScore.score + }); + winStreakNum++; + } else { + showHeroScores.push({ + hid, addScore: 0, plusScore: 0, score: curHeroScore.score + }); + winStreakNum = 0; + } + const myHero = await HeroModel.findByHidAndRole(hid, roleId, 'quality star colorStar lv'); + let { quality, star, colorStar, lv } = myHero; + myHeroRecords.push({ + hid, quality, star, colorStar, lv, damage, heal, underDamage + }); + } + + let attackInfo = { + roleId, + roleName, + lv: role.lv, + sHid: role.sHid, + headHid: role.headHid, + title: role.title, + ce: role.topFiveCe, + heroes: myHeroRecords, + isSuccess, + score: isSuccess ? addSumScore : 0 + } + + return { attackInfo, showHeroScores, winStreakNum, addSumScore } +} + +// 获取对手战报记录 +export async function generPVPOppRecInfo(isSuccess: boolean, curOpp: OppPlayers, oppRoleId: string, oppHeroes: pvpEndParamInter[]) { + let oppHeroRecords = new Array(); + 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 oppRole; + if (curOpp.isRobot) { + oppRole = { ...curOpp.robot, title: 1, topFiveCe: curOpp.robot.defCe }; + } else { + oppRole = await RoleModel.findByRoleId(oppRoleId); + } + return { + roleId: oppRole.roleId, + roleName: oppRole.roleName, + lv: oppRole.lv, + sHid: oppRole.sHid, + headHid: oppRole.headHid, + title: oppRole.title, + ce: oppRole.topFiveCe, + heroes: oppHeroRecords, + isSuccess: !isSuccess, + score: 0 + } +} diff --git a/game-server/app/services/redisService.ts b/game-server/app/services/redisService.ts index 208f23bd4..8e071439b 100644 --- a/game-server/app/services/redisService.ts +++ b/game-server/app/services/redisService.ts @@ -127,6 +127,14 @@ export async function getMyRank(key: string, serverId: number, roleId: string) { return myRank + 1; } +// 获取排名第几名的信息 +export async function getFieldByRank(key: string, serverId: number, rank: number) { + const client: Redis.RedisClient = pinus.app.get('redis'); + let myRank = await client.zrevrangeAsync(getKeyName(key, serverId), rank - 1, rank - 1); + console.log('****', JSON.stringify(myRank)) + return myRank; +} + // 有序排行综合时间和得分排序 function encodeScoreWithTime(score: number, timestamp: number): number { // value = score * Math.power(10, 14) + max_time - timestamp diff --git a/game-server/config/redis.ts b/game-server/config/redis.ts index 74eef8e25..00b2f42ef 100644 --- a/game-server/config/redis.ts +++ b/game-server/config/redis.ts @@ -41,6 +41,8 @@ declare module 'redis' { zrankAsync(key: string, field: string): Promise; // 返回有序集中指定成员的排名,从大到小 zrevrankAsync(key: string, field: string): Promise; + // 命令返回有序集中,指定区间内的成员,从大到小 + zrevrangeAsync(key: string, start: number, end: number): Promise; } export interface Multi extends Commands { execAsync(...args: any[]): Promise; diff --git a/shared/consts/constModules/battleConst.ts b/shared/consts/constModules/battleConst.ts index 46aee4442..7b7a56bb5 100644 --- a/shared/consts/constModules/battleConst.ts +++ b/shared/consts/constModules/battleConst.ts @@ -154,5 +154,5 @@ export const COM_BATTLE_ROBOT_ID_NAME = [ ]; export const ROBOT_NAME = [ - '徐埋农', '简普瞳', '邛瑛', '嵇晁伊', '颜校', '吉辉娇' + '徐埋农', '简普瞳', '邛瑛', '嵇晁伊', '颜校', '吉辉娇', '罗宾', 'A', 'B', 'C', 'D', 'E', 'F' ]; diff --git a/shared/pubUtils/dictionary/DicWarJson.ts b/shared/pubUtils/dictionary/DicWarJson.ts index f24a69d4c..0d5a6a4a9 100644 --- a/shared/pubUtils/dictionary/DicWarJson.ts +++ b/shared/pubUtils/dictionary/DicWarJson.ts @@ -113,4 +113,5 @@ function parseAttribute(str: string) { break; } } + return attribute } \ No newline at end of file