import PlayerMgr from "../object/PlayerMgr"; import ActivityDefine from "./ActivityDefine"; import TeamMgr from "../core/TeamMgr"; import SKDataUtil from "../gear/SKDataUtil"; import SKLogger from "../gear/SKLogger"; import {BattleType, MsgCode} from "../role/EEnum"; import * as schedule from "node-schedule"; import World from "../object/World"; import GTimer from "../common/GTimer"; /** * 逐鹿之战 */ export default class SatAssembly { static shared = new SatAssembly(); // 比赛阶段 match_state: any = { prepare_magic: 1, // 备战-恶鬼竞赛 magic: 2, // 恶鬼竞赛 prepare_sat: 3, // 备战-巅峰对决 sat: 4 // 巅峰对决 } // 定时时间(毫秒单位) state_time: any = { sign_time: 2 * 60 * 1000, // 通知完2分钟后开始报名 prepare_magic_time: 15 * 60 * 1000, // 备战-恶鬼竞赛(15分钟) magic_time: 10 * 60 * 1000, // 恶鬼竞赛(10分钟) prepare_sat_time: 5 * 60 * 1000, // 备战-巅峰对决(5分钟) sat_time: 35 * 60 * 1000 // 巅峰对决(35分钟) } // 战斗状态 FightState: any = { Wait: 1, // 等待 FightEnd: 2, // 结束战斗 Fighting: 3, // 等待状态 } // 赛季 season: number; match_team: any[]; name: any; player_list: any; // 逐鹿之战状态 activity_state: any; // 通知时间 inform_time: any; // 比赛阶段 game_state: any; // 奖励 goods_award: any[]; // 定时匹配队伍 matching_cancel: any; // 定时调整队伍 adjust_cancel: any; constructor() { this.name = '逐鹿之战'; // 赛季 this.season = 1; // 参数队伍 this.match_team = []; this.player_list = {}; this.game_state = 0; } init() { this.activity_state = ActivityDefine.activityState.Close; this.goods_award = [50014, 50015, 10406, 10110, 10609, 10604, 50016, 95142, 50033]; //每周二、周五开启(周一:MON、周二:TUE、周三:WED、周四:THU、周五:FRI、周六:SAT、周天:SUN) schedule.scheduleJob("0 10 21 ? * TUE,FRI", () => { // 修改状态为准备报名 this.satReadyOpen(); }) } /** * 即将开启活动进行通知 */ satReadyOpen() { let times = 3; //1. js获取当前时间 let date = new Date(); //2. 获取当前分钟 let min = date.getMinutes(); //3. 设置当前时间+3分钟:把当前分钟数+3后的值重新设置为date对象的分钟数 date.setMinutes(min + 3); let time: string = date.getHours() + ":" + date.getMinutes(); let broad = () => { times--; let msg = `${this.name} 将在${time}开启报名,请大家踊跃参加!`; PlayerMgr.shared.broadcast('s2c_notice', { strRichText: msg }); PlayerMgr.shared.broadcast('s2c_game_chat', {scale: 3, msg: msg, name: '', resid: 0, teamid: 0,}); if (times >= 0) { setTimeout(() => { broad(); }, 10 * 1000); } else { setTimeout(() => { this.open(); }, this.state_time.sign_time); } } broad(); } /** * 逐鹿之战:玩家报名 */ playerSign(player: any) { // 逐鹿之战没有开启 if (this.activity_state == ActivityDefine.activityState.Close) { return MsgCode.SAT_NOT_OPEN; } // 不在逐鹿之战报名时间 if (this.activity_state != ActivityDefine.activityState.ReadyOpen) { return MsgCode.SAT_NOT_SIGN_TIME; } let team = TeamMgr.shared.getTeamInfo(player.teamid); // // 逐鹿之战必须3人以上组队参加 if (team == null || team.playerlist.length < 3) { return MsgCode.SAT_SIGN_TEAM; } // 逐鹿之战必须3人以上组队参加 for (let i = 0; i < team.playerlist.length; i++) { const mem = team.playerlist[i]; if (mem.level < 80) { return MsgCode.SAT_SIGN_LEVEL_80; } } // 只能队长报名 if (team.leader.roleid != player.roleid) { return MsgCode.SIGN_TEAM_LEADER; } if (this.player_list[player.teamid] != null) { return MsgCode.SIGN_ALREADY; } this.player_list[player.teamid] = { name: player.name + '的队伍', pid: player.roleid, // 队长角色编号 teamid: player.teamid, // 队伍编号 magic_score: 0, // 恶鬼积分 sat_score: 0, // 逐鹿积分 peak: 150, // 队伍巅峰积分 num: team.playerlist.length,// 队伍人数 } this.sayStage(team, this.match_state.prepare_magic, this.state_time.prepare_magic_time) this.matchTeam(team); return MsgCode.SUCCESS; } /** * 请求离开逐鹿之战 */ leaveSat(player: any, teamId: any) { if (player) { let team = this.player_list[teamId]; if (team != null && team != undefined) { if (team.pid == player.roleid) { delete this.player_list[teamId]; } else { player.send_notice("您不是队长不可以次操作!"); player.send('s2c_leave_sat', { code: MsgCode.FAILED }); return; } } for (let i = 0; i < this.match_team.length; i++) { let info: any = this.match_team[i]; if (info.teamid != teamId) { continue; } this.match_team.splice(i, 1); break; } // 通知当前队伍成员将证道大会标题取消显示 let team_list = TeamMgr.shared.getTeamInfo(teamId); if (team_list) { for (const member of team_list.playerlist) { member.send('s2c_leave_sat', { code: MsgCode.SUCCESS }); } } player.map_transfer(1011); } } /** * 通知队伍中玩家比赛状态 * @param team */ sayStage(team: any, type: number, countDown: number) { if (team != null) { countDown = countDown - (GTimer.getTime() - this.inform_time); for (let i = 0; i < team.playerlist.length; i++) { const mem = team.playerlist[i]; // 通知前端改为巅峰 if (type == this.match_state.prepare_sat) { let teamInfo = this.player_list[team.teamid]; if (teamInfo) { mem.send('s2c_update_say_peak', { score: teamInfo.peak }) } } // 通知前端更改比赛状态 mem.send('s2c_say_stage', { type: type, countDown: countDown, }); } } } matchTeam(team: any) { let team_data: any = {}; team_data.teamid = team.teamid; // 队伍编号 team_data.wtime = 0; team_data.ltime = 0; team_data.fight_state = this.FightState.Wait; team_data.fight_end_time = 0; team_data.battle_index = 0; this.match_team.push(team_data); } /** * 活动开始-报名 * 备战-恶鬼竞赛 */ open() { this.player_list = {}; this.match_team = []; this.activity_state = ActivityDefine.activityState.ReadyOpen; let msg = `${this.name}开启,请前往长安城逐鹿处报名!`; PlayerMgr.shared.broadcast('s2c_notice', { strRichText: msg }); PlayerMgr.shared.broadcast('s2c_game_chat', { scale: 3, msg: msg, name: '', resid: 0, teamid: 0, }); this.inform_time = GTimer.getTime(); // 开始预热期-元魔竞赛 setTimeout(() => { this.inform_time = GTimer.getTime(); this.magic_warm_up(); }, this.state_time.prepare_magic_time); SKLogger.info(`活动(${this.name})已经开启!${this.name}状态改变 当前状态:开始报名`); } /** * 开始预热期比赛-元魔竞赛 * 10分钟后结束恶鬼竞赛 */ magic_warm_up() { // 更新活动状态 this.game_state = this.match_state.magic; this.activity_state = ActivityDefine.activityState.Opening; let count_player: number = Object.keys(this.player_list).length if (count_player >= 2) { World.shared.magicWorldMgr.onCreateWorldMagic(count_player * 2); for (const teamId in this.player_list) { if (this.player_list.hasOwnProperty(teamId)) { // 通知玩家-竞赛阶段 this.sayStage(TeamMgr.shared.getTeamInfo(teamId), this.match_state.magic, this.state_time.magic_time); PlayerMgr.shared.broadcast('s2c_game_chat', { scale: 3, msg: "上古战场突然间涌入恶鬼,请各位仙友展示自己的实力吧,消灭他们!", name: '', resid: 0, teamid: teamId, }); } } SKLogger.info(`活动(${this.name})已经开始刷新恶鬼!当前共${count_player}队伍参加!`) // 10分钟后结束预热期 通知前端 setTimeout(() => { this.inform_time = GTimer.getTime(); // 预热期比赛结束 this.magic_warm_up_end(); }, this.state_time.magic_time); } else { this.close(); SKLogger.info(`活动(${this.name})!当前共${count_player}队伍参加,参加队伍不足2个队伍将关闭本次活动!`) } } /** * 结束预热期比赛-元魔竞赛 * 备战阶段15分钟后进入-巅峰对决 */ magic_warm_up_end() { let score = 200; // 清理所有元魔 World.shared.magicWorldMgr.CheckWorldMagicDeadAll(); // 获取前3名队伍,前三名队伍增加巅峰积分; let list = this.integralTop(1); list.splice(1, list.length); for (const element of list) { score -= 50; let teamInfo = this.player_list[element.teamid]; // 更新 队伍积分状态集合 if (teamInfo) { let team = TeamMgr.shared.getTeamInfo(teamInfo.teamid); this.player_list[teamInfo.teamid] = { name: team.leader.name + '的队伍', pid: team.leader.roleid, // 队长角色编号 teamid: teamInfo.teamid, // 队伍编号 magic_score: teamInfo.magic_score, // 元魔积分 sat_score: teamInfo.sat_score, // 证道积分 peak: teamInfo.peak + score, // 队伍巅峰积分 num: team.playerlist.length, // 队伍人数 } } } // 通知队伍中玩家比赛状态-备战-巅峰对决 for (const teamId in this.player_list) { if (this.player_list.hasOwnProperty(teamId)) { this.sayStage(TeamMgr.shared.getTeamInfo(teamId), this.match_state.prepare_sat, this.state_time.prepare_sat_time); } } // 备战阶段 15分钟后进入-巅峰对决 setTimeout(() => { this.inform_time = GTimer.getTime(); // 备战-巅峰对决 this.SatPk(); }, this.state_time.prepare_sat_time); } /** * 进入-巅峰对决 */ SatPk() { // 即将关闭活动定时 setTimeout(() => { this.inform_time = GTimer.getTime(); // 即将关闭(活动结束前两分钟通知) this.readyClose(); }, this.state_time.sat_time - (2 * 60 * 1000)); // 关闭活动定时 setTimeout(() => { this.inform_time = GTimer.getTime(); // 活动结束-关闭 this.close(); }, this.state_time.sat_time); // 通知队伍中玩家比赛状态-巅峰对决 for (const teamId in this.player_list) { if (this.player_list.hasOwnProperty(teamId)) { this.sayStage(TeamMgr.shared.getTeamInfo(teamId), this.match_state.sat, this.state_time.sat_time); } } // 开始比赛 this.matching(); } /** * 即将关闭活动进行通知 */ readyClose() { this.activity_state = ActivityDefine.activityState.ReadyClose; // 关闭定时调整队伍 this.adjust_cancel.cancel(); // 关闭定时匹配队伍 this.matching_cancel.cancel(); let msg = `${this.name} 即将关闭,大家抓紧时间!`; PlayerMgr.shared.broadcast('s2c_notice', { strRichText: msg }); PlayerMgr.shared.broadcast('s2c_game_chat', { scale: 3, msg: msg, name: '', resid: 0, teamid: 0, }); } /** * 开始比赛 */ matching() { SKLogger.info(`逐鹿之战状态改变 当前状态:开始比赛`); this.checkMatch(this.match_team); this.matching_cancel = schedule.scheduleJob("0 0/5 * * * ? ", () => { this.checkMatch(this.match_team); }) this.adjust_cancel = schedule.scheduleJob("0/10 * * * * ? ", () => { this.checkFightTime(); }) } // 战斗开始之前的 10秒 beforeFight(t1: any, t2: any) { let team = TeamMgr.shared.getTeamInfo(t1.teamid); let eteam = TeamMgr.shared.getTeamInfo(t2.teamid); if (team && eteam) { let selfTeam = []; for (let index = 0; index < team.playerlist.length; index++) { let member = team.playerlist[index]; let satRole: any = {}; satRole.onlyid = member.onlyid; satRole.roleid = member.roleid; satRole.resid = member.resid; satRole.level = member.level; satRole.name = member.name; selfTeam.push(satRole); } let enemyTeam = []; for (let index = 0; index < eteam.playerlist.length; index++) { let member = eteam.playerlist[index]; let satRole: any = {}; satRole.onlyid = member.onlyid; satRole.roleid = member.roleid; satRole.resid = member.resid; satRole.level = member.level; satRole.name = member.name; enemyTeam.push(satRole); } TeamMgr.shared.broadcast(t1.teamid, 's2c_sat_match', { teamS: selfTeam, teamE: enemyTeam, }); TeamMgr.shared.broadcast(t2.teamid, 's2c_sat_match', { teamS: enemyTeam, teamE: selfTeam, }); t1.fight_state = this.FightState.Fighting; t2.fight_state = this.FightState.Fighting; setTimeout(() => { this.startFight(t1, t2); }, 11 * 1000); } } /** * 进入战斗 * @param t1 * @param t2 */ startFight(t1: any, t2: any) { let team = TeamMgr.shared.getTeamInfo(t1.teamid); let eteam = TeamMgr.shared.getTeamInfo(t2.teamid); if (team && eteam) { let eonlyid = eteam.leader.onlyid; team.leader.playerBattle(eonlyid, BattleType.Sat); } } /** * 战斗休息10秒 */ checkFightTime() { let nowtime = Date.now(); for (const teaminfo of this.match_team) { if (teaminfo.fight_state == this.FightState.FightEnd) { if (nowtime - teaminfo.fight_end_time > 10 * 1000) { teaminfo.fight_end_time = 0; teaminfo.fight_state = this.FightState.Wait; } } } } /** * 获得匹配队伍 * @param teamid */ getMatchTeamInfo(teamid: any): any { for (let teaminfo of this.match_team) { if (teaminfo.teamid == teamid) { return teaminfo; } } return null; } /** * 匹配队伍进行战斗 */ checkMatch(match: any) { if (match.length <= 1) { this.close(); } else { let peak_team_all: any = []; let peak_team: any = []; let num = Math.floor(match.length / 2); let flag = true; for (let i = 0; i < num; i++) { let count = 0; while (flag) { if (peak_team.length < 2) { if (count >= 5) { flag = false; continue; } count++; let ran = Math.floor(Math.random() * match.length); if (peak_team_all.indexOf(match[ran]) != -1 || match[ran].fight_state != this.FightState.Wait) { continue; } peak_team.push(match[ran]); peak_team_all.push(match[ran]); } else { flag = false; } } if (peak_team.length >= 2) { if (peak_team[0].teamid != peak_team[1].teamid){ this.beforeFight(peak_team[0], peak_team[1]); } } peak_team = []; flag = true; } } } /** * 玩家点击挑战 */ challenge(player: any, rivalTeamId: any) { if (player.teamid == rivalTeamId){ player.send_notice("您不可以挑战自己哦!"); return; } // 获取己方队伍信息 let oneself = this.getMatchTeamInfo(player.teamid); // 获取敌方队伍信息 let rival = this.getMatchTeamInfo(rivalTeamId); if (oneself == null) { player.send_notice("获取您的信息失败!"); SKLogger.info("您的队伍ID:"+player.teamid+ "集合:"+SKDataUtil.toJson(this.match_team,"[]")) return; } if (rival == null) { player.send_notice("获取挑战者信息失败!"); SKLogger.info("挑战者队伍ID:"+rivalTeamId+ "集合:"+SKDataUtil.toJson(this.match_team,"[]")) return; } if (oneself.fight_state != this.FightState.Wait) { player.send_notice("您当前在保护阶段不可以进行挑战!"); return; } if (rival.fight_state != this.FightState.Wait) { player.send_notice("对方在保护阶段不可以进行挑战!"); return; } this.beforeFight(oneself, rival); } /** * 奖励 * @param teamId * @param type 1 元魔 0 证道 * @param isWin 1 胜利 0 失败 */ sendReward(teamId: any, isWin: any, type: number) { let teamInfo = this.player_list[teamId]; if (teamInfo != null) { let team = TeamMgr.shared.getTeamInfo(teamId); if (team) { // 获取队伍战斗分数(胜利 人数 * 10,失败 人数 * 5) let score = isWin == 1 ? 10 * team.playerlist.length : 5 * team.playerlist.length; // 更新参数队伍的积分 let dataScore = this.updateMatchScore(isWin, score, teamId, type, team, teamInfo); for (const member of team.playerlist) { // 获取随机道具 let item = this.goods_award[Math.floor((Math.random() * this.goods_award.length))]; let exp = member.level * 6000 + member.relive * 50000; let pExp = Math.floor(exp * 1.2); member.addExp(exp); // 随机发送几个道具 member.addItem(item, Math.floor(Math.random() * 3) + 1, false, "逐鹿之战奖励!") member.curPet && (member.curPet.addExp(pExp)); // 同步证道积分 if (type == 0) { member.sat_integral += score; } // 通知前端更新积分信息 member.send('s2c_match_battles', { type: type, // 1 元魔 0 证道 isWin: isWin, // 1 胜利 0 失败 icon: item, // 图标 exp: exp, // 人物经验 petExp: pExp, // 宠物经验 score: score, // 当前获得分数 peak: dataScore.peak, // 当前巅峰积分 satScore: dataScore.satScore, // 队伍证道积分 matchScore: dataScore.matchScore // 队伍元魔积分 }); } } // 巅峰对决(巅峰积分小于等于0清理出场) if (type == 0 && isWin == 0) { let info = this.player_list[teamId]; if (info.peak <= 0) { for (const member of team.playerlist) { member.send_notice("由于你所在队伍的巅峰积分不足,失去继续比赛资格!") } this.leaveSat(PlayerMgr.shared.getPlayerByRoleId(info.pid), teamId); // 当前队伍小于2个队伍直接结束活动 let count_player: number = Object.keys(this.player_list).length if (count_player <= 1) { this.close(); } } } } } /** * 更新参数队伍的积分 * @param isWin 1 胜利 0 失败 * @param score 分数 * @param teamId 队伍ID * @param type 1:元魔 0:证道 */ updateMatchScore(isWin: number, score: number, teamId: any, type: number, team: any, player_team: any): any { let data: any = {}; if (type == 1) { player_team.magic_score += score; } else { player_team.sat_score += score; if (isWin == 1){ player_team.peak += 50; }else { player_team.peak -= 50; } } // 巅峰积分 data.peak = player_team.peak; // 元魔积分 data.satScore = player_team.sat_score; // 证道积分 data.matchScore = player_team.magic_score; // 更新 队伍积分状态集合 this.player_list[teamId] = { name: team.leader.name + '的队伍', pid: team.leader.roleid, // 队长角色编号 teamid: teamId, // 队伍编号 magic_score: data.matchScore, // 元魔积分 sat_score: data.satScore, // 证道积分 peak: data.peak, // 队伍巅峰积分 num: team.playerlist.length, // 队伍人数 } return data; } /** * 返回当前逐鹿之战队员信息及分数信息 * @param player * @param teamId */ say_team_info(player: any, teamId: any) { let teamInfo = this.player_list[teamId]; if (teamInfo != null) { let team = TeamMgr.shared.getTeamInfo(teamId); if (team) { let list: any = []; for (const member of team.playerlist) { list.push({ "roleId": member.roleid, // 角色编号 "name": member.name, // 角色名称 "relive": member.relive, // 角色转生等级 "level": member.level, // 角色转生等级 "resid": member.resid, // 角色外观 "race": member.race // 角色种族 }) } player.send('s2c_say_team_info', { roleId: team.leader.roleid, // 队长角色编号 magic_score: teamInfo.magic_score, // 队伍元魔总积分 sat_score: teamInfo.sat_score, // 队伍证道总积分 gameState: this.game_state, // 当前证道大会阶段 teamInfo: SKDataUtil.toJson(list, "[]") // 队伍成员信息 }) } } else { player.send_notice("没有获取到您当前队伍报名信息!") } } /** * 积分榜信息 * @param player * @param type */ say_integral_info(player: any, type: number) { player.send('s2c_say_integral_info', { type: type, // 1 元魔,0 证道 gameState: this.game_state, // 当前逐鹿之战阶段 scoreboard: SKDataUtil.toJson(this.integralTop(type), "[]") // 逐鹿之战积分榜信息 }) } /** * 积分榜数据 * @param type */ integralTop(type: number) { let list: any = []; let count_player: number = Object.keys(this.player_list).length if (count_player >= 1) { let player_list: any = this.player_list; // 进行排序 let result: any; if (type == 0) { result = Object.values(player_list).sort((a: any, b: any) => { return b.magic_score - a.magic_score; }); } else { result = Object.values(player_list).sort((a: any, b: any) => { return b.sat_score - a.sat_score; }); } for (const entryInfo of result) { let team = TeamMgr.shared.getTeamInfo(entryInfo.teamid); let team_player: any = []; for (const member of team.playerlist) { team_player.push({ roleId: member.roleid, // 角色编号 name: member.name, // 角色名称 relive: member.relive, // 角色转生等级 level: member.level, // 角色等级 race: member.race, // 角色种族 resid: member.resid // 角色外观 }) } list.push({ captainName: team.leader.name, teamid: team.teamid, teamInfo: SKDataUtil.toJson(team_player, "[]"), score: type == 1 ? entryInfo.magic_score : entryInfo.sat_score }); } } list = list.sort((a: any, b: any) => { return b.score - a.score; }); return list; } // 战斗结束 battleEnd(teamid: any, iswin: any) { let teaminfo = this.getMatchTeamInfo(teamid); if (teaminfo != null) { if (teaminfo.fight_state == this.FightState.Fighting) { teaminfo.fight_state = this.FightState.FightEnd; teaminfo.fight_end_time = Date.now(); this.sendReward(teamid, iswin, 0); teaminfo.battle_index++; } } else { SKLogger.info(`证道队伍战斗结束未找到队伍编号:${teamid}`); } } /** * 关闭活动 */ close() { if (this.activity_state == ActivityDefine.activityState.Close) { return; } // 关闭定时调整队伍 if (this.adjust_cancel != undefined && this.adjust_cancel != null) { this.adjust_cancel.cancel(); } // 关闭定时匹配队伍 if (this.matching_cancel != undefined && this.matching_cancel != null) { this.matching_cancel.cancel(); } // 清理元魔 World.shared.magicWorldMgr.CheckWorldMagicDeadAll(); // 活动状态 this.activity_state = ActivityDefine.activityState.Close; // 公布第一名 let list = this.integralTop(0); if (list.length != 0) { let player_team = list[0]; let strRichText = `由于${player_team.captainName}的队伍表现出色,在本次逐鹿之战中大放光彩,成为本届逐鹿王者`; PlayerMgr.shared.broadcast('s2c_screen_msg', { strRichText: strRichText, bInsertFront: 0 }); // 通知全服展示 if (player_team) { PlayerMgr.shared.broadcast('s2c_sat_win', { info: player_team.teamInfo }) } } // 清理在场队伍跳转长安 for (const teamId in this.player_list) { if (this.player_list.hasOwnProperty(teamId)) { let team = this.player_list[teamId]; this.leaveSat(PlayerMgr.shared.getPlayerByRoleId(team.pid), teamId); } } // 清理数据 this.match_team = []; this.player_list = {}; } }