diff --git a/game-server/app/servers/guild/handler/gvgBattleHandler.ts b/game-server/app/servers/guild/handler/gvgBattleHandler.ts index fdea22b21..31e725426 100644 --- a/game-server/app/servers/guild/handler/gvgBattleHandler.ts +++ b/game-server/app/servers/guild/handler/gvgBattleHandler.ts @@ -1,6 +1,6 @@ import { GVGCityType } from './../../../db/GVGCity'; import { GVGRecModel } from '../../../db/GVGRec'; -import { GVGAreaInMap, GVGTeamInList, GVGTeamInListOnPoint, GVGTeamSpineInMap, LeagueGood, MyTeamInfo } from '../../../domain/gvgField/returnData'; +import { GVGAreaInMap, GVGTeamInList, GVGTeamInListOnPoint, GVGTeamSpineInMap, LeagueGood, MyTeamInfo, MyTeamSimpleInfo } from '../../../domain/gvgField/returnData'; import { GVGTeamModel, GVGTeamType, GVGTeamUpdate } from '../../../db/GVGTeam'; import { GVGUserDataModel } from '../../../db/GVGUserData'; import { GVGCityModel } from '../../../db/GVGCity'; @@ -23,6 +23,7 @@ import { sendMessageToUserWithSuc } from '../../../services/pushService'; import { GVGHeroInfo } from '../../../domain/dbGeneral'; import { ArtifactModel } from '../../../db/Artifact'; import { getHeroesAttributes } from '../../../services/playerCeService'; +import { gvgBattleStartSchedule } from '../../../services/timeTaskService'; export default function (app: Application) { new HandlerService(app, {}); @@ -40,8 +41,8 @@ export class GVGBattleHandler { async getTeams(msg: {}, session: BackendSession) { const roleId = session.get('roleId'); const teams = await GVGTeamModel.findByRole(roleId, '-_id teamCode index head frame spine lineup') - - return resResult(STATUS.SUCCESS, { teams }); + + return resResult(STATUS.SUCCESS, { teams: teams.map(team => new MyTeamSimpleInfo(team)) }); } // 保存队伍 @@ -101,7 +102,7 @@ export class GVGBattleHandler { if (!team) { return resResult(STATUS.GVG_SAVE_TEAM_FAILED); } - return resResult(STATUS.SUCCESS, { curTeam: pick(team, ['teamCode', 'index', 'head', 'frame', 'spine', 'lineup']) }); + return resResult(STATUS.SUCCESS, { curTeam: new MyTeamSimpleInfo(team) }); } // 获取城池信息 @@ -509,4 +510,8 @@ export class GVGBattleHandler { // ! 重新组织每个城市的数据,添加据点和积分点的信息 return resResult(STATUS.SUCCESS, { cities }); } + + async debugStartSchedule() { + await gvgBattleStartSchedule(); + } } diff --git a/game-server/app/servers/guild/handler/gvgFightHandler.ts b/game-server/app/servers/guild/handler/gvgFightHandler.ts index afabc1a37..452c9b758 100644 --- a/game-server/app/servers/guild/handler/gvgFightHandler.ts +++ b/game-server/app/servers/guild/handler/gvgFightHandler.ts @@ -145,7 +145,7 @@ export class GVGProduceHandler { let dicWarJson = gameData.warJson.get(dicWar.dispatchJsonId); result.setRobot(dicGVGVestige, dicWarJson, serverNames[serverId]); } else { - let hisVestigeRank = await GVGVestigeRankModel.findByRole(vestigeId, roleId); + let hisVestigeRank = await GVGVestigeRankModel.findByRole(vestigeId, targetRoleId); if(!hisVestigeRank) return resResult(STATUS.GVG_VESTIGE_TARGET_NOT_FOUND); let role = await RoleModel.findByRoleId(hisVestigeRank.roleId, 'roleId roleName serverId guildName title lv heads head spines spine frames frame') diff --git a/game-server/app/servers/guild/handler/gvgHandler.ts b/game-server/app/servers/guild/handler/gvgHandler.ts index bae24924a..5b0370ece 100644 --- a/game-server/app/servers/guild/handler/gvgHandler.ts +++ b/game-server/app/servers/guild/handler/gvgHandler.ts @@ -1,9 +1,9 @@ import { Application, BackendSession, ChannelService, HandlerService, pinus } from "pinus"; -import { GVG_ITEM, DATA_NAME, GVG_ACTIVE_TYPE, GVG_PERIOD, GVG_SERVER_TYPE, ITEM_CHANGE_REASON, LEAGUE_JOB, LEAGUE_MANAGE_TYPE, STATUS, GVG_REC_TYPE, TASK_TYPE } from "../../../consts"; +import { GVG_ITEM, DATA_NAME, GVG_ACTIVE_TYPE, GVG_PERIOD, GVG_SERVER_TYPE, ITEM_CHANGE_REASON, LEAGUE_JOB, LEAGUE_MANAGE_TYPE, STATUS, GVG_REC_TYPE, TASK_TYPE, GVG_TECH_TYPE } from "../../../consts"; import { GVGLeagueModel } from "../../../db/GVGLeague"; import { GVGLeaguePrepareModel } from "../../../db/GVGLeaguePrepare"; import { GVGMainData, LeagueContributeInfo, LeagueMemberContributeInfo, LeagueMemberListInfo } from "../../../domain/gvgField/returnData"; -import { resResult } from "../../../pubUtils/util"; +import { getRandEelm, resResult } from "../../../pubUtils/util"; import { calLeagueCe, getGroupIdOfServer, getGVGConfig, getGVGPeriodData, getGVGServerType, getServerTypeByTime } from "../../../services/gvg/gvgService"; import { autoCreateLeague, checkCanChooseJob, checkCanPrepare, checkLeagueAuth, getMyAuth } from "../../../services/gvg/gvgTeamService"; import { getAllServerName } from "../../../services/redisService"; @@ -421,6 +421,14 @@ export class GVGHandler { let curQueue = leaguePrepare.techQueue.find(cur => cur.id == techId); if(curQueue.progress >= curQueue.maxProgress) { leaguePrepare = await GVGLeaguePrepareModel.activate(configId, myLeague.leagueCode, techId); + // 发放连弩 + if(dicTech.type == GVG_TECH_TYPE.BATTLE_ITEM_KNIFE) { + let members = myLeague.members||[]; + let randMembers = getRandEelm(members, dicTech.param[0]); + for(let { roleId } of randMembers) { + await addGVGReward(roleId, '', myLeague.leagueCode, null, [{ id: GVG_ITEM.KNIFE, count: dicTech.param[1] }], [], ITEM_CHANGE_REASON.GVG_TECH_SEND_KNIFE); + } + } } // 添加 活跃 diff --git a/game-server/app/servers/guild/remote/guildRemote.ts b/game-server/app/servers/guild/remote/guildRemote.ts index 372c2c649..d856a230c 100644 --- a/game-server/app/servers/guild/remote/guildRemote.ts +++ b/game-server/app/servers/guild/remote/guildRemote.ts @@ -8,6 +8,7 @@ import { setHiddenData } from '../../../services/dataService'; import { setKvToMemory } from '../../../services/pushService'; import { getGVGConfig, setGVGConfig, setGVGServerGroup } from '../../../services/gvg/gvgService'; import { GVGConfigType } from '../../../db/GVGConfig'; +import { catapultHurt, gvgBattleStart, initCatapult } from '../../../services/gvg/gvgBattleService'; export default function (app: Application) { new HandlerService(app, {}); @@ -118,4 +119,28 @@ export class GuildRemote { errlogger.error(`remote ${__filename} \n ${e.stack}`); } } + + public async gvgBattleStart() { + try { + return await gvgBattleStart(); + } catch(e) { + errlogger.error(`remote ${__filename} \n ${e.stack}`); + } + } + + public async initCatapult(cityId: number, groupId: number, serverType: number, leagueCode: string, leagueName: string) { + try { + return await initCatapult(cityId, groupId, serverType, leagueCode, leagueName); + } catch(e) { + errlogger.error(`remote ${__filename} \n ${e.stack}`); + } + } + + public async catapultHurt() { + try { + return await catapultHurt(); + } catch(e) { + errlogger.error(`remote ${__filename} \n ${e.stack}`); + } + } } \ No newline at end of file diff --git a/game-server/app/services/gvg/gvgBattleMemory.ts b/game-server/app/services/gvg/gvgBattleMemory.ts index 9a35852dc..38fd8ae20 100644 --- a/game-server/app/services/gvg/gvgBattleMemory.ts +++ b/game-server/app/services/gvg/gvgBattleMemory.ts @@ -1,7 +1,7 @@ // 存在激战期的内存数据 import { pinus } from "pinus"; -import { GVG_PERIOD } from "../../consts"; +import { GVG_CATAPULT, GVG_PERIOD } from "../../consts"; import { GVGTeamModel, GVGTeamType } from "../../db/GVGTeam"; import { GVGTeamMem } from "../../domain/battleField/gvgBattle"; import { dispatch } from "../../pubUtils/dispatcher"; @@ -34,6 +34,18 @@ class GVGBattleData { return teams.slice(0, 20); } + public findCatapultAttackTeam(areaIds: number[], leagueCode: string) { + let teams: string[] = []; + for(let areaId of areaIds) { + let teamCodes = this.areaToTeams.get(areaId)||new Set(); + for(let teamCode of teamCodes) { + let team = this.teams.get(teamCode); + if(team && team.leagueCode != leagueCode && !team.isRobot) teams.push(teamCode); + } + } + return teams; + } + public leaveCity(roleId: string) { let teamCodes = this.roleToTeam.get(roleId)||[]; for(let teamCode of teamCodes) { @@ -117,11 +129,17 @@ class GVGBattleData { this.enterCity(team); continue; } let { areaId: fromAreaId, pointId: fromPointId } = teamMem; - teamMem.battleEnd(team); + teamMem.updateTeam(team); this.setRolePoints(team.roleId, fromPointId, team.pointId); this.setAreaMap(team.teamCode, fromAreaId, team.areaId); } } + + // 投石车 + public findCatapult() { + let teamCodes = this.roleToTeam.get(GVG_CATAPULT)||[]; + return teamCodes.map(teamCode => this.teams.get(teamCode)); + } } export function getGVGBattleData(groupId: number, serverType: number) { @@ -132,11 +150,15 @@ export function getGVGBattleData(groupId: number, serverType: number) { return gvgBattleMap.get(key); } +export function getGVGBattleMap() { + return gvgBattleMap; +} + export async function initTeamToMem() { let sid = pinus.app.getServerId(); let servers = pinus.app.getServersByType('guild'); let { configId, period } = getGVGPeriodData(); - if(period != GVG_PERIOD.BATTLE) return; + // if(period != GVG_PERIOD.BATTLE) return; let teams = await GVGTeamModel.findByConfigId(configId); for(let team of teams) { if(dispatch(team.cityId.toString(), servers)?.id == sid) { diff --git a/game-server/app/services/gvg/gvgBattleService.ts b/game-server/app/services/gvg/gvgBattleService.ts index 9facc2fa1..2757b9430 100644 --- a/game-server/app/services/gvg/gvgBattleService.ts +++ b/game-server/app/services/gvg/gvgBattleService.ts @@ -3,14 +3,18 @@ import { GVGLeagueType } from "../../db/GVGLeague"; import { GVGTeamModel, GVGTeamType, GVGTeamUpdate } from "../../db/GVGTeam"; import { GVGCityModel, GVGCityType } from "../../db/GVGCity"; import { gameData } from "../../pubUtils/data"; -import { STATUS } from "../../consts"; +import { GVG_AREA_TYPE, GVG_TECH_TYPE, STATUS } from "../../consts"; import { nowSeconds } from "../../pubUtils/timeUtil"; import { DicGVGAreaPoint } from "../../pubUtils/dictionary/DicGVGAreaPoint"; -import { getGVGBattleData } from "./gvgBattleMemory"; +import { getGVGBattleData, getGVGBattleMap } from "./gvgBattleMemory"; import { GVGCityMapInfo } from "../../domain/gvgField/returnData"; import { pick } from "underscore"; import { GVG } from "../../pubUtils/dicParam"; import { GVGHeroInfo, PvpEnemies, PvpHeroInfo } from "../../domain/dbGeneral"; +import { getGVGConfig } from "./gvgService"; +import { GVGLeaguePrepareModel } from "../../db/GVGLeaguePrepare"; +import { pinus } from "pinus"; +import { dispatch } from "../../pubUtils/dispatcher"; /** @@ -63,6 +67,7 @@ export function getBirthAreaOfCity(city: GVGCityType, leagueCode: string) { return isGuard? dicGVGCity.defenseBirth: dicGVGCity.attackBirth; } +// guild.gvgBattleHandler.startMove 检测 export function checkMoveStatus(team: GVGTeamType, cityId: number, areaId: number) { if(!team) return STATUS.GVG_BATTLE_TEAM_NOT_FOUND; if(team.cityId != cityId) return STATUS.GVG_BATTLE_IS_NOT_IN_CITY; @@ -122,6 +127,7 @@ export function getGVGWarId(defenseTeam: GVGTeamType) { return GVG.GVG_ROBOT_WARJSON; // 据点守卫使用 } +// guild.gvgBattleHandler.battleStart 里的heroes返回 export function getOppHeroes(warId: number, isRobot: boolean, lineup: GVGHeroInfo[]) { let heroes: PvpEnemies[] = []; const dicWar = gameData.war.get(warId); @@ -147,6 +153,7 @@ export function getOppHeroes(warId: number, isRobot: boolean, lineup: GVGHeroInf return heroes } +// guild.gvgBattleHandler.battleStart 检测 export function checkGVGBattleStart(roleId: string, attackTeam: GVGTeamType, defenseTeam: GVGTeamType) { if(!attackTeam || !defenseTeam) return STATUS.GVG_BATTLE_TEAM_INVALID; @@ -160,4 +167,58 @@ export function checkGVGBattleStart(roleId: string, attackTeam: GVGTeamType, def if(defenseTeam.durability <= 0) return STATUS.GVG_DEFENSE_TEAM_BROKEN; return STATUS.SUCCESS; +} + +// gvg激战期开始定时器 +export async function gvgBattleStart() { + let servers = pinus.app.getServersByType('guild'); + + let { configId } = getGVGConfig(); + let guardCities = await GVGCityModel.findAllGuardCities(configId); + for(let { cityId, groupId, serverType, guardLeague, guardLeagueName } of guardCities) { + let sid = dispatch(cityId.toString(), servers)?.id; + await pinus.app.rpc.guild.guildRemote.initCatapult.toServer(sid, cityId, groupId, serverType, guardLeague, guardLeagueName); + } +} + +// 每次活动开始初始化投石车 +export async function initCatapult(cityId: number, groupId: number, serverType: number, leagueCode: string, leagueName: string) { + let { configId } = getGVGConfig(); + + let leaguePrepare = await GVGLeaguePrepareModel.findByLeague(configId, leagueCode); + let activeTech = leaguePrepare?.activeTech||[]; + let hasCatapult = false, atk = 0, durability = 0; + for(let techId of activeTech) { + let dicTech = gameData.gvgTech.get(techId); + if(dicTech && dicTech.type == GVG_TECH_TYPE.BATTLE_ITEM_CATAPULT) { + hasCatapult = true, atk = dicTech.param[0]; durability = dicTech.param[1]; + } + } + if(hasCatapult) { + let dicCity = gameData.gvgCity.get(cityId); + let areaIds = (dicCity?.areaIds||[]).filter(areaId => { + let dicArea = gameData.gvgArea.get(areaId); + return dicArea && dicArea.areaType == GVG_AREA_TYPE.CATAPULT; + }); + let teams = await GVGTeamModel.initCatapult(configId, groupId, serverType, cityId, leagueCode, leagueName, areaIds, atk, durability); + // 处理内存 + let teamObj = getGVGBattleData(groupId, serverType); + teamObj.enterCity(...teams); + } +} + +// 投石车投伤害 +export async function catapultHurt() { + for(let [_, teamObj] of getGVGBattleMap()) { + let teams = teamObj.findCatapult(); + for(let catapult of teams) { + if(catapult.isBroken) continue; + let dicArea = gameData.gvgArea.get(catapult.areaId); + let relateArea = dicArea?.relateArea||[]; + let teamCodes = teamObj.findCatapultAttackTeam(relateArea, catapult.leagueCode); + let dicGVGCity = gameData.gvgCity.get(catapult.cityId); + let teams = await GVGTeamModel.attackByCatapult(teamCodes, catapult.captapultAtk, dicGVGCity.attackBirth) + teamObj.battleEnd(teams); + } + } } \ No newline at end of file diff --git a/game-server/app/services/gvg/gvgFightService.ts b/game-server/app/services/gvg/gvgFightService.ts index a2e2fa762..68224802e 100644 --- a/game-server/app/services/gvg/gvgFightService.ts +++ b/game-server/app/services/gvg/gvgFightService.ts @@ -31,13 +31,13 @@ import { addVestigeLeagueRankRec } from "./gvgRecService"; import { getGroupIdOfServer, getGVGServerType } from "./gvgService"; // 备战期的遗迹和激战期的开始结束战斗时间 -export function getFightTimeByPeriod(period: GVG_PERIOD) { +export function getFightTimeByPeriod(period: GVG_PERIOD, time?: number) { let dicPeriod = gameData.gvgPeriod.get(period); if(!dicPeriod) return { startFightTime: 0, endFightTime: 0 }; return { - startFightTime: getTimeFun().getTimeWithHour(dicPeriod.startHour, dicPeriod.startMinute, dicPeriod.startSecond), - endFightTime: getTimeFun().getTimeWithHour(dicPeriod.endHour, dicPeriod.endMinute, dicPeriod.endSecond), + startFightTime: getTimeFun(time).getTimeWithHour(dicPeriod.startHour, dicPeriod.startMinute, dicPeriod.startSecond), + endFightTime: getTimeFun(time).getTimeWithHour(dicPeriod.endHour, dicPeriod.endMinute, dicPeriod.endSecond), } } diff --git a/game-server/app/services/gvg/gvgService.ts b/game-server/app/services/gvg/gvgService.ts index 4be10b383..2cf1b3ea6 100644 --- a/game-server/app/services/gvg/gvgService.ts +++ b/game-server/app/services/gvg/gvgService.ts @@ -32,6 +32,7 @@ export async function createNewGVGConfig() { if(!await checkHasCities(league)) needDissmissLeagueId.push(league._id); } await GVGLeagueModel.dismissByIds(needDissmissLeagueId); + await pinus.app.rpc.systimer.systimerRemote.initGVGConfigSchedule.broadcast(); return config; } diff --git a/game-server/app/services/timeTaskService.ts b/game-server/app/services/timeTaskService.ts index 0b65aad20..529c838da 100644 --- a/game-server/app/services/timeTaskService.ts +++ b/game-server/app/services/timeTaskService.ts @@ -5,7 +5,7 @@ import { nowSeconds, getTimeFun, getSeconds } from '../pubUtils/timeUtil'; import { getTodayGuildActivity, gameData } from '../pubUtils/data'; import { pvpSeasonEnd } from './pvpService'; import { getAllOnlineRoles, getAllServers, delGuildActivityRank, getServerCreateTime } from './redisService'; -import { GUILD_ACTIVITY_TYPE, REFRESH_TIME, COUNTER, AUCTION_TIME, GM_MAIL_TYPE, SERVER_TIMER, ACTIVITY_TYPE, PUSH_ROUTE, STATUS, LADDER_STATUS, LADDER_SERVER_GAP_TIME } from '../consts'; +import { GUILD_ACTIVITY_TYPE, REFRESH_TIME, COUNTER, AUCTION_TIME, GM_MAIL_TYPE, SERVER_TIMER, ACTIVITY_TYPE, PUSH_ROUTE, STATUS, LADDER_STATUS, LADDER_SERVER_GAP_TIME, GVG_PERIOD } from '../consts'; import { pinus } from 'pinus'; import { settleGuildWeekly } from './guildService'; import { SendMailFun, sendMailsByGmMail, } from './mailService'; @@ -16,7 +16,7 @@ import { dispatch } from '../pubUtils/dispatcher'; import { createNewServer, initMarquee, setServerMainten } from './gmService'; import moment = require('moment'); import { reportOneOnline } from './authenticateService'; -import { LADDER, PVP } from '../pubUtils/dicParam'; +import { GVG, LADDER, PVP } from '../pubUtils/dicParam'; import { fetch37Words } from './sdkService'; import { GMMailModel, GMMailType } from '../db/GMMail'; import { Maintenance, ServerlistModel, ServerlistType } from '../db/Serverlist'; @@ -44,7 +44,7 @@ import { HiddenDataModel, HiddenDataModelType } from '../db/HiddenData'; import { setHiddenData, setHiddenDataToMemory } from './dataService'; import { GVGConfigModel } from '../db/GVGConfig'; import { createNewGVGConfig, initLeaguePrepare } from './gvg/gvgService'; -import { saveVestigeRankSchedule } from './gvg/gvgFightService'; +import { getFightTimeByPeriod, saveVestigeRankSchedule } from './gvg/gvgFightService'; const PER_SECOND = 1 * 1000; const PER_DAY = 24 * 60 * 60; @@ -913,5 +913,54 @@ export async function initGVGConfigSchedule() { } scheduleJob('gvgFightSchedule', '0 0 22 * * ?', saveVestigeRankSchedule); + + let { startFightTime, endFightTime } = getFightTimeByPeriod(GVG_PERIOD.BATTLE, config.battleTime); + + scheduleJob(`gvgBattleStartSchedule`, startFightTime * 1000, gvgBattleStartSchedule); + scheduleJob(`gvgBattleEndSchedule`, endFightTime * 1000, gvgBattleEndSchedule); +} + +let gvgBattleSecondJob: Job; // gvg每5秒的定时器 +let gvgBattleCatapultJob: Job; // gvg投石车定时器 + +// gvg激战期开始定时器 +export async function gvgBattleStartSchedule() { + // 初始化投石车 + let guildServers = pinus.app.getServersByType('guild'); + if(guildServers.length > 0) { + pinus.app.rpc.guild.guildRemote.gvgBattleStart.toServer(guildServers[0].id); + } + // 发放道具 + if(gvgBattleSecondJob) gvgBattleSecondJob.cancel(); + gvgBattleSecondJob = scheduleJob('gvgBattleSecondJob', '*/5 * * * * *', gvgBattleSecondSchedule); + if(gvgBattleCatapultJob) gvgBattleCatapultJob.cancel(); + gvgBattleCatapultJob = scheduleJob('gvgBattleCatapultJob', `*/${GVG.GVG_CATAPULT_TIME} * * * * *`, gvgBattleCatapult); +} + +// 每隔5秒的积分计算定时器 +async function gvgBattleSecondSchedule() { + // console.log('********** gvgBattleSecondJob *************'); +} + +// 每隔10秒的投石车投机定时器 +async function gvgBattleCatapult() { + console.log('********** gvgBattleCatapultJob *************'); + pinus.app.rpc.guild.guildRemote.catapultHurt.broadcast(); +} + +// gvg激战期结束定时器 +async function gvgBattleEndSchedule() { + // 排行榜发放奖励 + // 城池占领情况 + // 定时器关闭 + if(gvgBattleSecondJob) { + gvgBattleSecondJob.cancel(); + gvgBattleSecondJob = undefined; + } + if(gvgBattleCatapultJob) { + gvgBattleCatapultJob.cancel(); + gvgBattleCatapultJob = undefined; + } + } // —————————————— gvg end —————————————— // \ No newline at end of file diff --git a/shared/consts/constModules/gvgConst.ts b/shared/consts/constModules/gvgConst.ts index 9d1b30b72..fe4cb5587 100644 --- a/shared/consts/constModules/gvgConst.ts +++ b/shared/consts/constModules/gvgConst.ts @@ -75,6 +75,7 @@ export enum GVG_ITEM { PRODUCE_COIN = 10, // 内政令 FIGHT_COIN = 11, // 征战令 BATTLE_FEAT = 12, // 战功 + KNIFE = 14, // 诸葛连弩 } export enum GVG_RESOURCE_TYPE { @@ -130,4 +131,15 @@ export enum VESTIGE_STATUS { CHECK = 1, // 出兵中 BATTLE = 2, // 战斗中 COMPLETE = 3, // 战斗结束 - } \ No newline at end of file +} + +export enum GVG_AREA_TYPE { + DEFENSER = 1, // 1-守方备战区 + ATTACKER = 2, // 2-攻方备战区 + BIG = 3, // 3-大据点区 + MIDDLE = 4, // 4-中据点区 + SMALL = 5, // 5-小据点区 + CATAPULT = 6, // 6-投石车区 +} + +export const GVG_CATAPULT = 'catapult'; \ No newline at end of file diff --git a/shared/consts/constModules/sysConst.ts b/shared/consts/constModules/sysConst.ts index 7ce9b702e..d7b9cd806 100644 --- a/shared/consts/constModules/sysConst.ts +++ b/shared/consts/constModules/sysConst.ts @@ -1116,6 +1116,7 @@ export enum ITEM_CHANGE_REASON { GVG_VESTIGE_START = 170, // gvg征战中原挑战 GVG_VESTIGE_END = 171, // gvg征战中原挑战 GVG_VESTIGE_RECEIVE_RANK = 172, // gvg征战中原领取排行榜奖励 + GVG_TECH_SEND_KNIFE = 173, // gvg点科技树发放诸葛连弩 } export enum TA_EVENT { diff --git a/shared/db/GVGCity.ts b/shared/db/GVGCity.ts index 371b2530d..b50c42ffa 100644 --- a/shared/db/GVGCity.ts +++ b/shared/db/GVGCity.ts @@ -75,6 +75,12 @@ export default class GVGCity extends BaseModel { const cities: GVGCityType[] = await GVGCityModel.find({ configId, groupId, serverType, hasGuard: true }).lean(); return cities } + + // 查询有联军驻守的城池 + public static async findAllGuardCities(configId: number) { + const cities: GVGCityType[] = await GVGCityModel.find({ configId, hasGuard: true }).lean(); + return cities + } } diff --git a/shared/db/GVGLeaguePrepare.ts b/shared/db/GVGLeaguePrepare.ts index 82d3237a7..e6e6fe581 100644 --- a/shared/db/GVGLeaguePrepare.ts +++ b/shared/db/GVGLeaguePrepare.ts @@ -141,6 +141,11 @@ export default class GVGLeaguePrepare extends BaseModel { const result: GVGLeaguePrepareType = await GVGLeaguePrepareModel.findOneAndUpdate({ configId, leagueCode }, { $set: { lv }}, { new: true }).lean(); return result; } + + public static async findByConfigId(configId: number) { + const result: GVGLeaguePrepareType[] = await GVGLeaguePrepareModel.aggregate([{ $match: {configId} }]); + return result; + } } export const GVGLeaguePrepareModel = getModelForClass(GVGLeaguePrepare); diff --git a/shared/db/GVGTeam.ts b/shared/db/GVGTeam.ts index 7c1ac992e..52f41854c 100644 --- a/shared/db/GVGTeam.ts +++ b/shared/db/GVGTeam.ts @@ -3,10 +3,11 @@ import BaseModel from "./BaseModel"; import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; import { genCode } from "../pubUtils/util"; import { nowSeconds } from "../pubUtils/timeUtil"; -import { GVG } from "../pubUtils/dicParam"; +import { EXTERIOR, GVG } from "../pubUtils/dicParam"; import { DicGVGAreaPoint } from "../pubUtils/dictionary/DicGVGAreaPoint"; import { InitTeamParam, SaveTeamUpdateParam } from "../domain/gvgField/gvgDb"; import { GVGHeroInfo } from "../domain/dbGeneral"; +import { GVG_CATAPULT } from "../consts"; @index({ roleId: 1, index: 1 }) @index({ teamCode: 1 }) @@ -106,12 +107,18 @@ export default class GVGTeam extends BaseModel { @prop({ required: true, default: false }) isRobot: boolean; // 是否是机器人 + @prop({ required: true, default: false }) + captapultAtk: number; // 投石车的攻击力 + @prop({ required: true, default: false }) isCatapult: boolean; // 是否是投石车 @prop({ required: true, default: false }) isBroken: boolean; // 机器人是否被击破,如果没有被击破,那么这个位置上就还是机器人,如果被击破了,这个位置就空出给玩家 + @prop({ required: false }) + batchCode: string; // 批量编号 + // 创建队伍 public static async saveTeam(roleId: string, index: number, updateParam: SaveTeamUpdateParam, initParam: InitTeamParam) { const doc = new GVGTeamModel(); @@ -192,7 +199,10 @@ export default class GVGTeam extends BaseModel { return { updateOne: { filter: { groupId, serverType, cityId, areaId, pointId }, - update: { $setOnInsert: { teamCode: genCode(8), maxDurability: durability, roleName: name, head, spine, lineupCe: ce, isRobot: true, isBroken: false, startMoveTime: 0, stopMoveTime: 0 }, $set: { configId, durability } }, + update: { $setOnInsert: { + teamCode: genCode(8), maxDurability: durability, roleName: name, head, spine, frame: EXTERIOR.EXTERIOR_FACECASE, lineupCe: ce, isRobot: true, + isBroken: false, startMoveTime: 0, stopMoveTime: 0, guildCode: '', leagueCode: '', leagueName: '' + }, $set: { configId, durability } }, upsert: true } } @@ -200,6 +210,30 @@ export default class GVGTeam extends BaseModel { return await this.findRobotTeams(groupId, serverType, cityId); } + public static async findCatapultTeams(groupId: number, serverType: number, cityId: number) { + const team: GVGTeamType[] = await GVGTeamModel.find({ groupId, serverType, cityId, isRobot: true, isCatapult: true }).lean(); + return team; + } + + // 生成投石车 + public static async initCatapult(configId: number, groupId: number, serverType: number, cityId: number, leagueCode: string, leagueName: string, areaIds: number[], atk: number, durability: number) { + await GVGTeamModel.bulkWrite(areaIds.map(areaId => { + return { + updateOne: { + filter: { groupId, serverType, cityId, areaId }, + update: { $setOnInsert: { + teamCode: genCode(8), maxDurability: durability, captapultAtk: atk, leagueCode, leagueName, + roleName: GVG.GVG_CATAPULT_NAME, head: GVG.GVG_CATAPULT_HEAD, spine: GVG.GVG_CATAPULT_SPINE, frame: EXTERIOR.EXTERIOR_FACECASE, lineupCe: GVG.GVG_CATAPULT_CE, + isRobot: true, isCatapult: true, + isBroken: false, startMoveTime: 0, stopMoveTime: 0, guildCode: '', pointId: 0, roleId: GVG_CATAPULT + }, $set: { configId, durability } }, + upsert: true + } + } + })); + return await this.findCatapultTeams(groupId, serverType, cityId); + } + // 攻击方攻击cd public static async battleStartLockAttack(teamCode: string) { const team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { attackTime: nowSeconds() + GVG.GVG_DEFAULT_ATTACK_CD } }, { new: true }).lean(); @@ -256,6 +290,19 @@ export default class GVGTeam extends BaseModel { return await GVGTeamModel.exists({ configId, groupId, serverType, pointId }); } + // 投石车伤害 + public static async attackByCatapult(teamCodes: string[], inc: number, rebirthAreaId: number) { + let batchCode = genCode(8); + await GVGTeamModel.updateMany({ teamCode: { $in: teamCodes } }, { $inc: { durability: -inc }, $set: { batchCode } }); + let brokenTeams: GVGTeamType[] = await GVGTeamModel.find({ batchCode, durability: { $lte: 0 } }).lean(); + if(brokenTeams.length > 0) { + await GVGTeamModel.bulkWrite(brokenTeams.map(({ teamCode, maxDurability }) => { + return { updateOne: { filter: { teamCode }, update: { $set: { areaId: rebirthAreaId, pointId: 0, durability: maxDurability } }}} + })); + } + let teams: GVGTeamType[] = await GVGTeamModel.find({ batchCode }).lean(); + return teams + } } diff --git a/shared/domain/battleField/gvgBattle.ts b/shared/domain/battleField/gvgBattle.ts index 6c731f911..578f0a1ca 100644 --- a/shared/domain/battleField/gvgBattle.ts +++ b/shared/domain/battleField/gvgBattle.ts @@ -1,4 +1,5 @@ import GVGTeam, { GVGTeamType } from "../../db/GVGTeam"; +import { nowSeconds } from "../../pubUtils/timeUtil"; // 积分点分类统计,1-3级积分点代表从小到大 export class LeagueCityPoint { @@ -25,27 +26,14 @@ export class GVGTeamMem extends GVGTeam { constructor(team: GVGTeamType) { super(); - this.roleId = team.roleId; - this.roleName = team.roleName; - this.serverId = team.serverId; - this.teamCode = team.teamCode; - this.index = team.index; - this.leagueCode = team.leagueCode; - this.guildCode = team.guildCode; - this.areaId = team.areaId; - this.fromAreaId = team.fromAreaId; - this.cityId = team.cityId; - this.pointId = team.pointId; - this.head = team.head; - this.spine = team.spine; - this.frame = team.frame; - this.durability = team.durability; - this.restartTime = team.restartTime; - this.attackTime = team.attackTime; - this.defenseTime = team.defenseTime; - this.startMoveTime = team.startMoveTime; - this.stopMoveTime = team.stopMoveTime; - this.score = team.score; + this.updateTeam(team); + } + + public updateTeam(team: GVGTeamType) { + for(let key in team) { + this[key] = team[key]; + } + this.isMoving = this.stopMoveTime > nowSeconds(); } public setCity(cityId: number, areaId = 0, pointId = 0) { @@ -60,11 +48,4 @@ export class GVGTeamMem extends GVGTeam { this.startMoveTime = startMoveTime; this.stopMoveTime = stopMoveTime; } - - public battleEnd(team: GVGTeamType) { - this.durability = team.durability; - this.restartTime = team.restartTime; - this.defenseTime = team.defenseTime; - this.stopMoveTime = team.stopMoveTime; - } } diff --git a/shared/domain/gvgField/returnData.ts b/shared/domain/gvgField/returnData.ts index 6792f50ef..f5f189f5d 100644 --- a/shared/domain/gvgField/returnData.ts +++ b/shared/domain/gvgField/returnData.ts @@ -623,6 +623,10 @@ export class GVGTeamSpineInMap { isMoving: boolean = false; pointId: number = 0; fromAreaId: number = 0; + teamCode: string = ''; + leagueCode: string = ''; + leagueName: string = ''; + constructor(obj: GVGTeamMem, serverNames: {[serverId: string]: string}) { this.spine = obj.spine; @@ -633,6 +637,9 @@ export class GVGTeamSpineInMap { this.isMoving = nowSeconds() < this.stopMoveTime; this.pointId = obj.pointId; this.fromAreaId = obj.fromAreaId; + this.teamCode = obj.teamCode; + this.leagueCode = obj.leagueCode; + this.leagueName = obj.leagueName; } } @@ -680,6 +687,27 @@ export class GVGTeamInListOnPoint extends GVGTeamInList { } } +export class MyTeamSimpleInfo { + teamCode: string; // 队伍唯一id + index: number; // 队伍位置 + head: number; // 保存头像 + frame: number; // 保存相框 + spine: number; // 保存形象 + lineup: { + actorId: number; // 武将 + dataId: number; // 出兵表上的位置 + order: number; // 行动 + }[]; + + constructor(team: GVGTeamType) { + this.teamCode = team.teamCode; + this.index = team.index; + this.head = team.head; + this.frame = team.spine; + this.lineup = team.lineup.map(({ actorId, dataId, outIndex }) => ({ actorId, dataId, order: outIndex })); + } +} + // 更新自己队伍时候的比较详细点的数据 export class MyTeamInfo { teamCode: string; // 队伍唯一id diff --git a/shared/pubUtils/dicParam.ts b/shared/pubUtils/dicParam.ts index 49564e302..8ed563290 100644 --- a/shared/pubUtils/dicParam.ts +++ b/shared/pubUtils/dicParam.ts @@ -371,14 +371,15 @@ export const ARTIFACT = { }; export const GUIDE = { GUIDE_FINGER_GK: 104, // 需要手指软引导的关卡 + GUIDE_DEFEAT_GK: 104, // 通过该关卡后开启首次失败引导 }; export const GVG = { GVG_LEAGUE_COMPOSE: 3, // 一个联军有最多多少军团组成 GVG_CROSS_SERVICE_STARTTIME: 4, // 开服几周后开始跨服玩法 GVG_ROLE_TOTAL_RATIO: 1.2, // 贤臣+猛将总人数上限系数 - GVG_ROLE_RATIO: 1.2, // 贤臣/猛将各职能选择人数上限系数 - GVG_PRODUCER_GET: '10&4|11&2', // 贤臣每天发多少令 - GVG_FIGHTER_GET: '10&2|11&4', // 猛将每天发多少令 + GVG_ROLE_RATIO: 1, // 贤臣/猛将各职能选择人数上限系数 + GVG_PRODUCER_GET: '10&6|11&2', // 贤臣每天发多少令 + GVG_FIGHTER_GET: '10&2|11&6', // 猛将每天发多少令 GVG_LEAGUE_TECH_LIST: 3, // 科技树解锁队列数量 GVG_LEAGUE_ACTIVE_POINT: '1&2|2&2|3&2|4&2', // 活跃的来源 GVG_SERVICETYPE_VESTIGE: '1&1|2&3', // 单服和跨服随机出几个遗迹点