添加获取对手阵容,开始战斗,结算

This commit is contained in:
luying
2021-01-07 17:37:06 +08:00
parent edc45932da
commit 5bfac1723c
12 changed files with 299 additions and 20 deletions

View File

@@ -1,13 +1,18 @@
import {Application, BackendSession} from 'pinus';
const _ = require('underscore');
import { gameData } from '../../../pubUtils/data';
import { checkPvp, initPvpInfo, refreshEnemies, getEnemies, } from '../../../services/pvpService';
import { checkPvp, initPvpInfo, refreshEnemies, getEnemies, getPlusScore, getLvByScore, } from '../../../services/pvpService';
import { RoleModel, RoleType } from '../../../db/Role';
import { STATUS } from '../../../consts/statusCode';
import { resResult } from '../../../pubUtils/util';
import { resResult, reduceCe, genCode } from '../../../pubUtils/util';
import { SystemConfigModel } from '../../../db/SystemConfig'
import { PvpDefenseModel } from '../../../db/PvpDefense';
import { PvpDefenseModel, PvpDefenseType, OppPlayers } from '../../../db/PvpDefense';
import { oppHeroesDefenseInter, pvpEndParamInter } from '../../../pubUtils/interface';
import { HeroType } from '../../../db/Hero';
import { CeAttrNumber } from '../../../db/generalField';
import { checkBattleHeroesByHid } from '../../../services/normalBattleService';
import { BattleRecordModel } from '../../../db/BattleRecord';
export default function(app: Application) {
return new PvpHandler(app);
}
@@ -49,6 +54,192 @@ export class PvpHandler {
pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { oppPlayers });
let result = getEnemies(pvpDefense.oppPlayers, pvpDefense.winStreakNum);
return resResult(STATUS.SUCCESS, { data: result });
return resResult(STATUS.SUCCESS, { oppPlayers: result, refOppCnt: 0 });
}
// 获取对手阵容具体信息
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 { 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 flag = 1; // 对比hero信息
let { record: { heroes: dbHeroes, oppRoleId, pos } } = BattleRecord;
for(let {hid} of myHeroes) {
if(dbHeroes.indexOf(hid) == -1) flag = 0;
}
if(!flag) {
return resResult(STATUS.BATTLE_INFO_VALIDATE_ERR);
}
// 更新军功
let pvpDefense = await PvpDefenseModel.findByRoleId(roleId);
if(!pvpDefense) return resResult(STATUS.PVP_NOT_OPEN);
let { oppPlayers, winStreakNum, heroScores, score } = 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 showHeroScores = new Array<{hid: number, addScore: number, plusScore: number, score: number}>();
for(let { hid, damage, heal, hurt } 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;
}
score += 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;
}
}
let pLv = getLvByScore(heroScores);
// 刷新对手
const role = await RoleModel.findByRoleId(roleId);
let newOppPlayers: Array<OppPlayers> = await refreshEnemies(role, score, pLv);
pvpDefense = await PvpDefenseModel.updateInfoAndInclude(roleId, { oppPlayers: newOppPlayers, heroScores, score, pLv, winStreakNum });
let result = getEnemies(pvpDefense.oppPlayers, pvpDefense.winStreakNum);
// 更新battleRecord
await BattleRecordModel.updateBattleRecordByCode(battleCode, {
$set: { status: isSuccess?1:2 }
}, true);
// TODO 记录战报
return resResult(STATUS.SUCCESS, {
battleCode, isSuccess,
score, pLv, myRank: 0,
heroScores: showHeroScores,
oppPlayers: result
});
}
}

View File

@@ -76,6 +76,7 @@ export async function matchPlayers(roleId: string, scale: number, range: number,
enemyObj.enemyId = roleId;
enemyObj.ce = defCe;
// TODO 修改获取attribute
let heroIndex = 0;
for(let enemy of dicWarJson) {
if(enemy.relation == 2) {

View File

@@ -60,6 +60,18 @@ export async function checkBattleHeroes(roleId: string, heroes: Array<number>) {
return flag;
}
export async function checkBattleHeroesByHid(roleId: string, heroes: Array<number>) {
let flag = true;
if(heroes.length <= 0) flag = false;
const findHeroes = await HeroModel.findByHidRange(heroes, roleId);
if(findHeroes.length != heroes.length) flag = false;
for(let hid of heroes) {
let hero = findHeroes.find(cur => cur.hid == hid);
if(!hero) flag = false;
}
return flag;
}
export async function updateWarStar(roleId: string, battleId: number, warType: number, star: number) {
let role = await RoleModel.findByRoleId(roleId);

View File

@@ -15,5 +15,12 @@ export async function eventOnPlayerLvUp(roleId: string, lv: number, addFuncs: Ar
await checkPvp(role);
addFuncs.push(FUNCS_ID.PVP);
}
}
if (!dataFuncs.includes(FUNCS_ID.EVENT)) {//开启奇遇
let res = getFuncsSwitch(FUNCS_ID.EVENT);
if (!res || lv >= res.param) {
addFuncs.push(FUNCS_ID.EVENT);
}
}
}

View File

@@ -1,15 +1,15 @@
/**
* 体力系统
*/
import { PvpDefenseModel, Heroes, OppPlayers, Robot, PvpDefenseType } from '../db/PvpDefense';
import { PvpDefenseModel, Heroes, OppPlayers, Robot, PvpDefenseType, HeroScores } from '../db/PvpDefense';
import { RoleType } from '../db/Role';
import { PVP_HERO_POS, ROBOT_NAME } from '../consts';
import { dicPvpOpponent, DicPvpOpponent } from "../pubUtils/dictionary/DicPvpOpponent";
import { getRandomIndexByLen, genCode, getRandomByLen } from '../pubUtils/util';
import { oppPlayersInter } from '../pubUtils/interface';
import { gameData } from "../pubUtils/data";
import { gameData, getPLvByScore } from "../pubUtils/data";
import { PVP } from '../pubUtils/dicParam';
export async function initPvpInfo(role: RoleType) {
let heroes: Array<Heroes> = [];
@@ -56,6 +56,7 @@ export function getEnemies(oppPlayers: OppPlayers[], winStreakNum: number) {
result.push({
pos, roleId, roleName, headHid, sHid, pLv, defCe,
addScore: dicOpponent.score,
rankLv: 0,
plusScore: getPlusScore(winStreakNum)
});
} else {
@@ -66,6 +67,7 @@ export function getEnemies(oppPlayers: OppPlayers[], winStreakNum: number) {
result.push({
pos, roleId, roleName, headHid, sHid, pLv, defCe,
addScore: dicOpponent.score,
rankLv: 0, // TODO读取排名
plusScore: getPlusScore(winStreakNum)
});
}
@@ -105,10 +107,11 @@ async function matchPlayer(oppPlayers: OppPlayers[], roleId: string, pLv: number
range.splice(index, 1);
if(range.length <= 0) return false;
index = getRandomIndexByLen(range.length);
result = range[range.length];
result = range[index];
}
oppPlayers.push({
roleId: result.roleId,
oppDef: result._id,
pos,
isRobot: false,
@@ -128,8 +131,11 @@ function matchRobot(oppPlayers: OppPlayers[], myCe: number, pLv: number, dicOpp:
let roleId = generateRobotRoleId();
let roleName = getRandomByLen(ROBOT_NAME);
let robot = new Robot(roleId, roleName, Math.floor(myCe * ratio), Math.floor(pLv + (minLv + maxLv)/2), result.war_id)
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)
oppPlayers.push({
roleId,
oppDef: null,
pos,
isRobot: true,
@@ -151,6 +157,17 @@ export function checkRoleIsRobot(roleId: string) {
// 根据连胜次数,获得加成的积分
export function getPlusScore(win: number) {
let result = win - 1;
if(result > 10) result = 10;
if(result < 0) result = 0;
if(result > PVP.PVP_WINREWARD_UPLIMIT) result = PVP.PVP_WINREWARD_UPLIMIT;
return result;
}
export function getLvByScore(heroScores: HeroScores[]) {
heroScores.sort((a, b) => b.score - a.score);
let score = 0;
for(let i = 0; i < 5; i++) {
if(!heroScores[i]) break;
score += heroScores[i].score;
}
return getPLvByScore(score);
}

View File

@@ -171,7 +171,7 @@ export default class GMUsers extends Service {
let {uid, tel} = role.userInfo;
result.push({
key: roleId, roleId, roleName, serverId, lv, vLv, uid, tel, heroCount, equipCount, itemCount, gold, coin,
hasDefense: defense?'是':'否', defCe: defense?defense.ce:0
hasDefense: defense?'是':'否', defCe: defense?defense.defCe:0
});
}
return ctx.service.utils.resResult(STATUS.SUCCESS, { list: result });
@@ -378,7 +378,7 @@ export default class GMUsers extends Service {
})
}
public async saveHeroToDefense(roleId: string, roleName: string, hid: number) {
public async saveHeroToDefense(roleId: string, _roleName: string, hid: number) {
const {ctx} = this;
let hero = await HeroModel.findByHidAndRole(hid, roleId);
let role = await RoleModel.findByRoleId(roleId);
@@ -406,7 +406,7 @@ export default class GMUsers extends Service {
let defense = await PvpDefenseModel.findByRoleId(roleId);
if(!defense) {
defense = await PvpDefenseModel.createPvpDefense({roleId, roleName, heroes: [heroInfo], ce});
// defense = await PvpDefenseModel.createPvpDefense({roleId, roleName, heroes: [], defCe:ce});
} else {
defense = await PvpDefenseModel.addHeroToDefense(roleId, heroInfo, ce);
}

View File

@@ -105,6 +105,10 @@ export const STATUS = {
COM_BATTLE_REWARDED: { code: 20628, simStr: '奖励已领取' },
COM_BATTLE_HEROES_ERR: { code: 20629, simStr: '阵容异常' },
// PVP 20700-20799
PVP_ROLE_NOT_FOUND: { code: 20700, simStr: '未找到该对手' },
PVP_NOT_OPEN: { code: 20701, simStr: 'pvp尚未开启' },
// 共斗藏宝图合成
COM_BLUEPRT_QUALITY_CANNOT_COMPOSE: { code: 20630, simStr: '该品质藏宝图不可合成' },
COM_BLUEPRT_COUNT_ERROR: { code: 20631, simStr: '材料数量不足' },

View File

@@ -7,6 +7,15 @@ import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoos
@index({ roleId: 1, battleId: 1 })
@index({ battleCode: 1 })
class Record {
@prop({ required: true, type: Number })
heroes: Array <number>; // 武将id
@prop({ required: false })
oppRoleId?: string; // pvp对手
@prop({ required: false })
pos?: number; // pvp位置
}
export default class BattleRecord extends BaseModel {
@prop({ required: true })
roleId: string; // 角色 id
@@ -26,10 +35,8 @@ export default class BattleRecord extends BaseModel {
status: number; // 关卡状态 0-挑战中 1-挑战成功 2-挑战失败
@prop({ required: true, default: 0 })
star: number; // 关卡状态 0-挑战中 1-挑战成功 2-挑战失败
@prop({ required: true })
record: { // 使用的武将等记录
heroes: Array <number>; // 武将id
};
@prop({ required: true, _id: false })
record: Record; // 使用的武将等记录
public static async getBattleRecordByCode(battleCode: string, lean = true) {
const result: BattleRecordType = await BattleRecordModel.findOne({ battleCode }).lean(lean);

View File

@@ -153,6 +153,12 @@ export default class Hero extends BaseModel {
const hero: HeroType[] = await HeroModel.find({ seqId: {$in: seqIds}, roleId }).lean(lean);
return hero;
}
public static async findByHidRange(hids: Array<number>, roleId: string, lean = true) {
const hero: HeroType[] = await HeroModel.find({ hid: {$in: hids}, roleId }).lean(lean);
return hero;
}
public static async findBySeqIdAndRole(seqId: number, roleId: string, lean = true) {
const hero: HeroType = await HeroModel.findOne({ seqId, roleId }).lean(lean);
return hero;

View File

@@ -10,6 +10,8 @@ interface pvpUpdateInter {
oppPlayers?: OppPlayers[];
score?: number;
pLv?:number;
heroScores?: HeroScores[];
winStreakNum?: number;
}
export class Heroes {
@@ -74,6 +76,8 @@ export class Robot {
}
export class OppPlayers {
@prop({ required: true })
roleId: string;
@prop({ ref: 'PvpDefense', type: mongoose.Schema.Types.ObjectId })
oppDef: Ref<PvpDef>;
@prop({ required: true })
@@ -84,7 +88,7 @@ export class OppPlayers {
robot: Robot
}
class HeroScores {
export class HeroScores {
@prop({ required: true })
hid: number;
@prop({ required: true })
@@ -180,8 +184,8 @@ export default class PvpDefense extends BaseModel {
.populate({
path: 'oppPlayers.oppDef',
populate: {
path: 'role',
select: 'headHid sHid topFiveCe roleId roleName'
path: 'role heroes.hero',
select: 'headHid sHid topFiveCe roleId roleName hid ceAttr globalCeAttr'
}
}).lean();
return result;

View File

@@ -33,4 +33,5 @@ export const PVP = {
PVP_CHALLENGE_FINALTIMES: 60, // PVP赛季最后一天挑战次数刷新时间分钟
PVP_SEASON_DAYS: 30, // PVP一个赛季的时间
PVP_OPPONENT_FREEREFRESH: 3, // pvp挑战对手每日免费刷新次数
PVP_WINREWARD_UPLIMIT: 10, // 连胜奖励军功加成上限
};

View File

@@ -66,4 +66,33 @@ export interface oppPlayersInter {
defCe: number; // 防守阵容战力
addScore: number; // 战胜后可获军功
plusScore: number; // 连胜加成军功
rankLv: number;
}
export interface oppHeroesDefenseInter {
actorId: number; // 武将id
actorName: string; // 武将名
dataId: number; // 出兵表唯一id
relation: number; // 地方还是我方
direction: number; // 方向
outIndex: number; // 玩家设置的出场顺序即order字段
x: number; // 战场x坐标
y: number; // 战场y坐标
var: number; // 变量
lv: number; // 等级
hide: number; // 是否隐藏
initial_ai: number; // ai类型
attribute: Attributes;
star: number; // 星级
skill: string|number; // 技能
seid: string; // 技能
spine: string|number; // 动画
}
export interface pvpEndParamInter {
hid: number;
damage: number;
heal: number;
hurt: number;
}