xy-server/game/activity/SatAssembly.ts

840 lines
30 KiB
TypeScript
Raw Permalink Normal View History

2025-04-23 09:34:08 +08:00
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 = `由于<color=#ee2c2c >${player_team.captainName}</c >的队伍表现出色,在本次<color=#00ff00 >逐鹿之战</c >中大放光彩,成为本届<color=#ffff00 >逐鹿王者</color >`;
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 = {};
}
}