Files
ZYZ/game-server/app/servers/battle/handler/pvpHandler.ts
2021-01-08 17:53:23 +08:00

483 lines
22 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 {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 { RoleModel, RoleType } from '../../../db/Role';
import { STATUS } from '../../../consts/statusCode';
import { resResult, reduceCe, genCode } from '../../../pubUtils/util';
import { SystemConfigModel } from '../../../db/SystemConfig'
import { PvpDefenseModel, PvpDefenseType, 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 { 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';
export default function(app: Application) {
return new PvpHandler(app);
}
export class PvpHandler {
constructor(private app: Application) {
}
async getData (msg: {}, session: BackendSession) {
let roleId = session.get('roleId');
let {pvpDefense, warId} = await findPvpDefAllByRoleId(roleId);
let oppPlayers = await getEnemies(pvpDefense.oppPlayers, pvpDefense.winStreakNum);
let { heroes, score, pLv, winStreakNum, refOppCnt, challengeCnt, challengeRefTime, receivedBox, hisScore, heroScores, isFirstEntry, seasonNum, seasonEndTime } = pvpDefense;
if (isFirstEntry) {
await PvpDefenseModel.updateInfo(roleId, {isFirstEntry:false});
}
let myRank = await getMyRank(REDIS_KEY.PVP_RANK, 0, roleId);//去redis中获取排名
let data = {warId, seasonNum, seasonEndTime, myRank, oppPlayers, heroes: heroes.map(cur => {
let {actorId, dataId, order} = cur;
return { actorId, dataId, order }
}), score, pLv, winStreakNum, refOppCnt, challengeCnt, challengeRefTime, receivedBox, hisScore, heroScores, isFirstEntry}
return resResult(STATUS.SUCCESS, data);
}
// 刷新对手
async refreshOppPlayer (msg: {}, session: BackendSession) {
let roleId = session.get('roleId');
let sid = session.get('sid');
let pvpDefense = await PvpDefenseModel.findByRoleIdIncludeAll(roleId);
// 刷新次数及消耗
let {refOppCnt, refOppTime, consume} = getRefOppCnt(pvpDefense.refOppCnt, pvpDefense.refOppTime);
if(refOppCnt >= gameData.maxPvpRefreshCnt) {
return resResult(STATUS.PVP_REFRESH_CNT_REACH_MAX);
}
let costResult = await handleCost(roleId, sid, consume);
if(!costResult) return resResult(STATUS.ROLE_MATERIAL_NOT_ENOUGH);
// 刷新对手
let role = <RoleType>pvpDefense.role;
let oppPlayers = await refreshEnemies(role, pvpDefense.score, pvpDefense.pLv);
pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { oppPlayers, refOppCnt: refOppCnt + 1, refOppTime });
let result = await getEnemies(pvpDefense.oppPlayers, pvpDefense.winStreakNum);
return resResult(STATUS.SUCCESS, { oppPlayers: result, refOppCnt: pvpDefense.refOppCnt });
}
// 获取对手阵容具体信息
async getOppoPlayer (msg: { roleId: string }, session: BackendSession) {
let roleId = session.get('roleId');
let oppoRoleId = msg.roleId;
let pvpDefense = await PvpDefenseModel.findByRoleIdIncludeAll(roleId);
let { oppPlayers } = pvpDefense;
let role = <RoleType>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 heroes = new Array<oppHeroesDefenseInter>();
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
});
}
}
} else { // 真人
let oppDef = <PvpDefenseType>curOpp.oppDef;
let role = <RoleType>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 = <HeroType>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 resResult(STATUS.SUCCESS, { roleId: oppoRoleId, pos: curOpp.pos, heroes });
}
// 开战
async pvpStart (msg: { warId: number, heroes: number[], roleId: string }, session: BackendSession) {
const { warId, heroes, roleId: oppRoleId } = msg;
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let warInfo = gameData.war.get(warId);
if(!warInfo) {
return resResult(STATUS.BATTLE_MISS_INFO);
}
let checkHeroes = await checkBattleHeroesByHid(roleId, heroes);
if(!checkHeroes) return resResult(STATUS.BATTLE_HERO_NOT_FOUND);
const pvpDefense = await PvpDefenseModel.findByRoleId(roleId);
if(!pvpDefense) return resResult(STATUS.PVP_NOT_OPEN);
// 检查挑战次数
let { challengeCnt } = refresh(pvpDefense.challengeCnt, pvpDefense.challengeRefTime, pvpDefense.seasonEndTime);
if (challengeCnt == 0) {
return resResult(STATUS.PVP_CHALLENGE_TIMES_NOT_ENOUGH);
}
let { oppPlayers } = pvpDefense;
let curOpp = oppPlayers.find(cur => cur.roleId == oppRoleId);
if(!curOpp) return resResult(STATUS.PVP_ROLE_NOT_FOUND)
const battleCode = genCode(8); // 关卡唯一值
await BattleRecordModel.updateBattleRecordByCode(battleCode, {
$set: {
roleId, roleName, warId,
status: 0,
warName: warInfo.gk_name,
warType: warInfo.warType,
record: { heroes, pos: curOpp.pos, oppRoleId }
}
}, true);
return resResult(STATUS.SUCCESS, {
battleCode
});
}
// 结算
async pvpEnd (msg: { battleCode: string, isSuccess: boolean, myHeroes: pvpEndParamInter[], oppHeroes: pvpEndParamInter[] }, session: BackendSession) {
let roleId = session.get('roleId');
let roleName = session.get('roleName');
const { battleCode, isSuccess, myHeroes, oppHeroes } = msg;
const BattleRecord = await BattleRecordModel.getBattleRecordByCode(battleCode, true);
if(!BattleRecord || BattleRecord.status != 0) {
return resResult(STATUS.BATTLE_STATUS_WRONG);
}
let { record: { heroes: dbHeroes, oppRoleId, pos } } = BattleRecord;
let flag = 1; // 对比hero信息
for(let {hid} of myHeroes) {
if(dbHeroes.indexOf(hid) == -1) flag = 0;
}
if(!flag) return resResult(STATUS.BATTLE_INFO_VALIDATE_ERR);
// 更新军功
let {pvpDefense, warId} = await findPvpDefByRoleId(roleId);
if(!pvpDefense) return resResult(STATUS.PVP_NOT_OPEN);
let { oppPlayers, winStreakNum, heroScores, score, hisScore } = pvpDefense;
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<HeroesRecord>();
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<HeroesRecord>();
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
});
}
}
score += addSumScore;
if(score > hisScore) hisScore = score;
let pLv = getLvByScore(heroScores);
// 刷新对手
const role = await RoleModel.findByRoleId(roleId);
let newOppPlayers: Array<OppPlayers> = 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 }
}, true);
// 增加挑战次数
let { challengeCnt, challengeRefTime } = comsumeChallengeCnt(pvpDefense.challengeCnt, pvpDefense.challengeRefTime, pvpDefense.seasonEndTime);
if ( hisScore < score) {
hisScore = score;
}
pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { oppPlayers: newOppPlayers, heroScores, score, pLv, winStreakNum, challengeCnt, challengeRefTime, hisScore });
let result = await getEnemies(pvpDefense.oppPlayers, pvpDefense.winStreakNum);
// 加入排行榜
let params = new RankParam(roleName, role.lv, role.vLv, role.headHid, role.sHid, role.title);
await setRank(REDIS_KEY.PVP_RANK, 0, roleId, pvpDefense.score, pvpDefense.updatedAt.getTime(), params);
let myRank = await getMyRank(REDIS_KEY.PVP_RANK, 0, roleId);
return resResult(STATUS.SUCCESS, {
battleCode, isSuccess,
score, pLv, myRank, hisScore,
heroScores: showHeroScores,
oppPlayers: result,
seasonNum: pvpDefense.seasonNum,
seasonEndTime: pvpDefense.seasonEndTime,
refOppCnt: pvpDefense.refOppCnt,
challengeCnt: pvpDefense.challengeCnt,
challengeRefTime: pvpDefense.challengeRefTime,
winStreakNum: pvpDefense.winStreakNum,
warId
});
}
async saveDefense(msg: { heroes: Array<{actorId: number, dataId: number, order: number}>, isDefaultHero:boolean }, session: BackendSession) {
let {heroes, isDefaultHero} = msg;
let roleId = session.get('roleId');
if (heroes.length > 5) {
return resResult(STATUS.WRONG_PARMS);
}
heroes = _.uniq(heroes, function(item) {
return item.order;
});
let { heroes: defHeros, seasonEndTime, challengeCnt: lastChallengeCnt, challengeRefTime: lastChallengeRefTime } = await PvpDefenseModel.findByRoleId(roleId);
let defCe = 0;
let { challengeCnt, challengeRefTime } = refresh(lastChallengeCnt, lastChallengeRefTime, seasonEndTime);
if (!!isDefaultHero) {
let role = await RoleModel.findByRoleId(roleId);
let { resHeroes } = await defaultHeroes(role);
return resResult(STATUS.SUCCESS, { heroes: resHeroes, challengeCnt, challengeRefTime} );
} else {
for (let dataId = PVP_HERO_POS.START; dataId <= PVP_HERO_POS.END; dataId++) {
let index = _.findIndex(heroes, {dataId});
let defIndex = _.findIndex(defHeros, {dataId});
if (defIndex == -1) {
defIndex = defHeros.length;
defHeros.push({actorId:0, order:0,ce:0, hero:null,dataId});
}
if (index == -1) {
defHeros[defIndex].actorId = 0;
defHeros[defIndex].order = 0;
defHeros[defIndex].ce = 0;
defHeros[defIndex].hero = null;
defHeros[defIndex].dataId = dataId;
continue;
}
let hero = await HeroModel.findByHidAndRole(heroes[index].actorId, roleId);
if (!hero) {
continue;
}
defHeros[defIndex].actorId = heroes[index].actorId;
defHeros[defIndex].order = heroes[index].order;
defHeros[defIndex].ce = hero.ce;
defHeros[defIndex].hero = hero._id;
defCe += hero.ce;
}
let { heroes: resHeroes } = await PvpDefenseModel.updateInfo(roleId, {defCe, heroes: defHeros, challengeCnt, challengeRefTime });
return resResult(STATUS.SUCCESS, { heroes: resHeroes, challengeCnt, challengeRefTime });
}
}
async getRank(msg: {}, session: BackendSession) {
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let serverId = session.get('serverId')
const hasRank = await existsRank(REDIS_KEY.PVP_RANK, serverId);
if(!hasRank) await initRank(serverId);
let {ranks, myRank} = await getRank(REDIS_KEY.PVP_RANK, 0, roleId);
if(!myRank) {
let pvpDefense = await PvpDefenseModel.findByRoleId(roleId);
let role = await RoleModel.findByRoleId(roleId);
let { lv, vLv, headHid, sHid, title} = role;
let rankRank = new RankParam(roleName, lv, vLv, headHid, sHid, title);
myRank = {
rank: 0, roleId, ...rankRank, num: pvpDefense.score, str: ''
}
}
return resResult(STATUS.SUCCESS, { ranks: ranks.slice(0, 100), myRank });
}
async getPlayerDetail(msg: { roleId: string }, session: BackendSession) {
let roleId = session.get('roleId');
let { roleId: oppoRoleId } = msg;
let isRobot = checkRoleIsRobot(oppoRoleId);
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<PlayerDetailHero>();
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
});
}
}
result = new PlayerDetail({...robot, lv: role.lv, heroes})
} else { // 查询对方pvpDefense
let pvpDefense = await PvpDefenseModel.findByRoleId(oppoRoleId);
let dbHeroes = await HeroModel.findByRole(oppoRoleId);
let role = await RoleModel.findByRoleId(oppoRoleId);
let heroes = new Array<PlayerDetailHero>();
for(let {hid, lv, star, colorStar, quality } of dbHeroes) {
let heroScore = pvpDefense.heroScores.find(cur => cur.hid == hid);
heroes.push({
actorId: hid, lv, star, colorStar, quality,
score: heroScore?heroScore.score: 0
});
}
heroes.sort((a, b) => b.score - a.score);
result = new PlayerDetail({...role, heroes});
}
return resResult(STATUS.SUCCESS, result);
}
async receiveBox(msg: {id: number}, session: BackendSession) {
let {id} = msg;
let roleId = session.get('roleId');
let sid: string = session.get('sid');
let roleName = session.get('roleName');
let { hisScore, receivedBox, challengeCnt: lastChallengeCnt, challengeRefTime: lastChallengeRefTime, seasonEndTime } = await PvpDefenseModel.findByRoleIdIncludeAll(roleId);
let pvpBoxs = getPvpBoxs();
let pvpBox = _.findWhere(pvpBoxs, {id})
if (hisScore < pvpBox.score) {
return resResult(STATUS.PVP_NOT_REACH_BOX_SCORE);
}
if (_.indexOf(receivedBox, id) != -1 ) {
return resResult(STATUS.PVP_BOX_IS_GOT);
}
receivedBox.push(id);
let { challengeCnt, challengeRefTime } = refresh(lastChallengeCnt, lastChallengeRefTime, seasonEndTime);
await PvpDefenseModel.updateInfo(roleId, {receivedBox, challengeCnt, challengeRefTime});
let result = await addItems(roleId, roleName, sid, pvpBox.reward );
return resResult(STATUS.SUCCESS,{goods: result, receivedBox, challengeCnt, challengeRefTime});
}
async getRec(msg: {}, session: BackendSession ) {
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let pvpRecords = await PvpRecordModel.getRecByRoleId(roleId);
return resResult(STATUS.SUCCESS, {list: pvpRecords});
}
}