diff --git a/game-server/app.ts b/game-server/app.ts index 64d156bae..ad6e40c39 100644 --- a/game-server/app.ts +++ b/game-server/app.ts @@ -35,6 +35,7 @@ import { checkAndSetApiIsClose } from './app/services/chatService'; import { initGuildActivityIndexInPinus, resetJoinWoodenHorse } from './app/services/guildActivity/guildActivityService'; import { setGVGConfig, setGVGServerGroup } from './app/services/gvg/gvgService'; import { isDevelopEnv } from './app/services/utilService'; +import { initTeamToMem } from './app/services/gvg/gvgBattleMemory'; const filePath = (_pinus as any).FILEPATH; filePath.MASTER = '/config/master'; @@ -204,9 +205,9 @@ async function treatStartLogic(app: _pinus.Application) { } if(app.getServerType() == 'guild'|| app.getServerType() == 'chat'|| app.getServerType() == 'connector') { setGVGServerGroup(); - if(app.getServerType() == 'guild') { - setGVGConfig(); - } + } + if(app.getServerType() == 'guild') { + setGVGConfig().then(initTeamToMem); } if(app.isMaster()) { diff --git a/game-server/app/servers/guild/handler/gvgBattleHandler.ts b/game-server/app/servers/guild/handler/gvgBattleHandler.ts index b78d1ccae..380077928 100644 --- a/game-server/app/servers/guild/handler/gvgBattleHandler.ts +++ b/game-server/app/servers/guild/handler/gvgBattleHandler.ts @@ -1,16 +1,14 @@ import { GVGCityType } from './../../../db/GVGCity'; import { GVGRecModel } from '../../../db/GVGRec'; -import { GVGAreaInMap, GVGTeamInList, GVGTeamInListOnPoint, GVGTeamSpineInMap, LeagueGood } from '../../../domain/gvgField/returnData'; -import { GVGTeamModel, GVGTeamType } from '../../../db/GVGTeam'; +import { GVGAreaInMap, GVGTeamInList, GVGTeamInListOnPoint, GVGTeamSpineInMap, LeagueGood, MyTeamInfo } from '../../../domain/gvgField/returnData'; +import { GVGTeamModel, GVGTeamType, GVGTeamUpdate } from '../../../db/GVGTeam'; import { GVGUserDataModel } from '../../../db/GVGUserData'; import { GVGCityModel } from '../../../db/GVGCity'; import { Application, BackendSession, ChannelService, HandlerService } from "pinus"; -import { DEBUG_MAGIC_WORD, GVG_PERIOD, STATUS } from "../../../consts"; -import { LineupHero } from "../../../domain/roleField/hero"; import { resResult, genCode } from "../../../pubUtils/util"; import { GVGLeagueModel } from '../../../db/GVGLeague'; import { checkGVGPeriod, getGroupIdOfServer, getGVGConfig, getGVGPeriodData, getGVGServerType } from '../../../services/gvg/gvgService'; -import { checkAreaIsInCity, checkMoveStatus, getBirthAreaOfCity, initRobots } from '../../../services/gvg/gvgBattleService'; +import { calBattleScoreByCe, calLeagueScore, checkAreaIsInCity, checkMoveStatus, getBirthAreaOfCity, initRobots, teamBreak } from '../../../services/gvg/gvgBattleService'; import { getGVGBattleData } from '../../../services/gvg/gvgBattleMemory'; import { nowSeconds } from '../../../pubUtils/timeUtil'; import { GVGBattleRecModel } from '../../../db/GVGBattleRec'; @@ -19,6 +17,9 @@ import { gameData } from '../../../pubUtils/data'; import { getAllServerName } from '../../../services/redisService'; import { checkBattleHeroesByHid } from '../../../services/normalBattleService'; import { pick } from 'underscore'; +import { SaveTeamParam, SaveTeamUpdateParam } from '../../../domain/gvgField/gvgDb'; +import { GVG_PERIOD, PUSH_ROUTE, STATUS } from '../../../consts'; +import { sendMessageToUserWithSuc } from '../../../services/pushService'; export default function (app: Application) { new HandlerService(app, {}); @@ -34,7 +35,10 @@ 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 }); } // 保存队伍 @@ -43,23 +47,35 @@ export class GVGBattleHandler { // frame: 相框 // spine: 形象 // lineup: 阵容 - async saveTeam(msg: { index: number, head: number, frame: number, spine: number, lineup: [ LineupHero ] }, session: BackendSession) { - // if(checkGVGPeriod(GVG_PERIOD.BATTLE)) return resResult(STATUS.GVG_NOT_BATTLE_PERIOD); + async saveTeam(msg: SaveTeamParam, session: BackendSession) { const roleId = session.get('roleId'); const serverId = session.get('serverId'); const roleName = session.get('roleName'); const guildCode = session.get('guildCode'); + const { index, head, spine, frame, lineup } = msg; + + let { configId, period } = getGVGPeriodData(); + // if (period != GVG_PERIOD.BATTLE) return resResult(STATUS.GVG_NOT_BATTLE_PERIOD); // TODO 测试临时注 + + let groupId = await getGroupIdOfServer(serverId); + let serverType = await getGVGServerType(serverId); let myLeague = await GVGLeagueModel.findLeagueByGuild(guildCode); if(!myLeague) return resResult(STATUS.GVG_LEAGUE_NOT_EXIST); - const { index, head, frame, spine, lineup } = msg; + let { leagueCode, name: leagueName } = myLeague; let durability = gameData.gvgTeamDurability.get(index)||0; - let { isOK, heroes } = await checkBattleHeroesByHid(roleId, lineup.map(cur => cur.actorId)); - if(!isOK) return resResult(STATUS.BATTLE_HERO_NOT_FOUND); - let lineupCe = heroes.reduce((pre, cur) => pre + cur.ce, 0); - const team = await GVGTeamModel.saveTeam(roleId, roleName, serverId, myLeague.leagueCode, myLeague.name, index, head, frame, spine, durability, lineup, lineupCe); + let updateParam: SaveTeamUpdateParam = { index, head, spine, frame, configId, groupId, serverType } + if(lineup) { + let { isOK, heroes } = await checkBattleHeroesByHid(roleId, lineup.map(cur => cur.actorId)); + if(!isOK) return resResult(STATUS.BATTLE_HERO_NOT_FOUND); + let lineupCe = heroes.reduce((pre, cur) => pre + cur.ce, 0); + updateParam.lineup = lineup; + updateParam.lineupCe = lineupCe; + } + + const team = await GVGTeamModel.saveTeam(roleId, index, updateParam, { roleName, serverId, leagueCode, leagueName, durability, maxDurability: durability }); if (!team) { return resResult(STATUS.GVG_SAVE_TEAM_FAILED); } @@ -87,6 +103,7 @@ export class GVGBattleHandler { return resResult(STATUS.SUCCESS, { cityId, guardLeague: { leagueCode, name, icon }, + guardStartTime: startFightTime - 3 * 60,// TODO 进系统参数表 startTime: startFightTime, endTime: endFightTime, ourTeamCnt, @@ -96,29 +113,31 @@ export class GVGBattleHandler { // 进入城池之前的检查 async checkMyTeam(msg: { cityId: number }, session: BackendSession) { - if(!checkGVGPeriod(GVG_PERIOD.BATTLE)) return resResult(STATUS.GVG_NOT_BATTLE_PERIOD); const roleId = session.get('roleId'); + const { cityId } = msg; - const resData = {}; - const teams = await GVGTeamModel.findByRole(roleId); + let hasSettled = false, otherCityId = 0; + const teams = await GVGTeamModel.findByRole(roleId, 'cityId'); // 玩家队伍信息中城池id不一致,说明玩家已经进入了其他城池 - if (teams && teams.length > 0 && teams[0].cityId && teams[0].cityId !== cityId) { - resData['hasSettled'] = true; - resData['cityId'] = teams[0].cityId; + for(let { cityId: teamCityId } of teams) { + if(teamCityId > 0 && teamCityId != cityId) { + hasSettled = true; otherCityId = teamCityId; break; + } } - return resResult(STATUS.SUCCESS, resData); + return resResult(STATUS.SUCCESS, { hasSettled, cityId: otherCityId }); } // 进入城池 async enterCity(msg: { cityId: number }, session: BackendSession) { - if(!checkGVGPeriod(GVG_PERIOD.BATTLE)) return resResult(STATUS.GVG_NOT_BATTLE_PERIOD); const roleId = session.get('roleId'); + const roleName = session.get('roleName'); const serverId = session.get('serverId'); const guildCode = session.get('guildCode'); const { cityId } = msg; - let { configId } = getGVGPeriodData(); + let { configId, period } = getGVGPeriodData(); + // if (period != GVG_PERIOD.BATTLE) return resResult(STATUS.GVG_NOT_BATTLE_PERIOD); // TODO 测试临时注 let groupId = await getGroupIdOfServer(serverId); let serverType = await getGVGServerType(serverId); @@ -126,45 +145,48 @@ export class GVGBattleHandler { let myLeague = await GVGLeagueModel.findLeagueByGuild(guildCode); if(!myLeague) return resResult(STATUS.GVG_LEAGUE_NOT_EXIST); - await initRobots(groupId, serverType, cityId); + // 初始化本城池的守擂机器人 + await initRobots(configId, groupId, serverType, cityId); - let city: GVGCityType = await GVGCityModel.findByCityId(configId, groupId, serverType, cityId); - - let gvgUserData = await GVGUserDataModel.findByRole(configId, myLeague.leagueCode, roleId); - if (!gvgUserData) { - return resResult(STATUS.GVG_USER_NOT_FOUND); + let teams = await GVGTeamModel.findByRole(roleId, '-_id'); + // 每赛季初自己的几支队伍恢复耐久、城市、顺便更新一下自己的玩家名、联军 + let updateArr: GVGTeamUpdate[] = [], originCityId = 0; + for(let team of teams) { + if(team.configId != configId) { + let { teamCode, maxDurability } = team; + updateArr.push({ teamCode, durability: maxDurability, cityId: 0, areaId: 0, pointId: 0, roleName, guildCode, leagueCode: myLeague.leagueCode, leagueName: myLeague.name, groupId, serverType }); + } + if(team.cityId) originCityId = team.cityId; } + if(updateArr.length > 0) teams = await GVGTeamModel.refreshByConfig(roleId, updateArr); - let teamObj = getGVGBattleData(groupId, serverType); - let teams: GVGTeamType[] = []; // 检测是否已经在城池中,玩家不在这个城池中时进行处理 - if (!await GVGTeamModel.checkCity(roleId, cityId, groupId, serverType)) { - if(gvgUserData.cityId > 0) { // 如果leaveCity没有退出成功,玩家还遗留在上一座城中,做一下处理 + if (originCityId != cityId) { + let gvgUserData = await GVGUserDataModel.findByRole(configId, myLeague.leagueCode, roleId); + if(gvgUserData?.cityId > 0) { // 如果leaveCity没有退出成功,玩家还遗留在上一座城中,做一下处理 await GVGCityModel.decreasePlayer(configId, groupId, serverType, gvgUserData.cityId, roleId); } const roleTeamCnt = await GVGTeamModel.getTeamCntByRole(roleId); - city = await GVGCityModel.increasePlayer(configId, groupId, serverType, cityId, roleId, myLeague.leagueCode, roleTeamCnt); + let city = await GVGCityModel.increasePlayer(configId, groupId, serverType, cityId, roleId, myLeague.leagueCode, roleTeamCnt); if(!city) return resResult(STATUS.GVG_BATTLE_CITY_FULL); gvgUserData = await GVGUserDataModel.changeCity(configId, myLeague.leagueCode, roleId, cityId); - // 更新内存队伍信息 let areaId = getBirthAreaOfCity(city, myLeague.leagueCode); await GVGTeamModel.enterCity(roleId, cityId, areaId, groupId, serverType); - teams = await GVGTeamModel.findByRole(roleId); + teams = await GVGTeamModel.findByRole(roleId, '-_id'); + // 更新内存队伍信息 + let teamObj = getGVGBattleData(groupId, serverType); teamObj.enterCity(teams); } - if (!teams || teams.length === 0) { - teams = await GVGTeamModel.findByRole(roleId); - } - const recs = await GVGRecModel.findByCity(cityId, configId); + const teamResult = teams.map(team => new MyTeamInfo(team)); return resResult(STATUS.SUCCESS, { cityId, ranks: [], // ! redis 中积分排行榜 recs, - teams, + teams: teamResult, }); } @@ -176,7 +198,7 @@ export class GVGBattleHandler { const serverId = session.get('serverId'); const { cityId } = msg; let { configId, period } = getGVGPeriodData(); - if (period != GVG_PERIOD.BATTLE) return resResult(STATUS.GVG_NOT_BATTLE_PERIOD); + let groupId = await getGroupIdOfServer(serverId); let serverType = await getGVGServerType(serverId); @@ -245,8 +267,10 @@ export class GVGBattleHandler { let teams = await GVGTeamModel.findByAreaId(groupId, serverType, cityId, myTeam.areaId); let points: GVGTeamInListOnPoint[] = [], players: GVGTeamInList[] = []; let pointIds = gameData.gvgPointByAreaId.get(myTeam.areaId)||[]; + console.log('#### teams', teams, teams.length); for(let pointId of pointIds) { let team = teams.find(cur => cur.pointId == pointId); + console.log('#### point', pointId, team); let obj = new GVGTeamInListOnPoint(pointId, !!team, team); points.push(obj); } @@ -337,12 +361,14 @@ export class GVGBattleHandler { let { attackTeam, defenseTeam } = await GVGTeamModel.findBattleTeams(teamCode, oppoTeamCode); if(!attackTeam || !defenseTeam) return resResult(STATUS.GVG_BATTLE_TEAM_INVALID); if(attackTeam.attackTime > nowSeconds()) return resResult(STATUS.GVG_TEAM_ATTACKING); - if(defenseTeam.defenseTime > nowSeconds()) return resResult(STATUS.GVG_TEAM_DEFENSEING); + if(defenseTeam.defenseTime > nowSeconds() || defenseTeam.lockTime > nowSeconds()) return resResult(STATUS.GVG_TEAM_DEFENSEING); + if(attackTeam.durability <= 0) return resResult(STATUS.GVG_ATTACK_TEAM_BROKEN); + if(defenseTeam.durability <= 0) return resResult(STATUS.GVG_DEFENSE_TEAM_BROKEN); const battleRecord = await GVGBattleRecModel.createRec(attackTeam, defenseTeam); - attackTeam = await GVGTeamModel.lockAttack(teamCode, groupId, serverType); - defenseTeam = await GVGTeamModel.lockDefense(oppoTeamCode, groupId, serverType); + attackTeam = await GVGTeamModel.battleStartLockAttack(teamCode); + defenseTeam = await GVGTeamModel.battleStartLockDefense(oppoTeamCode, teamCode); // 内存处理 let teamObj = getGVGBattleData(groupId, serverType); teamObj.setTime(teamCode, attackTeam); @@ -353,23 +379,37 @@ export class GVGBattleHandler { // 队伍停止攻击 async battleEnd(msg: { cityId: number, battleCode: string, isSuccess: boolean }, session: BackendSession) { - const { battleCode, isSuccess } = msg; + const serverId = session.get('serverId'); + const { cityId, battleCode, isSuccess } = msg; + + let { configId, period } = getGVGPeriodData(); const record = await GVGBattleRecModel.findByBattleCode(battleCode); if(!record) return resResult(STATUS.GVG_BATTLEREC_NOT_FOUND); - const myTeam = await GVGTeamModel.findByTeamCode(record.attackTeam.roleId, record.attackTeam.teamCode); - const leagueGoods: LeagueGood[] = null; - // ! 计算并更新两支队伍耐久 - const curTeam = await GVGTeamModel.findOneAndUpdate({ teamCode: myTeam.teamCode }, {}).lean(); + let { attackTeam, defenseTeam } = await GVGTeamModel.findBattleTeams(record.attackTeam.teamCode, record.defenseTeam.teamCode); + if(defenseTeam.attackTeam != attackTeam.teamCode) return resResult(STATUS.GVG_LOCK_TIME_OUT) + + let groupId = await getGroupIdOfServer(serverId); + let serverType = await getGVGServerType(serverId); + let city = await GVGCityModel.findByCityId(configId, groupId, serverType, cityId); + if (!city) return resResult(STATUS.GVG_CITY_NOT_FOUND); + + // 计算并更新两支队伍耐久 + let { win, fail } = gameData.gvgBattleDurabilityMinus; + attackTeam = await GVGTeamModel.battleEndAttack(attackTeam.teamCode, isSuccess? -win: -fail, calBattleScoreByCe(isSuccess, attackTeam.lineupCe), calLeagueScore(defenseTeam)); + defenseTeam = await GVGTeamModel.battleEndDefense(defenseTeam.teamCode, isSuccess? -fail: -win, calBattleScoreByCe(isSuccess, defenseTeam.lineupCe)); + + if(attackTeam.durability <= 0) attackTeam = await teamBreak(city, attackTeam); + if(defenseTeam.durability <= 0) defenseTeam = await teamBreak(city, defenseTeam); + // ! 推送战斗结果给对手队伍 // const channel = this.channelService.getChannel(teamCode, false); // if (!!channel) { // channel.pushMessage('onBattleResult', { isSuccess }); // } - // ! 结算奖励 - if (isSuccess) { - // ! 更新 leagueGoods + if(!defenseTeam.isRobot) { + sendMessageToUserWithSuc(defenseTeam.roleId, PUSH_ROUTE.GVG_TEAM_ATTACKED, { cityId, areaId: defenseTeam.areaId, teams: [defenseTeam] }); } - return resResult(STATUS.SUCCESS, { curTeam, leagueGoods }); + return resResult(STATUS.SUCCESS, { curTeam: new MyTeamInfo(attackTeam) }); } // 使用道具 diff --git a/game-server/app/services/gvg/gvgBattleMemory.ts b/game-server/app/services/gvg/gvgBattleMemory.ts index 583650ddb..b50e6bab2 100644 --- a/game-server/app/services/gvg/gvgBattleMemory.ts +++ b/game-server/app/services/gvg/gvgBattleMemory.ts @@ -1,7 +1,11 @@ // 存在激战期的内存数据 -import { GVGTeamType } from "../../db/GVGTeam"; +import { pinus } from "pinus"; +import { GVG_PERIOD } from "../../consts"; +import { GVGTeamModel, GVGTeamType } from "../../db/GVGTeam"; import { GVGTeamMem } from "../../domain/battleField/gvgBattle"; +import { dispatch } from "../../pubUtils/dispatcher"; +import { getGVGPeriodData } from "./gvgService"; // 积分点占领情况,groupId_serverType_cityId -> GVGBattleData const gvgBattleMap: Map = new Map(); @@ -44,7 +48,6 @@ class GVGBattleData { for(let team of teams) { let fromAreaId = this.teams.get(team.teamCode)?.areaId||0; - console.log('#### team', team.teamCode) if(!this.teams.has(team.teamCode)) { this.teams.set(team.teamCode, new GVGTeamMem(team)) } @@ -107,4 +110,18 @@ export function getGVGBattleData(groupId: number, serverType: number) { gvgBattleMap.set(key, new GVGBattleData(groupId, serverType)); } return gvgBattleMap.get(key); +} + +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; + let teams = await GVGTeamModel.findByConfigId(configId); + for(let team of teams) { + if(dispatch(team.cityId.toString(), servers)?.id == sid) { + let teamObj = getGVGBattleData(team.groupId, team.serverType); + teamObj.enterCity([team]); + } + } } \ No newline at end of file diff --git a/game-server/app/services/gvg/gvgBattleService.ts b/game-server/app/services/gvg/gvgBattleService.ts index 19df2b70a..ee0894a1d 100644 --- a/game-server/app/services/gvg/gvgBattleService.ts +++ b/game-server/app/services/gvg/gvgBattleService.ts @@ -1,6 +1,6 @@ import { GVGTeamMem } from "../../domain/battleField/gvgBattle"; import { GVGLeagueType } from "../../db/GVGLeague"; -import { GVGTeamModel, GVGTeamType } from "../../db/GVGTeam"; +import { GVGTeamModel, GVGTeamType, GVGTeamUpdate } from "../../db/GVGTeam"; import { GVGCityModel, GVGCityType } from "../../db/GVGCity"; import { gameData } from "../../pubUtils/data"; import { STATUS } from "../../consts"; @@ -8,6 +8,8 @@ import { nowSeconds } from "../../pubUtils/timeUtil"; import { DicGVGAreaPoint } from "../../pubUtils/dictionary/DicGVGAreaPoint"; import { getGVGBattleData } from "./gvgBattleMemory"; import { GVGCityMapInfo } from "../../domain/gvgField/returnData"; +import { pick } from "underscore"; +import { GVG } from "../../pubUtils/dicParam"; /** @@ -71,17 +73,24 @@ export function checkMoveStatus(team: GVGTeamType, cityId: number, areaId: numbe return STATUS.SUCCESS; } -export async function initRobots(groupId: number, serverType: number, cityId: number) { - let teamObj = getGVGBattleData(groupId, serverType); - if(!teamObj.checkHasRobot(cityId)) { - let dicPoints: DicGVGAreaPoint[] = []; - let { areaIds = []} = gameData.gvgCity.get(cityId); - for(let [_, point] of gameData.gvgAreaPoint) { - if(areaIds.indexOf(point.areaId) != -1) dicPoints.push(point); +export async function initRobots(confidId: number, groupId: number, serverType: number, cityId: number) { + let robotTeams = await GVGTeamModel.findRobotTeams(groupId, serverType, cityId); + let updateDicPoints: DicGVGAreaPoint[] = []; + let { areaIds = []} = gameData.gvgCity.get(cityId); + for(let [_, point] of gameData.gvgAreaPoint) { + if(areaIds.indexOf(point.areaId) == -1) continue; + let robotTeam = robotTeams.find(team => team.pointId == point.pointId); + if(!robotTeam || (!robotTeam.isBroken && robotTeam.configId != confidId) ) { + updateDicPoints.push(point); } - let teams = await GVGTeamModel.initRobots(groupId, serverType, cityId, dicPoints); - teamObj.enterCity(teams); } + if(updateDicPoints.length > 0) { + robotTeams = await GVGTeamModel.initRobots(confidId, groupId, serverType, cityId, updateDicPoints); + // 存入内存 + let teamObj = getGVGBattleData(groupId, serverType); + teamObj.enterCity(robotTeams); + } + return robotTeams; } export function checkAreaIsInCity(cityId: number, areaIds: number[]) { @@ -91,4 +100,22 @@ export function checkAreaIsInCity(cityId: number, areaIds: number[]) { if(dicCity.areaIds.indexOf(areaId) == -1) return false; } return true; +} + +export function calBattleScoreByCe(isSuccess: boolean, lineupCe: number) { + let winScore = Math.floor(lineupCe/GVG.GVG_BATTLE_SCORE); + if(winScore <= 0) winScore = 1; + return isSuccess? winScore: 0; +} + +// 计算打投石车/守卫的得分 +export function calLeagueScore(team: GVGTeamType) { + return 0 +} + +export async function teamBreak(city: GVGCityType, team: GVGTeamType) { + if(team.durability > 0) return team + let areaId = getBirthAreaOfCity(city, team.leagueCode); + team = await GVGTeamModel.teamBreak(team.teamCode, team.isRobot, team.maxDurability, areaId); + return team; } \ No newline at end of file diff --git a/shared/consts/constModules/chatConst.ts b/shared/consts/constModules/chatConst.ts index 77d0b2eac..3277cabcc 100644 --- a/shared/consts/constModules/chatConst.ts +++ b/shared/consts/constModules/chatConst.ts @@ -180,4 +180,5 @@ export const PUSH_ROUTE = { LEAGUE_ABDICATE: 'onLeagueAbdicate', // 当被转让盟主 LEAGUE_ITEM_UPDATE: 'onLeagueItemUpdate', GVG_TASK_UPDATE: 'onGVGTaskUpdate', // GVG任务更新 + GVG_TEAM_ATTACKED: 'onTeamAttacked', // 当队伍受到攻击 } \ No newline at end of file diff --git a/shared/consts/statusCode.ts b/shared/consts/statusCode.ts index 470cfaae8..031799b0a 100644 --- a/shared/consts/statusCode.ts +++ b/shared/consts/statusCode.ts @@ -369,6 +369,9 @@ export const STATUS = { GVG_BATTLEREC_NOT_FOUND: { code: 21407, simStr: '未找到该记录' }, GVG_AREA_NOT_IN_CITY: { code: 21408, simStr: '选择区域不在这座城池中' }, GVG_TEAM_NOT_FOUND: { code: 21409, simStr: '未找到这个队伍' }, + GVG_LOCK_TIME_OUT: { code: 21410, simStr: '挑战超时' }, + GVG_ATTACK_TEAM_BROKEN: { code: 21411, simStr: '挑战队伍已被击破' }, + GVG_DEFENSE_TEAM_BROKEN: { code: 21411, simStr: '对方队伍已被击破' }, // 通用 30000 - 30099 DIC_DATA_NOT_FOUND: { code: 30000, simStr: '数据表未找到' }, diff --git a/shared/db/GVGBattleRec.ts b/shared/db/GVGBattleRec.ts index 381fd9b9d..95ac7868d 100644 --- a/shared/db/GVGBattleRec.ts +++ b/shared/db/GVGBattleRec.ts @@ -13,7 +13,7 @@ class TeamInfo { teamCode: string; // 玩家队伍唯一标识 @prop({ required: true }) - teamId: number; // 队伍id,1-3,玩家的第几个队伍 + index: number; // 队伍id,1-3,玩家的第几个队伍 @prop({ required: true }) leagueCode: string; // 联军 @@ -62,7 +62,7 @@ export default class GVGBattleRec extends BaseModel { public static async createRec(attackTeam: GVGTeamType, defenseTeam: GVGTeamType) { const battleCode = genCode(8); - const result: GVGBattleRecType = await GVGBattleRecModel.findOneAndUpdate({ battleCode }, { $set: { attackTeam, defenseTeam, isSuccess: false } }).lean(); + const result: GVGBattleRecType = await GVGBattleRecModel.findOneAndUpdate({ battleCode }, { $set: { attackTeam, defenseTeam, isSuccess: false } }, { new: true, upsert: true }).lean(); return result; } diff --git a/shared/db/GVGTeam.ts b/shared/db/GVGTeam.ts index 23884d595..c99491648 100644 --- a/shared/db/GVGTeam.ts +++ b/shared/db/GVGTeam.ts @@ -6,12 +6,16 @@ import { LineupHero } from './../domain/roleField/hero'; import { nowSeconds } from "../pubUtils/timeUtil"; import { GVG } from "../pubUtils/dicParam"; import { DicGVGAreaPoint } from "../pubUtils/dictionary/DicGVGAreaPoint"; +import { InitTeamParam, SaveTeamUpdateParam } from "../domain/gvgField/gvgDb"; -@index({ roleId: 1, teamId: 1 }) +@index({ roleId: 1, index: 1 }) @index({ teamCode: 1 }) @index({ cityId: 1, leagueId: 1 }) export default class GVGTeam extends BaseModel { + @prop({ required: true }) + configId: number; // 赛季,每赛季在enterCity的时候检测,如果不一样就更新durability那些东西 + @prop({ required: true }) roleId: string; // 玩家id @@ -25,7 +29,7 @@ export default class GVGTeam extends BaseModel { teamCode: string; // 玩家队伍唯一标识 @prop({ required: true }) - teamId: number; // 队伍id,1-3,玩家的第几个队伍 + index: number; // 队伍id,1-3,玩家的第几个队伍 @prop({ required: true }) leagueCode: string; // 联军 @@ -66,6 +70,12 @@ export default class GVGTeam extends BaseModel { @prop({ required: true, default: 0 }) attackTime: number; // 进攻冷却时间 + @prop({ required: true, default: 0 }) + lockTime: number; // 正在被进攻中 + + @prop({ required: true, default: 0 }) + attackTeam: string; // 正在被这支队伍进攻中 + @prop({ required: true, default: 0 }) fromAreaId: number; // 从那个区域移动 @@ -79,7 +89,10 @@ export default class GVGTeam extends BaseModel { defenseTime: number; // 防守保护时间 @prop({ required: true, default: 0 }) - point: number; // 积分 + playerScore: number; // 积分 + + @prop({ required: true, default: 0 }) + leagueScore: number; // 积分 @prop({ required: true, type: () => LineupHero, _id: false }) lineup: LineupHero[]; @@ -96,57 +109,34 @@ export default class GVGTeam extends BaseModel { @prop({ required: true, default: false }) isRobot: boolean; // 是否是机器人 + @prop({ required: true, default: false }) + isCatapult: boolean; // 是否是投石车 + + @prop({ required: true, default: false }) + isBroken: boolean; // 机器人是否被击破,如果没有被击破,那么这个位置上就还是机器人,如果被击破了,这个位置就空出给玩家 + // 创建队伍 - public static async createTeam(roleId: string, roleName: string, serverId: number, leagueCode: string, leagueName: string, teamId: number, head: number, spine: number, frame: number, durability: number, lineup: [LineupHero], lineupCe: number) { + public static async saveTeam(roleId: string, index: number, updateParam: SaveTeamUpdateParam, initParam: InitTeamParam) { const doc = new GVGTeamModel(); const teamCode = genCode(8); - const update = Object.assign(doc.toJSON(), { roleId, roleName, serverId, leagueCode, leagueName, teamId, teamCode, head, spine, frame, lineup, durability, maxDurability: durability, lineupCe }); - const team: GVGTeamType | null = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $setOnInsert: update }, { upsert: true, new: true }).lean(); + const insert = Object.assign(doc.toJSON(), { ...initParam, teamCode }); + delete insert.lineup; + const team: GVGTeamType | null = await GVGTeamModel.findOneAndUpdate({ roleId, index }, { $setOnInsert: insert, $set: updateParam }, { upsert: true, new: true }).lean(); return team; } - // 保存队伍 - public static async saveTeam(roleId: string, roleName: string, serverId: number, leagueCode: string, leagueName: string, teamId: number, head: number, spine: number, frame: number, durability: number, lineup: [LineupHero], lineupCe: number) { - let team: GVGTeamType = await GVGTeamModel.findOne({ roleId, teamId }).lean(); - if (!team) { - team = await this.createTeam(roleId, roleName, serverId, leagueCode, leagueName, teamId, head, spine, frame, durability, lineup, lineupCe); - return team; - } - - const update = { head, spine, frame }; - if (lineup && lineup.length > 0) { - update['lineup'] = lineup; - } - team = await GVGTeamModel.findOneAndUpdate({ roleId, teamId }, { update }, { new: true }).lean(); - return team; - } - - // 查找角色队伍数 - public static async getTeamCntByRole(roleId: string) { - const teams: GVGTeamType[] = await GVGTeamModel.find({ roleId }).select('teamCode').lean(); - return teams.length; - } - - // 通过城池ID获取队伍数 - public static async getTeamCntByCity(cityId: number, leagueCode?: string) { - const query = { cityId }; - if (leagueCode) { - query['leagueCode'] = leagueCode; - } - const teams: GVGTeamType[] = await GVGTeamModel.find(query).select('').lean(); - return teams.length; - } - - public static async checkCity(roleId: string, cityId: number, groupId: number, serverType: number) { - return await GVGTeamModel.exists({ roleId, cityId, groupId, serverType }); - } - // 玩家切换城池更新队伍信息 public static async enterCity(roleId: string, cityId: number, areaId: number, groupId: number, serverType: number) { const res = await GVGTeamModel.updateMany({ roleId }, { cityId, areaId, pointId: 0, groupId, serverType }).lean(); return !!res['ok']; } + // 查找角色队伍数 + public static async getTeamCntByRole(roleId: string) { + const teams: GVGTeamType[] = await GVGTeamModel.find({ roleId }).select('teamCode').lean(); + return teams.length; + } + // 获取我的编队 public static async findByRole(roleId: string, select = '') { const teams: GVGTeamType[] = await GVGTeamModel.find({ roleId }).select(select).lean(); @@ -161,12 +151,12 @@ export default class GVGTeam extends BaseModel { // 移动 public static async startMove(teamCode: string, areaId: number, fromAreaId: number) { - const res: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { areaId, fromAreaId, stopMoveTime: nowSeconds() + GVG.GVG_DEFAULT_MOVE_CD } }).lean(); + const res: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { areaId, fromAreaId, stopMoveTime: nowSeconds() + GVG.GVG_DEFAULT_MOVE_CD } }, { new: true }).lean(); return res; } public static async stopMove(teamCode: string, areaId: number) { - const res: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { areaId, fromAreaId: 0, stopMoveTime: nowSeconds() } }).lean(); + const res: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { areaId, fromAreaId: 0, stopMoveTime: nowSeconds() } }, { new: true }).lean(); return res; } @@ -180,40 +170,83 @@ export default class GVGTeam extends BaseModel { } return { attackTeam, defenseTeam } } - - public static async checkRobot(groupId: number, serverType: number, cityId: number) { - return await GVGTeamModel.exists({ groupId, serverType, cityId, isRobot: true }); - } - public static async initRobots(groupId: number, serverType: number, cityId: number, dicPoints: DicGVGAreaPoint[]) { - await GVGTeamModel.bulkWrite(dicPoints.map(dic => { + // 每赛季初刷新自己的耐久等东西 + public static async refreshByConfig(roleId: string, updateArr: GVGTeamUpdate[]) { + await GVGTeamModel.bulkWrite(updateArr.map(obj => { return { updateOne: { - filter: { groupId, serverType, cityId, pointId: dic.pointId }, - update: { $setOnInsert: { teamCode: `robot${dic.pointId}`, ...dic, roleName: dic.name, isRobot: true } }, upsert: true + filter: { roleId, teamCode: obj.teamCode }, + update: { $set: obj } } } })); + return await GVGTeamModel.findByRole(roleId, '-_id'); + } + + public static async findRobotTeams(groupId: number, serverType: number, cityId: number) { const team: GVGTeamType[] = await GVGTeamModel.find({ groupId, serverType, cityId, isRobot: true }).lean(); return team; } + // 每赛季初刷新机器人 + public static async initRobots(configId: number, groupId: number, serverType: number, cityId: number, dicPoints: DicGVGAreaPoint[]) { + await GVGTeamModel.bulkWrite(dicPoints.map(({ pointId, areaId, name, head, spine, ce, durability }) => { + 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 } }, + upsert: true + } + } + })); + return await this.findRobotTeams(groupId, serverType, cityId); + } + // 攻击方攻击cd - public static async lockAttack(teamCode: string, groupId: number, serverType: number) { - const team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { attackTime: nowSeconds() + GVG.GVG_DEFAULT_ATTACK_CD, groupId, serverType } }, { new: true }).lean(); + public static async battleStartLockAttack(teamCode: string) { + const team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { attackTime: nowSeconds() + GVG.GVG_DEFAULT_ATTACK_CD } }, { new: true }).lean(); return team; } - // 防守方防守cd - public static async lockDefense(teamCode: string, groupId: number, serverType: number) { - const team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { attackTime: nowSeconds() + GVG.GVG_DEFAULT_DEFENSE_CD, groupId, serverType } }, { new: true }).lean(); + // 防守方锁定cd + public static async battleStartLockDefense(teamCode: string, attackTeam: string) { + const team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { lockTime: nowSeconds() + GVG.GVG_DEFAULT_ATTACK_CD, attackTeam } }, { new: true }).lean(); return team; } + // 结算挑战方 + public static async battleEndAttack(teamCode: string, hpInc: number, playerScoreInc: number, leagueScoreInc: number) { + const team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $inc: { durability: hpInc, playerScore: playerScoreInc, leagueScore: leagueScoreInc } }, { new: true }).lean(); + return team; + } + + // 结算防守方 + public static async battleEndDefense(teamCode: string, hpInc: number, playerScoreInc: number) { + const team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { defenseTime: nowSeconds() + GVG.GVG_DEFAULT_DEFENSE_CD }, $inc: { durability: hpInc, playerScore: playerScoreInc } }, { new: true }).lean(); + return team; + } + + // 队伍进入修整器 + public static async teamBreak(teamCode: string, isRobot: boolean, maxDurability: number, areaId: number) { + if(!isRobot) { + const team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { restartTime: nowSeconds() + GVG.GVG_DEFAULT_DEFENSE_CD, stopMoveTime: nowSeconds(), areaId, durability: maxDurability } }, { new: true }).lean(); + return team; + } else { + const team: GVGTeamType = await GVGTeamModel.findOneAndUpdate({ teamCode }, { $set: { durability: 0, isBroken: true } }, { new: true }).lean(); + return team; + } + } + public static async findByAreaId(groupId: number, serverType: number, cityId: number, areaId: number) { const team: GVGTeamType[] = await GVGTeamModel.find({ groupId, serverType, cityId, areaId, stopMoveTime: { $lte: nowSeconds() } }).lean(); return team; } + + public static async findByConfigId(configId: number) { + const team: GVGTeamType[] = await GVGTeamModel.find({ configId, cityId: { $gt: 0 } }).lean(); + return team; + } } diff --git a/shared/domain/battleField/gvgBattle.ts b/shared/domain/battleField/gvgBattle.ts index 5bda21910..85ec2a52f 100644 --- a/shared/domain/battleField/gvgBattle.ts +++ b/shared/domain/battleField/gvgBattle.ts @@ -29,7 +29,7 @@ export class GVGTeamMem extends GVGTeam { this.roleName = team.roleName; this.serverId = team.serverId; this.teamCode = team.teamCode; - this.teamId = team.teamId; + this.index = team.index; this.leagueCode = team.leagueCode; this.guildCode = team.guildCode; this.areaId = team.areaId; @@ -45,7 +45,7 @@ export class GVGTeamMem extends GVGTeam { this.defenseTime = team.defenseTime; this.startMoveTime = team.startMoveTime; this.stopMoveTime = team.stopMoveTime; - this.point = team.point; + this.playerScore = team.playerScore; } public setCity(cityId: number, areaId = 0, pointId = 0) { diff --git a/shared/domain/gvgField/gvgDb.ts b/shared/domain/gvgField/gvgDb.ts index 1d0d7a59f..932836934 100644 --- a/shared/domain/gvgField/gvgDb.ts +++ b/shared/domain/gvgField/gvgDb.ts @@ -8,6 +8,7 @@ import { gameData } from "../../pubUtils/data"; import { EXTERIOR, GVG } from "../../pubUtils/dicParam"; import { DicGVGVestige } from "../../pubUtils/dictionary/DicGVGVestige"; import { DicWarJson } from "../../pubUtils/dictionary/DicWarJson"; +import { LineupHero } from "../roleField/hero"; export class OppPlayerHeroInfo { @prop({ required: true }) @@ -246,4 +247,28 @@ export class OppDetailData{ let hero = this.heroes.find(cur => cur.actorId == hid); if(hero) hero.setAttribute(attribute); } +} + +export interface SaveTeamParam { + index: number; + head: number; + frame: number; + spine: number; + lineup?: LineupHero[]; +} + +export interface SaveTeamUpdateParam extends SaveTeamParam { + lineupCe?: number; + configId: number; + groupId: number; + serverType: number; +} + +export interface InitTeamParam { + roleName: string; + serverId: number; + leagueCode: string; + leagueName: string; + durability: number; + maxDurability: number; } \ No newline at end of file diff --git a/shared/domain/gvgField/returnData.ts b/shared/domain/gvgField/returnData.ts index 687f142fa..f73ad5eb8 100644 --- a/shared/domain/gvgField/returnData.ts +++ b/shared/domain/gvgField/returnData.ts @@ -678,4 +678,42 @@ export class GVGTeamInListOnPoint extends GVGTeamInList { this.hasTeam = hasTeam; if(team) this.isRobot = team.isRobot; } +} + +// 更新自己队伍时候的比较详细点的数据 +export class MyTeamInfo { + teamCode: string; // 队伍唯一id + index: number; // 队伍位置 + head: number; // 保存头像 + frame: number; // 保存相框 + spine: number; // 保存形象 + lineup: { + actorId: number; // 武将 + dataId: number; // 出兵表上的位置 + order: number; // 行动 + }[]; + durability: number; // 耐久 + maxDurability: number; // 最大耐久 + restartTime: number; // 修整期结束时间 + attackTime: number; // 进攻冷却结束时间 + stopMoveTime: number; // 移动冷却结束时间 + defenseTime: number; // 防守保护时间 + areaId: number; // 出生在的区域 + pointId: number; + + constructor(team: GVGTeamType) { + this.teamCode = team.teamCode; + this.index = team.index; + this.head = team.head; + this.frame = team.spine; + this.lineup = team.lineup; + this.durability = team.durability; + this.maxDurability = team.maxDurability; + this.restartTime = team.restartTime; + this.attackTime = team.attackTime; + this.stopMoveTime = team.stopMoveTime; + this.defenseTime = team.defenseTime; + this.areaId = team.areaId; + this.pointId = team.pointId; + } } \ No newline at end of file diff --git a/shared/pubUtils/dicParam.ts b/shared/pubUtils/dicParam.ts index 0a5733e90..343fb83d6 100644 --- a/shared/pubUtils/dicParam.ts +++ b/shared/pubUtils/dicParam.ts @@ -406,4 +406,6 @@ export const GVG = { GVG_DEFAULT_ATTACK_CD: 5, // GVG激战期默认的攻击CD GVG_DEFAULT_DEFENSE_CD: 2, // GVG激战期默认的防御CD GVG_DEFAULT_DURABILITY_MINUS: '5&100', // GVG激战期默认的队伍耐扣除规则,胜&败:num&num + GVG_PRODUCE_GAME_RATIO: '1&0.5|2&0.1|3&0.2', // 云台外政中贡献分3种产量分值换算 1:粮食*系数 2:铁矿*系数 3:木材*系数 + GVG_BATTLE_SCORE: 1000000, // 战力换算积分的除数 };