pvp随机地图
This commit is contained in:
@@ -292,7 +292,7 @@ export const FILENAME = {
|
||||
DIC_PVP_OPPONENT: 'dic_pvp_opponent',
|
||||
DIC_PVP_TEAM_LEVEL: 'dic_pvp_teamLevel',
|
||||
DIC_GK_PVP: 'dic_zyz_gk_pvp',
|
||||
DIC_PVP_REFRESHCONSUME: 'dic_pvp_refreshConsume'
|
||||
DIC_PVP_REFRESHCONSUME: 'dic_pvp_refreshConsume',
|
||||
}
|
||||
|
||||
export const WAR_RELATE_TABLES = [
|
||||
|
||||
+51
-51
@@ -1,7 +1,7 @@
|
||||
import BaseModel from './BaseModel';
|
||||
import { index, getModelForClass, prop, DocumentType, modelOptions } from '@typegoose/typegoose';
|
||||
const _ = require('underscore');
|
||||
|
||||
const Transaction = require('mongoose-transactions');
|
||||
@index({ roleId: 1, id: 1 })
|
||||
@index({ seqId: 1 })
|
||||
@modelOptions({ schemaOptions: { id: false } })
|
||||
@@ -50,59 +50,59 @@ export default class Item extends BaseModel {
|
||||
return items;
|
||||
}
|
||||
|
||||
public static async decreaseItems(roleId: string, items: Array<{ id: number, count: number, ratio?: number }>, lean = true) {
|
||||
let updateItems = new Array<{ id: number, count: number, ratio?: number }>(), hasError: boolean = false, result = new Array();
|
||||
for (let { id, count, ratio } of items) {
|
||||
let rec: ItemType;
|
||||
if (!ratio) {
|
||||
rec = await ItemModel.findOneAndUpdate({ roleId, id, count: { $gte: count } }, { $inc: { count: -1 * count } }, { new: true }).lean(lean);
|
||||
} else {
|
||||
rec = await ItemModel.findOneAndUpdate({ roleId, id }, { $inc: { count: ratio * count } }, { new: true, upsert: true }).lean(lean);
|
||||
}
|
||||
if (!!rec) {
|
||||
let index = _.findIndex(result,{id})
|
||||
if (!!result[index]) {
|
||||
result[index] = { id: rec.id, count: rec.count }
|
||||
} else {
|
||||
result.push({ id: rec.id, count: rec.count });
|
||||
}
|
||||
updateItems.push({ id, count, ratio });
|
||||
} else {
|
||||
hasError = true; break;
|
||||
}
|
||||
}
|
||||
if (hasError) { // 数量不足
|
||||
for (let { id, count, ratio } of updateItems) {
|
||||
if (!ratio) ratio = -1;
|
||||
await ItemModel.findOneAndUpdate({ roleId, id }, { $inc: { count: -ratio * count } }, { new: true }).lean(lean);
|
||||
}
|
||||
return { hasError: true }
|
||||
} else {
|
||||
return { hasError: false, result }
|
||||
}
|
||||
}
|
||||
// public static async decreaseItems(roleId: string, items: Array<{ id: number, count: number, ratio?: number}>, lean = true) {
|
||||
// const transaction = new Transaction();
|
||||
// let hasError: boolean = false, result = new Array();
|
||||
// try {
|
||||
// for (let { id, count, ratio } of items) {
|
||||
// if (ratio) ratio = -1;
|
||||
// await transaction.update({ roleId, id, count: { $gte: count } }, { $inc: { count: ratio * count } }, { new: true});
|
||||
// //const rec: ItemType = await transaction.findOneAndUpdate({ roleId, id, count: { $gte: count } }, { $inc: { count: ratio * count } }, { new: true}).lean(lean);
|
||||
// // if (!!rec) {
|
||||
// // result.push({ id: rec.id, count: rec.count });
|
||||
// // } else {
|
||||
// // hasError = true; break;
|
||||
// // }
|
||||
// public static async decreaseItems(roleId: string, items: Array<{ id: number, count: number, ratio?: number }>, lean = true) {
|
||||
// let updateItems = new Array<{ id: number, count: number, ratio?: number }>(), hasError: boolean = false, result = new Array();
|
||||
// for (let { id, count, ratio } of items) {
|
||||
// let rec: ItemType;
|
||||
// if (!ratio) {
|
||||
// rec = await ItemModel.findOneAndUpdate({ roleId, id, count: { $gte: count } }, { $inc: { count: -1 * count } }, { new: true }).lean(lean);
|
||||
// } else {
|
||||
// rec = await ItemModel.findOneAndUpdate({ roleId, id }, { $inc: { count: ratio * count } }, { new: true, upsert: true }).lean(lean);
|
||||
// }
|
||||
// await transaction.run();
|
||||
// return {hasError, result};
|
||||
// } catch (error) {
|
||||
// await transaction.rollback().catch(console.error);
|
||||
// transaction.clean();
|
||||
// return {error};
|
||||
// if (!!rec) {
|
||||
// let index = _.findIndex(result,{id})
|
||||
// if (!!result[index]) {
|
||||
// result[index] = { id: rec.id, count: rec.count }
|
||||
// } else {
|
||||
// result.push({ id: rec.id, count: rec.count });
|
||||
// }
|
||||
// updateItems.push({ id, count, ratio });
|
||||
// } else {
|
||||
// hasError = true; break;
|
||||
// }
|
||||
// }
|
||||
// if (hasError) { // 数量不足
|
||||
// for (let { id, count, ratio } of updateItems) {
|
||||
// if (!ratio) ratio = -1;
|
||||
// await ItemModel.findOneAndUpdate({ roleId, id }, { $inc: { count: -ratio * count } }, { new: true }).lean(lean);
|
||||
// }
|
||||
// return { hasError: true }
|
||||
// } else {
|
||||
// return { hasError: false, result }
|
||||
// }
|
||||
// }
|
||||
public static async decreaseItems(roleId: string, items: Array<{ id: number, count: number, ratio?: number}>, lean = true) {
|
||||
const transaction = new Transaction();
|
||||
let hasError: boolean = false, result = new Array();
|
||||
try {
|
||||
for (let { id, count, ratio } of items) {
|
||||
if (ratio) ratio = -1;
|
||||
await transaction.update({ roleId, id, count: { $gte: count } }, { $inc: { count: ratio * count } }, { new: true});
|
||||
const rec: ItemType = await transaction.findOneAndUpdate({ roleId, id, count: { $gte: count } }, { $inc: { count: ratio * count } }, { new: true}).lean(lean);
|
||||
if (!!rec) {
|
||||
result.push({ id: rec.id, count: rec.count });
|
||||
} else {
|
||||
hasError = true; break;
|
||||
}
|
||||
}
|
||||
await transaction.run();
|
||||
return {hasError, result};
|
||||
} catch (error) {
|
||||
await transaction.rollback().catch(console.error);
|
||||
transaction.clean();
|
||||
return {error};
|
||||
}
|
||||
}
|
||||
|
||||
public static async deleteAccount(roleId: string) {
|
||||
let result = await ItemModel.deleteMany({ roleId });
|
||||
|
||||
+15
-3
@@ -7,7 +7,9 @@ import { PVP_PLAYER_POS, PVP_HERO_POS } from '../consts';
|
||||
|
||||
interface pvpUpdateInter {
|
||||
_id?: string;
|
||||
oppPlayers: OppPlayers[]
|
||||
oppPlayers?: OppPlayers[];
|
||||
score?: number;
|
||||
pLv?:number;
|
||||
}
|
||||
|
||||
export class Heroes {
|
||||
@@ -123,7 +125,8 @@ export default class PvpDefense extends BaseModel {
|
||||
challengeRefTime: number; // 上一次刷新的时间
|
||||
@prop({ required: true, default: [] })
|
||||
receivedBox: Array<number>;
|
||||
|
||||
@prop({ required: true, default: 0 })
|
||||
seasonNum: number;
|
||||
public static async findByRoleId(roleId: string, lean = true) {
|
||||
const result: PvpDefenseType = await PvpDefenseModel.findOne({ roleId }).lean(lean);
|
||||
return result;
|
||||
@@ -170,7 +173,7 @@ export default class PvpDefense extends BaseModel {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async findByRoleIdIncludeAll(roleId: string, lean = true) {
|
||||
public static async findByRoleIdIncludeAll(roleId: string) {
|
||||
const result: PvpDefenseType = await PvpDefenseModel.findOne({ roleId })
|
||||
.populate('role', 'headHid sHid topFiveCe roleId roleName')
|
||||
.populate('heroes.hero')
|
||||
@@ -201,6 +204,15 @@ export default class PvpDefense extends BaseModel {
|
||||
}).lean();
|
||||
return result;
|
||||
}
|
||||
public static async updateInfo(roleId: string, update: pvpUpdateInter, lean = true) {
|
||||
let result: PvpDefenseType = await PvpDefenseModel.findOneAndUpdate({roleId}, {$set:update}, {new: true}).lean(lean);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async getPvpDef(limitNum: number, lean = true) {
|
||||
let result: Array<PvpDefenseType> = await PvpDefenseModel.find().sort({ score: -1 }).limit(limitNum).lean(lean);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export const PvpDefenseModel = getModelForClass(PvpDefense);
|
||||
|
||||
@@ -15,6 +15,21 @@ export default class SystemConfig extends BaseModel {
|
||||
const result: SystemConfigType = await SystemConfigModel.findOne({ id: 1 }).lean(lean);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async createSystemConfig(seasonEndTime: number, warId: number, lean = true) {
|
||||
const result: SystemConfigType = await SystemConfigModel.findOneAndUpdate({ id: 1}, { seasonEndTime, warId }, { upsert: true, new: true }).lean(lean);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async updateSystemConfig(update: { seasonEndTime?: number, warId?: number, seasonNum?:number }, lean = true) {
|
||||
const result: SystemConfigType = await SystemConfigModel.findOneAndUpdate({ id: 1}, update, { upsert: true, new: true }).lean(lean);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async updateSeason( seasonEndTime: number, lean = true) {
|
||||
const result: SystemConfigType = await SystemConfigModel.findOneAndUpdate({ id: 1}, { $seasonEndTime: seasonEndTime, $inc: { seasonNum:1 } }, { upsert: true, new: true }).lean(lean);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export const SystemConfigModel = getModelForClass(SystemConfig);
|
||||
|
||||
+13
-2
@@ -39,7 +39,7 @@ import { ABI_TYPE_TO_STAGE } from "../consts";
|
||||
import { dicPvpOpponent } from './dictionary/DicPvpOpponent';
|
||||
import { dicPvpTeamLevel } from './dictionary/DicPvpTeamLevel';
|
||||
import { dicPvpRefreshConsume } from './dictionary/DicPvpRefreshConsume';
|
||||
|
||||
import { dicGkPvp, dicGkPvps } from './dictionary/DicGkPvp'
|
||||
export const gameData = {
|
||||
blurprtCompose: dicBlueprtCompose,
|
||||
blueprtPossibility: dicBlueprtPossibility,
|
||||
@@ -91,7 +91,9 @@ export const gameData = {
|
||||
pvpOpponent: dicPvpOpponent,
|
||||
pvpTeamLevel: dicPvpTeamLevel,
|
||||
pvpWar: dicWarPvp,
|
||||
pvpRefreshConsume: dicPvpRefreshConsume
|
||||
pvpRefreshConsume: dicPvpRefreshConsume,
|
||||
pvpGk: dicGkPvp,
|
||||
pvpGks: dicGkPvps,
|
||||
};
|
||||
|
||||
// 在此提供一些原先在gamedata中提供的方法,以便更方便获取gameData数据
|
||||
@@ -267,4 +269,13 @@ export function getPLvByScore(score: number) {
|
||||
if(score < topFiveMax) break;
|
||||
}
|
||||
return lv;
|
||||
}
|
||||
|
||||
export function getPvpGkByWarId (warId: number) {
|
||||
return gameData.pvpGk.get(warId);
|
||||
}
|
||||
|
||||
export function getPvpGkWarIds() {
|
||||
let warIds = gameData.pvpGks;
|
||||
return warIds;
|
||||
}
|
||||
@@ -27,3 +27,10 @@ export const SCHOOL = {
|
||||
export const SCROLL = {
|
||||
SCROLL_ACTIVE_FAVOUR: 50, // 首次激活增加的好感度
|
||||
};
|
||||
export const PVP = {
|
||||
PVP_CHALLENGE_COUNTS: 10, // pvp初始挑战次数
|
||||
PVP_CHALLENGE_NORMALTIMES: 120, // pvp日常挑战次数刷新时间(分钟)
|
||||
PVP_CHALLENGE_FINALTIMES: 60, // PVP赛季最后一天挑战次数刷新时间(分钟)
|
||||
PVP_SEASON_DAYS: 30, // PVP一个赛季的时间
|
||||
PVP_OPPONENT_FREEREFRESH: 3, // pvp挑战对手每日免费刷新次数
|
||||
};
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { readJsonFile } from '../util'
|
||||
import { FILENAME } from '../../consts'
|
||||
|
||||
export interface DicGkPvp {
|
||||
readonly war_id: number;
|
||||
readonly dispatchJsonId: number;
|
||||
readonly bg_img_id: number;
|
||||
readonly warType: number;
|
||||
}
|
||||
|
||||
const str = readJsonFile(FILENAME.DIC_GK_PVP);
|
||||
let arr = JSON.parse(str);
|
||||
|
||||
export const dicGkPvp = new Map<number, DicGkPvp>();
|
||||
export const dicGkPvps = new Array<number>();
|
||||
arr.forEach(o => {
|
||||
dicGkPvp.set(o.war_id, o);
|
||||
dicGkPvps.push(o.war_id);
|
||||
});
|
||||
@@ -1,157 +0,0 @@
|
||||
/**
|
||||
* 体力系统
|
||||
*/
|
||||
import { PvpDefenseModel, Heroes, OppPlayers, Robot, PvpDefenseType } from '../db/pvpDefense';
|
||||
import { RoleType } from '../db/Role';
|
||||
import { PVP_PLAYER_POS, 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";
|
||||
|
||||
|
||||
export async function initPvpInfo(role: RoleType) {
|
||||
let heroes: Array<Heroes> = [];
|
||||
//初始化最强5人阵容
|
||||
for (let i = 0; i < role.topFive.length; i++) {
|
||||
let item = role.topFive[i];
|
||||
if (item.hid) {
|
||||
heroes.push({
|
||||
actorId: item.hid,
|
||||
hero: item.hero,
|
||||
ce: item.ce,
|
||||
dataId: PVP_HERO_POS.START + i,
|
||||
order: i + 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
//初始化对手人阵容TODO
|
||||
let oppPlayers: Array<OppPlayers> = await refreshEnemies(role, 0, 1);
|
||||
|
||||
let result = await PvpDefenseModel.createPvpDefense({ roleId: role.roleId, roleName: role.roleName, role: role._id, heroes, oppPlayers, defCe: role.topFiveCe });
|
||||
//加入排行榜 TODO
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function checkPvp(role: RoleType) {
|
||||
let result = await PvpDefenseModel.findByRoleId(role.roleId);
|
||||
if (!!result)
|
||||
return result;
|
||||
result = await initPvpInfo(role);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回对手三人信息
|
||||
*
|
||||
* @param oppPlayers pvpDefense表中的oppPlayers字段,需要populate过的
|
||||
* @param pLv 玩家本人的队伍等级
|
||||
*/
|
||||
export function getEnemies(oppPlayers: OppPlayers[], winStreakNum: number) {
|
||||
let result = new Array<oppPlayersInter>();
|
||||
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,
|
||||
addScore: dicOpponent.score,
|
||||
plusScore: getPlusScore(winStreakNum)
|
||||
});
|
||||
} else {
|
||||
let opp = <PvpDefenseType>oppDef;
|
||||
let role = <RoleType>opp.role;
|
||||
let { roleId, roleName, headHid, sHid } = role;
|
||||
let { pLv, defCe } = opp;
|
||||
result.push({
|
||||
pos, roleId, roleName, headHid, sHid, pLv, defCe,
|
||||
addScore: dicOpponent.score,
|
||||
plusScore: getPlusScore(winStreakNum)
|
||||
});
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// TODO 刷新对手
|
||||
export async function refreshEnemies(role: RoleType, score: number, pLv: number) {
|
||||
let { roleId, topFiveCe } = role;
|
||||
let oppPlayers = new Array<OppPlayers>();
|
||||
let opp = dicPvpOpponent.values()
|
||||
for(let dicOpp of opp) {
|
||||
let flag = false; // 是否筛选成功
|
||||
if(score > 3000) { // TODO 将这个放到const
|
||||
flag = await matchPlayer(oppPlayers, roleId, pLv, dicOpp);
|
||||
// TODO 当前后分数段没有时,返回前一名的玩家
|
||||
if(!flag) flag = matchRobot(oppPlayers, topFiveCe, pLv, dicOpp);
|
||||
} else {
|
||||
flag = matchRobot(oppPlayers, topFiveCe, pLv, dicOpp);
|
||||
}
|
||||
if(!flag) continue;
|
||||
}
|
||||
|
||||
return oppPlayers;
|
||||
}
|
||||
|
||||
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);
|
||||
if(range.length <= 0) return false;
|
||||
|
||||
let index = getRandomIndexByLen(range.length);
|
||||
let result = range[index];
|
||||
if(!result) return false;
|
||||
if(result.roleId == roleId) {
|
||||
range.splice(index, 1);
|
||||
if(range.length <= 0) return false;
|
||||
index = getRandomIndexByLen(range.length);
|
||||
result = range[range.length];
|
||||
}
|
||||
|
||||
oppPlayers.push({
|
||||
oppDef: result._id,
|
||||
pos,
|
||||
isRobot: false,
|
||||
robot: null
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
function matchRobot(oppPlayers: OppPlayers[], myCe: number, pLv: number, dicOpp: DicPvpOpponent) {
|
||||
let { id: pos, minLv, maxLv, ratio } = dicOpp;
|
||||
let range = gameData.pvpWar;
|
||||
if(range.length <= 0) return false;
|
||||
|
||||
let index = getRandomIndexByLen(range.length);
|
||||
let result = range[index];
|
||||
if(!result) return false;
|
||||
|
||||
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)
|
||||
oppPlayers.push({
|
||||
oppDef: null,
|
||||
pos,
|
||||
isRobot: true,
|
||||
robot
|
||||
});
|
||||
return true
|
||||
}
|
||||
|
||||
// 生成机器人roleId
|
||||
function generateRobotRoleId() {
|
||||
return `${genCode(10)}_r`;
|
||||
}
|
||||
|
||||
// 根据roleId判断是不是机器人
|
||||
export function checkRoleIsRobot(roleId: string) {
|
||||
return !!roleId.match(/_r/);
|
||||
}
|
||||
|
||||
// 根据连胜次数,获得加成的积分
|
||||
export function getPlusScore(win: number) {
|
||||
let result = win - 1;
|
||||
if(result > 10) result = 10;
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
const PER_SECOND = 1 * 1000;
|
||||
const PER_DAY = 24 * 60 * 60;
|
||||
export function nowSeconds() {
|
||||
return Math.floor(Date.now() / PER_SECOND );
|
||||
}
|
||||
|
||||
export function getTodayZeroPoint() {
|
||||
var date = new Date();
|
||||
date.setHours(0);
|
||||
date.setMinutes(0);
|
||||
date.setSeconds(0);
|
||||
var time = Math.floor(date.getTime() / PER_SECOND);
|
||||
return time;
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import fs = require('fs');
|
||||
import path = require('path');
|
||||
import { DicRandomEffectPool } from './dictionary/DicRandomEffectPool';
|
||||
import { HERO_CE_RATIO, ABI_STAGE } from '../consts';
|
||||
import { PvpDefenseType } from '../db/PvpDefense';
|
||||
|
||||
const _ = require('underscore');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user