Files
ZYZ/game-server/app/services/guildActivity/guildActivityService.ts

1028 lines
43 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { ServerlistModel, ServerlistType } from "../../db/Serverlist";
import { RoleModel } from "../../db/Role";
import { GUILDACTIVITY } from "../../pubUtils/dicParam";
import { gameData, getBossHpRatio, getCityActivityRewards } from "../../pubUtils/data";
import { getCurDay, nowSeconds, getTimeFun, getZeroPoint, getZeroPointOfTime } from "../../pubUtils/timeUtil";
import { GUILD_ACTIVITY_STATUS, GET_POINT_WAYS, GUILD_ACTIVITY_TYPE, REDIS_KEY, AUCTION_SOURCE, MAIL_TYPE, CITY_STATUS, DEBUG_MAGIC_WORD, GUILD_POINT_WAYS, TASK_TYPE, AUCTION_TIME, CITY_ACTIVITY_DOOR, ABI_TYPE, PUSH_ROUTE, RACE_ACTIVITY_STATUS, SHOP_REFRESH_TYPE, COUNTER, RACE_EVENT_TYPE, BOSS_HP_RATIO_TYPE } from "../../consts";
import { Record, UserGuildActivityRecModel } from "../../db/UserGuildActivityRec";
import { GateMembersRec, CityParam, WoodenHorse, RaceActivityRankParam } from "../../domain/battleField/guildActivity";
import { DicGuildActivity } from "../../pubUtils/dictionary/DicGuildActivity";
import { getAllServers, getRoleOnlineInfo, getServerCreateTime, redisClient } from "../redisService";
import { SimpleGuildRankParam, SimpleRoleRankParam, GuildRankInfo, RoleRankInfo } from "../../domain/rank";
import { pinus } from "pinus";
import { GuildActivityRecordModel } from "../../db/GuildActivityRec";
import { genAuction, getGuildAuctionBasicNum, getGuildAuctionRewards, getRewardToDbFromMap, guildAuctionPreview } from "../auctionService";
import { sendMailByContent } from "../mailService";
import { GuildActivityCityType, GuildActivityCityModel } from "../../db/GuildActivityCity";
import { DicCityActivity } from "../../pubUtils/dictionary/DicCityActivity";
import { Rank } from "../rankService";
import { BossInstanceModel } from "../../db/BossInstance";
import { UserGuildModel } from "../../db/UserGuild";
import { addActive } from "../guildService";
import { ActivePlayer, GuildRecord, ServerRecordModel } from "../../db/ServerRecords";
import { getHonourObject } from "../role/rewardService";
import { sendMessageToCityWithSuc, sendMessageToGuildWithSuc, sendMessageToServerWithSuc, sendMessageToUserWithSuc } from "../pushService";
import { saveGuildGateHpLog } from "../../pubUtils/logUtil";
import { GuildActivityCityDeclareModel } from "../../db/GuildActivityCityDeclare";
import { getRandSingleEelm } from "../../pubUtils/util";
import { CounterModel } from "../../db/Counter";
import { setInterval } from "timers";
import { dispatch } from "../../pubUtils/dispatcher";
import { GuildModel } from "../../db/Guild";
import { getCityActivityObj, getGateActivityObj, getRaceActivityObj } from "../memoryCache/guildActivityData";
import { getBossHpRatioByServer } from "../guildBossService";
import { getHeroesAttributes } from "../playerCeService";
/**
* 定时任务,获得前一天的活跃玩家中位数武将战力
*/
export async function setPreDayActiveData(servers: ServerlistType[]) {
for (let server of servers) {
let roles = await RoleModel.getActivePlayers(server.id);
let activePlayerCnt = roles.length;
let activePlayerCe = 0, activePlayers: ActivePlayer[] = [];
let activeGuilds: GuildRecord[] = [];
for(let i = 0; i < roles.length; i++) {
let role = roles[i];
let activePlayer = new ActivePlayer(role);
if(i < 10) {
activePlayerCe += role.topLineupCe;
activePlayers.push(activePlayer);
}
if(role.hasGuild) {
let guildRecord = activeGuilds.find(cur => cur.guildCode == role.guildCode);
if(!guildRecord) {
activeGuilds.push({ guildCode: role.guildCode, players: [activePlayer] });
} else {
guildRecord.players.push(activePlayer);
}
}
}
await ServerRecordModel.updateData(server.id, { activePlayerCnt, activePlayerCe, activePlayers, activeGuilds });
}
return servers;
}
/**
* 根据当前时间判断军团活动倒计时
* @param id 军团活动id
*/
export function getGuildActivityStatus(id: number) {
let dicGuildActivity = gameData.guildActivity.get(id);
if (!dicGuildActivity) return false;
return getGuildActivityByDic(dicGuildActivity);
}
export async function getAllGuildActivityStatus(guildCode: string, serverId: number) {
let guildActivities: { aid: number, status: number, time: number, isOpen: boolean, isCompleted?: boolean }[] = [];
for(let [ aid, dicGuildActivity ] of gameData.guildActivity) {
let index = getGAIndexInPinus(aid);
let res = getGuildActivityByDic(dicGuildActivity);
let isCompleted = res.isOpen;
if(res.status == GUILD_ACTIVITY_STATUS.START && guildCode) {
let guildActivityRec = await GuildActivityRecordModel.getRecord(guildCode, serverId, aid, index);
if(guildActivityRec) isCompleted = guildActivityRec.isCompleted;
}
guildActivities.push({aid, ...res, isCompleted});
}
return guildActivities;
}
export function getGuildActivityByDic(dicGuildActivity: DicGuildActivity) {
let t = getTimeFun();
// console.log('*********', dicGuildActivity.startTime, dicGuildActivity.startMinute, dicGuildActivity.startSeconds)
let startTime = <number>t.getTimeWithHour(dicGuildActivity.startTime, dicGuildActivity.startMinute, dicGuildActivity.startSeconds);
let countdownTime = <number>t.getTimeWithHour(dicGuildActivity.countDown);
let { duringTime, openDay } = dicGuildActivity;
let endTime = startTime + duringTime;
let status = 0, time = 0;
let now = nowSeconds();
if (now >= countdownTime && now < startTime) {
status = GUILD_ACTIVITY_STATUS.WAITING;
time = startTime - now;
} else if (now >= startTime && now < endTime) {
status = GUILD_ACTIVITY_STATUS.START;
time = endTime - now;
} else {
status = GUILD_ACTIVITY_STATUS.END;
}
let day = getCurDay();
let isOpen = openDay.includes(day);
return {
status, time, isOpen
}
}
/**
* 根据每回合上报数据判断军功
* @param aid
* @param record
* @param memberRecord
*/
export function getRecordScore(aid: number, round: number, record: { round: number, dataId: number }[], memberRecord: GateMembersRec) {
let dicGuildActivity = gameData.guildActivity.get(aid);
if (!dicGuildActivity) return false;
let dicWarJson = gameData.warJson.get(dicGuildActivity.warid);
if (!dicWarJson) return false;
let { round: curRound, enemies: historyEnemies } = memberRecord;
let sum = 0, newRecords = new Array<Record>();
for (let { round, dataId } of record) {
if (!historyEnemies.includes(dataId)) {
let enemy = dicWarJson.find(cur => cur.dataId == dataId);
let enemyType = enemy.enemyType;
let score = gameData.gateActivityPoint.get(enemyType);
newRecords.push({ round, dataId, score, enemyType });
sum += score;
historyEnemies.push(dataId);
}
}
for (let i = curRound + 1; i <= round; i++) {
sum += gameData.gateActivityPoint.get(GET_POINT_WAYS.ROUND_START);
memberRecord.round = i;
}
return { score: sum, newRecords, memberRecord }
}
export async function getGateActivityRank(guildCode: string, serverId: number, roleId?: string, roleName?: string) {
let index = getGAIndexInPinus(GUILD_ACTIVITY_TYPE.GATE_ACTIVITY);
let r = new Rank(REDIS_KEY.GATE_ACTIVITY, { serverId, index }, true);
r.setGenerFieldsFun(generGuildActivityRankField);
let { ranks: guildRank, myRank: myGuildRank } = await r.getRankListWithMyRank({ guildCode });
if (!myGuildRank) {
myGuildRank = await r.generMyRankWithGuild(guildCode, 0, 0);
}
let myR = new Rank(REDIS_KEY.USER_GATE_ACTIVITY, { serverId, guildCode, index }, true);
myR.setGenerFieldsFun(generGuildActivityMemberRankField);
let { ranks: memberRank, myRank: myMemberRank } = await myR.getRankListWithMyRank({ roleId });
if (roleName && !myMemberRank) {
myMemberRank = await myR.generMyRankWithRole(roleId, 0, 0);
}
return { guildRank, myGuildRank, memberRank, myMemberRank }
}
export async function getCityActivityRank(guildCode: string, serverId: number, cityId: number, roleId?: string, roleName?: string) {
if(!cityId) {
return { guildRank: [], myGuildRank: undefined, memberRank: [], myMemberRank: undefined }
}
let index = getGAIndexInPinus(GUILD_ACTIVITY_TYPE.CITY_ACTIVITY);
let r = new Rank(REDIS_KEY.CITY_ACTIVITY, { serverId, cityId, index }, true);
r.setGenerFieldsFun(generGuildActivityRankField);
let { ranks: guildRank, myRank: myGuildRank } = await r.getRankListWithMyRank({ guildCode });
if (!myGuildRank) {
myGuildRank = await r.generMyRankWithGuild(guildCode, 0, 0);
}
let myR = new Rank(REDIS_KEY.USER_CITY_ACTIVITY, { serverId, guildCode, index }, true);
myR.setGenerFieldsFun(generGuildActivityMemberRankField);
let { ranks: memberRank, myRank: myMemberRank } = await myR.getRankListWithMyRank({ roleId });
if (roleName && !myMemberRank) {
myMemberRank = await myR.generMyRankWithRole(roleId, 0, 0);
}
return { guildRank, myGuildRank, memberRank, myMemberRank }
}
/**
* 获取和自己同屏的5个木牛流马
* @param guildCode
* @param serverId
*/
export async function getWoodenHorseList(guildCode: string, serverId: number) {
let obj = getRaceActivityObj();
let { myGuildRank, guildRank } = await obj.getRanks(serverId, guildCode);
let myRank = myGuildRank?.rank||0;
let startRank = myRank - 2 > 0 ? myRank - 2 : 1;
let endRank = startRank + 4;
let woodenHorseList = new Array<WoodenHorse>();
for (let { rank, code } of guildRank) {
if(rank >= startRank && rank <= endRank) {
let woodenHorse = await obj.getWoodenHorse(code, serverId);
if (woodenHorse) {
woodenHorseList.push(woodenHorse);
}
}
}
return woodenHorseList;
}
function generGuildActivityRankField(param: GuildRankInfo) {
let { rank, code, name, num } = param;
return new SimpleGuildRankParam(rank, code, name, num);
}
function generGuildActivityMemberRankField(param: RoleRankInfo) {
let { rank, roleId, roleName, num } = param;
return new SimpleRoleRankParam(rank, roleId, roleName, num);
}
/**
* 对这个guild服内所有军团发排行榜信息
* @param aid 活动类型
*/
export async function sendAllGuildRanks(aid: number) {
if (aid == GUILD_ACTIVITY_TYPE.GATE_ACTIVITY) {
let obj = getGateActivityObj();
let guilds = obj.getGuilds();
for (let [serverId, guildCodes] of guilds) {
for (let guildCode of guildCodes) {
let ranks = await getGateActivityRank(guildCode, serverId);
await sendMessageToGuildWithSuc(guildCode, PUSH_ROUTE.GATE_ACT_RANK, ranks);
}
}
} else if (aid == GUILD_ACTIVITY_TYPE.CITY_ACTIVITY) {
let obj = getCityActivityObj();
let { cities } = obj.getAllCities();
// console.log(JSON.stringify(cities));
for (let { serverId, cityId, guildCodes } of cities) {
for (let guildCode of guildCodes) {
let ranks = await getCityActivityRank(guildCode, serverId, cityId);
await sendMessageToGuildWithSuc(guildCode, PUSH_ROUTE.CITY_ACT_RANK, ranks);
}
}
}
}
export async function sendCityGuildRankToUser(serverId: number, cityId: number, guildCode: string, roleId: string) {
let ranks = await getCityActivityRank(guildCode, serverId, cityId);
await sendMessageToUserWithSuc(roleId, PUSH_ROUTE.CITY_ACT_RANK, ranks);
}
/**
* 活动结算奖励
* @param aid 活动类型
*/
export async function settleGuildActivityReward(aid: number) {
if (aid == GUILD_ACTIVITY_TYPE.GATE_ACTIVITY) {
let obj = getGateActivityObj();
let guilds = obj.getGuilds();
for (let [serverId, guildCodes] of guilds) {
// console.log('***** serverId', serverId, 'guildCodes', guildCodes);
for (let guildCode of guildCodes) {
await gateActivitySettleReward(guildCode, serverId);
}
}
} else if (aid == GUILD_ACTIVITY_TYPE.CITY_ACTIVITY) {
let obj = getCityActivityObj();
obj.endActivity();
let { cities } = obj.getAllCities();
for (let { serverId, cityId } of cities) {
await cityActivitySettleReward(cityId, serverId);
}
} else if (aid == GUILD_ACTIVITY_TYPE.RACE_ACTIVITY) {
let obj = getRaceActivityObj();
obj.stopRace();
for (let { guildCode, serverId } of obj.getGuilds()) {
let woodenHorse = await obj.getWoodenHorse(guildCode, serverId);
if (woodenHorse && woodenHorse.distance > 0 && !obj.hasSend(guildCode)) {
await raceActivitySettleReward(guildCode, woodenHorse);
}
}
}
}
// 全服发送结束新号
export async function sendEndMsgToAllServer() {
let serverlist = await getAllServers();
for (let serverId of serverlist) {
await sendMessageToServerWithSuc(serverId, PUSH_ROUTE.GUILD_ACTIVITY_END, {});
await sendGuildActivityStatus(serverId);
}
}
export async function sendGuildActivityStatus(serverId: number) {
let guildActivities: { aid: number, status: number, time: number, isOpen: boolean }[] = [];
gameData.guildActivity.forEach((dicGuildActivity, aid) => {
let res = getGuildActivityByDic(dicGuildActivity);
guildActivities.push({aid ,...res});
});
await sendMessageToServerWithSuc(serverId, PUSH_ROUTE.GUILD_ACTIVITY_STATUS, { guildActivities });
}
/**
* 单个城池城门血条破了之后给他发奖励
* @param guildCode 军团code
*/
export async function sendSingleCityActEndMsg(cityId: number, serverId: number) {
let obj = getCityActivityObj();
let guildCodes = obj.getGuildsInCity(serverId, cityId);
for (let guildCode of guildCodes) {
await sendMessageToGuildWithSuc(guildCode, PUSH_ROUTE.GUILD_ACTIVITY_END, {});
}
await cityActivitySettleReward(cityId, serverId);
}
/**
* 单个军团抵达赛道之后给他发奖励
* @param guildCode 军团code
*/
export async function sendSingleRaceActEndMsg(guildCode: string, woodenHorse: WoodenHorse) {
await sendMessageToGuildWithSuc(guildCode, PUSH_ROUTE.GUILD_ACTIVITY_END, {});
await raceActivitySettleReward(guildCode, woodenHorse);
}
/**
* 结算蛮夷入侵奖励
* @param guildCode 军团code
* @param serverId 服务器id
*/
export async function gateActivitySettleReward(guildCode: string, serverId: number) {
console.log('gateActivitySettleReward', guildCode, serverId);
let obj = getGateActivityObj();
let { members } = obj.getObj(guildCode, serverId);
// console.log('***** gateHp', gateHp, 'members', members);
let index = getGAIndexInPinus(GUILD_ACTIVITY_TYPE.GATE_ACTIVITY);
let r = new Rank(REDIS_KEY.GATE_ACTIVITY, { serverId, index }, true);
let rank = await r.getMyRank({ guildCode });
let guildScore = await r.getMyScore({ guildCode });
// console.log('****** ranks', rank, 'guildScore', guildScore);
let guild = await GuildModel.findByCode(guildCode, serverId, 'lv members');
let rewards = getGuildAuctionRewards(GUILD_ACTIVITY_TYPE.GATE_ACTIVITY, rank, guild?.lv);
// console.log('***** rewards', JSON.stringify(rewards));
members = members.filter(member => {
return guild.members?.find(roleId => roleId == member.roleId);
});
let rec = await GuildActivityRecordModel.updateInfo(guildCode, GUILD_ACTIVITY_TYPE.GATE_ACTIVITY, index, {
isSuccess: true,
isCompleted: true,
rank, score: guildScore,
members, memberCnt: members.length,
auctionType: AUCTION_SOURCE.GATE,
rewards: getRewardToDbFromMap(rewards)
});
// 结算功勋等奖励
let dic = gameData.guildActivity.get(GUILD_ACTIVITY_TYPE.GATE_ACTIVITY);
let myR = new Rank(REDIS_KEY.USER_GATE_ACTIVITY, { serverId, guildCode, index }, true);
let hasSentMember: string[] = [];
let ranks = <RoleRankInfo[]>await myR.getRankByRange();
for (let { rank, roleId, num: myScore } of ranks) {
if(hasSentMember.indexOf(roleId) == -1) {
let honour = dic.honour + myScore * GUILDACTIVITY.GATEACTIVITY_HONOUR_RATIO;
await updateUserRecAndSendHonour(honour, myScore, rank, roleId);
hasSentMember.push(roleId);
}
}
for (let { roleId } of members) {
// 只参加了,没有分数的人
if(hasSentMember.indexOf(roleId) == -1) {
await updateUserRecAndSendHonour(dic.honour, 0, 0, roleId);
hasSentMember.push(roleId);
}
// 发放活跃
await addActive(roleId, serverId, GUILD_POINT_WAYS.ACTIVITY); //获得活跃值
}
// 加入拍卖行
await genAuction(guildCode, AUCTION_SOURCE.GATE, rec.code, serverId, rewards);
// obj.delGuildRecord(guildCode, serverId);
}
async function updateUserRecAndSendHonour(honour: number, myScore: number, rank: number, roleId: string) {
let honourObj = getHonourObject(Math.floor(honour));
await sendMailByContent(MAIL_TYPE.GUILD_ACTIVITY_REWARD, roleId, { goods: [honourObj] })
await UserGuildActivityRecModel.updateInfoByRoleId(roleId, { score: myScore, rank });
}
/**
* 结算诸侯入侵奖励
* @param cityId 城镇id
* @param serverId 服务器id
*/
export async function cityActivitySettleReward(cityId: number, serverId: number) {
console.log('###### cityActivitySettleReward 0')
let obj = getCityActivityObj();
if(!obj.lockCity(serverId, cityId)) return;
let dicCity = gameData.cityActivity.get(cityId);
if (!dicCity) return;
let {gateHp} = await obj.getGateHpAndInc(serverId, cityId);
let isSuccess = gateHp <= 0; // 血条未击破则没有占领军团
let index = getGAIndexInPinus(GUILD_ACTIVITY_TYPE.CITY_ACTIVITY);
let r = new Rank(REDIS_KEY.CITY_ACTIVITY, { serverId, cityId, index }, true);
let ranks = <GuildRankInfo[]>await r.getRankByRange();
console.log('###### cityActivitySettleReward 1', JSON.stringify(ranks));
for (let { rank: guildRank, code: guildCode, name, num } of ranks) {
if (guildRank == 1) {
if (isSuccess) {
await GuildActivityCityModel.guard(serverId, cityId, guildCode, name, index + 1); // 占领
if(getCurDay(true) != 6) {
await declareCity(serverId, "", guildCode, dicCity.nextCity, true, index + 1);
}
} else {
await GuildActivityCityModel.guard(serverId, cityId, "", "", index + 1); // 无人能占领
}
}
let guild = await GuildModel.findByCode(guildCode, serverId, 'lv members');
let rewards = getGuildAuctionRewards(GUILD_ACTIVITY_TYPE.CITY_ACTIVITY, guildRank, guild?.lv, cityId);
let members = obj.getMembersOfGuild(guildCode);
members = members.filter(member => {
return guild.members?.find(roleId => roleId == member.roleId);
});
let rec = await GuildActivityRecordModel.updateInfo(guildCode, GUILD_ACTIVITY_TYPE.CITY_ACTIVITY, index, {
members, memberCnt: members.length,
isSuccess, isCompleted: true,
rank: guildRank, damage: num, remainGateHp: gateHp,
rewards: getRewardToDbFromMap(rewards),
auctionType: AUCTION_SOURCE.CITY,
}, cityId);
// 奖励加入拍卖行
await genAuction(guildCode, AUCTION_SOURCE.CITY, rec.code, serverId, rewards);
let dic = gameData.guildActivity.get(GUILD_ACTIVITY_TYPE.CITY_ACTIVITY);
let myR = new Rank(REDIS_KEY.USER_CITY_ACTIVITY, { serverId, guildCode, index }, true);
let ranks = <RoleRankInfo[]>await myR.getRankByRange();
let userRank = 0;
let hasSentMember: string[] = [];
for (let { rank, roleId, num: myScore } of ranks) {
if(hasSentMember.indexOf(roleId) == -1) {
let honour = dic.honour + getCityActivityRewards(dicCity.type, guildRank, rank);
await updateUserRecAndSendHonour(honour, myScore, rank, roleId);
hasSentMember.push(roleId);
}
userRank = rank;
}
for (let { roleId } of members) { // 只参加了,没有分数的人
if(hasSentMember.indexOf(roleId) == -1) {
let honour = dic.honour + getCityActivityRewards(dicCity.type, guildRank, userRank);
await updateUserRecAndSendHonour(honour, 0, 0, roleId);
hasSentMember.push(roleId);
}
// 发放活跃
await addActive(roleId, serverId, GUILD_POINT_WAYS.ACTIVITY); //获得活跃值
}
}
}
// export async function autoDeclare() {
// for(let [ cityId ] of gameData.cityActivity) {
// let msg = { cityId, declareGuildCode: "", declareCount: 0 };
// await sendMessageToCityWithSuc(cityId, PUSH_ROUTE.GUILD_CITY_DECLARE, msg);
// }
// }
/**
* 获取活动参加者
* @param guildCode 军团code
* @param sourceType 拍卖类型 AUCTION_SOURCE
* @param sourceCode 活动唯一code
*/
export async function participants(guildCode: string, sourceType: number, sourceCode: string) {
if(sourceCode == DEBUG_MAGIC_WORD) {
let userGuilds = await UserGuildModel.getListByGuild(guildCode);
return userGuilds.map(cur => {
return { roleId: cur.roleId, job: cur.job, baseNum: 0 }
})
}
if (sourceType == AUCTION_SOURCE.BOSS) {
let rec = await BossInstanceModel.findBySourceCode(guildCode, sourceCode);
if (!rec) return [];
let dic = gameData.bossBaseByBossLv.get(rec.bossLv);
return rec.ranks.map(cur => {
return { roleId: cur.roleId, job: cur.job, baseNum: dic?.basicDividend||0 }
});
} else {
let rec = await GuildActivityRecordModel.findBySourceCode(guildCode, sourceType, sourceCode);
if (!rec) return [];
let guild = await GuildModel.findByCode(guildCode, null, 'lv');
let baseNum = getGuildAuctionBasicNum(rec.aid, rec.rank, guild?.lv, rec.challengeCityId);
let members = rec.members || [];
return members.map(cur => {
return { roleId: cur.roleId, job: cur.job, baseNum }
})
}
}
/**
* 获取诸侯入侵各个城池状态
* @param guildCode 我方军团
* @param dbCities 所有城池
*/
export function getCities(guildCode: string, dbCities: GuildActivityCityType[]) {
let cities = new Array<CityParam>();
for (let [cityId, dic] of gameData.cityActivity) {
let param = new CityParam(cityId);
let curCity = dbCities.find(cur => cur.cityId == cityId);
if (curCity) {
param.guardGuildCode = curCity.guardGuildCode || "";
param.guardGuildName = curCity.guardGuildName || "";
param.declareCount = curCity.declareCount || 0;
}
param.status = getCityStatus(guildCode, cityId, dic, dbCities);
cities.push(param);
}
return cities
}
/**
* 诸侯混战 获取城池状态
* @param guildCode
* @param cityId
* @param dic
* @param dbCities
*/
export function getCityStatus(guildCode: string, cityId: number, dic: DicCityActivity, dbCities: GuildActivityCityType[]) {
let status = CITY_STATUS.NOT_OPEN;
let d = getCurDay(true);
let { week, preCity } = dic;
let activityStatus = getGuildActivityStatus(GUILD_ACTIVITY_TYPE.CITY_ACTIVITY);
if (!activityStatus) {
return CITY_STATUS.NOT_OPEN
}
let dicGuildActivity = gameData.guildActivity.get(GUILD_ACTIVITY_TYPE.CITY_ACTIVITY);
let { openDay } = dicGuildActivity;
let curIndex = openDay.indexOf(week[0]);
let startDay = openDay[curIndex - 1] || 0;
let endDay = openDay[openDay.length - 1] || 0;
if (d >= startDay && d <= endDay) status = CITY_STATUS.CAN_DECLARE;
if (d == startDay && activityStatus.status != GUILD_ACTIVITY_STATUS.END) status = CITY_STATUS.NOT_OPEN;
if (d == endDay && activityStatus.status == GUILD_ACTIVITY_STATUS.END) status = CITY_STATUS.NOT_OPEN;
let curCity = dbCities.find(cur => cur.cityId == cityId);
if (curCity) {
if (curCity.declareGuilds?.includes(guildCode)) {
status = CITY_STATUS.DECLARED;
} else if (curCity.guardGuildCode == guildCode) {
status = CITY_STATUS.GUARD;
}
}
// let hasGuard = false, hasDeclared = false;
// for(let { cityId: _cityId, guardGuildCode, declareGuilds } of dbCities) {
// let dicCity = gameData.cityActivity.get(_cityId);
// if(dicCity.type == dic.type) {
// if(guardGuildCode == guildCode) hasGuard = true;
// if(declareGuilds.includes(guildCode)) hasDeclared = true;
// }
// }
// if(status == CITY_STATUS.CAN_DECLARE && !hasDeclared && preCity.length > 0) {
// status = CITY_STATUS.NOT_OPEN;
// }
return status;
}
export async function sendGuildCityDeclare(serverId: number, cityId: number, declareGuildCode: string, declareCount: number) {
let msg = { cityId, declareGuildCode, declareCount };
await sendMessageToCityWithSuc(serverId, cityId, PUSH_ROUTE.GUILD_CITY_DECLARE, msg);
await sendMessageToGuildWithSuc(declareGuildCode, PUSH_ROUTE.GUILD_CITY_DECLARE, msg);
}
/**
* 每秒计算木牛流马状态并下发
* @param serverId 区id
*/
export async function calWoodenHorseAndSend(serverId: number) {
// console.log('calWoodenHorseAndSend');
let obj = getRaceActivityObj();
return await obj.calServerHorses(serverId);
}
/**
* 木牛流马活动开始信号
*/
export async function sendRaceStartMsg(serverId: number) {
let obj = getRaceActivityObj();
obj.startRace(); // 设置开启活动
await sendMessageToServerWithSuc(serverId, PUSH_ROUTE.RACE_START, {});
await calWoodenHorseAndSend(serverId);
}
export async function guildActivityStart(aid: number) {
if(aid == GUILD_ACTIVITY_TYPE.GATE_ACTIVITY) {
let obj = getGateActivityObj();
obj.startActivity();
} else if (aid == GUILD_ACTIVITY_TYPE.CITY_ACTIVITY) {
let obj = getCityActivityObj();
obj.startActivity();
} else if (aid == GUILD_ACTIVITY_TYPE.RACE_ACTIVITY) {
}
}
/**
* 结算粮草先行奖励
* @param cityId 城镇id
* @param serverId 服务器id
*/
export async function raceActivitySettleReward(guildCode: string, woodenHorse: WoodenHorse) {
let { serverId, durability, distance, isRobot } = woodenHorse;
if(isRobot) return;
let obj = getRaceActivityObj();
// 已发送
obj.send(guildCode);
// 计算排名,计算耐久,发送奖励
let { guildRank, myGuildRank } = await obj.getRanks(serverId, guildCode);
let rank = myGuildRank?.rank||0;
let joinIndex = getJoinIndex();
console.log('##### raceActivitySettleReward', joinIndex, serverId, guildCode);
let r = new Rank(REDIS_KEY.RACE_ACTIVITY, { serverId, index: joinIndex });
await r.setRankWithGuildInfo2(guildCode, myGuildRank.num, myGuildRank.sortTime, myGuildRank.durability);
let nextWeek = <number>getTimeFun().getAfterDayWithHour(7);
await r.setExpire(nextWeek);
let isSuccess = distance >= GUILDACTIVITY.RACEACTIVITY_LENGTH; // 血条未击破则没有占领军团
let members = obj.getMembersOfGuild(guildCode);
let guild = await GuildModel.findByCode(guildCode, serverId, 'lv');
let rewards = getGuildAuctionRewards(GUILD_ACTIVITY_TYPE.RACE_ACTIVITY, rank, guild?.lv);
let rec = await GuildActivityRecordModel.updateInfo(guildCode, GUILD_ACTIVITY_TYPE.RACE_ACTIVITY, joinIndex, {
memberCnt: members.length, members,
isSuccess, isCompleted: true, rank,
rewards: getRewardToDbFromMap(rewards),
woodenHorse: woodenHorse.getTreatTime(),
});
if (rec) {
// 奖励加入拍卖行
await genAuction(guildCode, AUCTION_SOURCE.RACE, rec.code, serverId, rewards);
let dic = gameData.guildActivity.get(GUILD_ACTIVITY_TYPE.RACE_ACTIVITY);
let honour = dic.honour + Math.floor(durability * GUILDACTIVITY.RACEACTIVITY_DURABILITY_REWARD);
let hasSentMember: string[] = [];
for(let { roleId } of members) {
if(hasSentMember.indexOf(roleId) == -1) {
await updateUserRecAndSendHonour(honour, 0, rank, roleId);
// 发放活跃
await addActive(roleId, serverId, GUILD_POINT_WAYS.ACTIVITY); //获得活跃值
hasSentMember.push(roleId);
}
}
}
}
/**
* !! 注意,这条函数会改变内存中的字典表,仅用于测试中使用
* 改变字典表中的军团活动开始时间&持续时间
* @param {number} aid 活动
* @param {number} startSeconds 从现在开始几秒后开启活动
* @param {number} endSeconds 从开始之后几秒后结束活动
*/
export async function setDicGuildActivity(now: number, aid: number, startSeconds: number, endSeconds: number) {
let startTime = new Date(now + startSeconds * 1000);
if(aid != 0) {
let guildActivity = gameData.guildActivity;
let cur = guildActivity.get(aid);
cur.startMinute = startTime.getMinutes();
cur.startTime = startTime.getHours();
cur.startSeconds = startTime.getSeconds();
cur.duringTime = endSeconds;
}
return startTime.getTime();
}
export async function setDicAuctionTime(startTime: number, endActivity: number, startGuild: number, endGuild: number, startWorld: number, endWorld: number) {
// console.log('********* setDicAuctionTime', startTime, endActivity, startGuild, endGuild, startWorld, endWorld);
let startGuildDate = new Date(startTime + endActivity * 1000 + startGuild * 1000);
let endGuildDate = new Date(startGuildDate.getTime() + endGuild * 1000);
let startWorldDate = new Date(endGuildDate.getTime() + startWorld * 1000);
let endWorldDate = new Date(startWorldDate.getTime() + endWorld * 1000);
let startDividendData = new Date(startWorldDate.getTime() + 3 * 60 * 1000)
// console.log('********* setDicAuctionTime', startGuildDate, endGuildDate, startWorldDate, endWorldDate);
gameData.auctionTime.set(AUCTION_TIME.GUILD_PREVIEW, formatTime(new Date(startTime)));
gameData.auctionTime.set(AUCTION_TIME.GUILD_OPEN, formatTime(startGuildDate));
gameData.auctionTime.set(AUCTION_TIME.GUILD_CLOSE, formatTime(endGuildDate));
gameData.auctionTime.set(AUCTION_TIME.WORLD_PREVIEW, formatTime(endGuildDate));
gameData.auctionTime.set(AUCTION_TIME.WORLD_OPEN, formatTime(startWorldDate));
gameData.auctionTime.set(AUCTION_TIME.WORLD_CLOSE, formatTime(endWorldDate));
gameData.auctionTime.set(AUCTION_TIME.DIVIDEND_START, formatTime(startDividendData));
// console.log('*********** setDicAuctionTime', gameData.auctionTime)
}
function formatTime(date: Date) {
return { hour: date.getHours(), minute: date.getMinutes(), seconds: date.getSeconds() }
}
export async function getCityActivityGateHp(serverId: number, cityId: number) {
let dicCityActivity = gameData.cityActivity.get(cityId);
let playerResult = await getPlayerCnt(serverId);
if (!playerResult) return dicCityActivity.hp
let { activePlayerCnt, activeGuildCnt, activePlayerCe, activeTopPlayerCnt, activePlayers } = playerResult;
// 倍数按开服天数变化
let ratio = await getBossHpRatioByServer(BOSS_HP_RATIO_TYPE.CITY_RATIO, serverId);
// 单个玩家的平均攻击力
let playerAtkResult = await getPlayerAtkAvg(activePlayers);
if (!playerAtkResult) return dicCityActivity.hp;
let { playerAtkAvg, playerAtkSum, playerCnt } = playerAtkResult;
// *单个玩家5回合造成的总伤害=单个玩家的平均攻击力*倍数*5综合技能次级属性算出的倍数
let player5Damage = playerAtkAvg * ratio * 5;
// *平均一个军团的玩家人数=前一天参与军团活动的玩家/前一天参与军团活动的军团数量,
let guildPlayerCntAvg = await getGuildPlayerCntAvg(serverId, activePlayerCnt, activeGuildCnt);
// 城池倍数
let cityRatio = Math.max(Math.floor(activeGuildCnt/6), dicCityActivity.hpN);
// 城门血量=单个玩家5回合造成的总伤害*平均一个军团的玩家人数*城池倍数
let gateHp = Math.floor(player5Damage * guildPlayerCntAvg * cityRatio);
if(gateHp <= dicCityActivity.hp) {
gateHp = dicCityActivity.hp;
}
saveGuildGateHpLog(serverId, cityId, { activePlayerCnt, activePlayerCe, activeTopPlayerCnt, activeGuildCnt, ratio, playerAtkSum, playerCnt, playerAtkAvg, player5Damage, guildPlayerCntAvg, cityRatio, gateHp });
return gateHp;
}
// *单个玩家的平均攻击力=本服活跃玩家中最强6人排名前10的玩家的最强6人的攻击之和/10
async function getPlayerAtkAvg(activePlayers: ActivePlayer[]) {
if (!activePlayers || activePlayers.length <= 0) return false;
let playerAtkSum = 0, playerCnt = 0;
activePlayers.sort((a, b) => b.ce - a.ce);
for (let i = 0; i < 10; i++) {
if (!activePlayers[i]) break;
let onePlayerAtkSum = 0, heroCnt = 0;
let { roleId, topLineup = [] } = activePlayers[i];
let attrByHid = await getHeroesAttributes(roleId);
for (let { hid } of topLineup) {
let atk = attrByHid.get(hid)?.getAtk() || 0;
onePlayerAtkSum += atk;
heroCnt++;
}
if (heroCnt == 0) continue; // 基本不可能但是以防NaN
playerAtkSum += onePlayerAtkSum / heroCnt * 6;
playerCnt++;
}
if (playerCnt == 0) return false;
let playerAtkAvg = playerAtkSum / playerCnt;
return { playerAtkSum, playerAtkAvg, playerCnt };
}
async function getGuildPlayerCntAvg (serverId: number, activePlayerCnt: number, activeGuildCnt: number) {
let minRatio = await getBossHpRatioByServer(BOSS_HP_RATIO_TYPE.CITY_PLAYER_RATIO, serverId);
let guildPlayerCntAvg = Math.floor(activePlayerCnt / activeGuildCnt);
if (guildPlayerCntAvg < minRatio) return minRatio;
return guildPlayerCntAvg
}
async function getPlayerCnt(serverId: number) {
let serverRecord = await ServerRecordModel.findTodayData(serverId);
if(!serverRecord) return false;
let activePlayerCnt = 50; // 前一天参与军团活动的玩家
let activeGuildCnt = 5; // 前一天参与军团活动的军团
let activePlayerCe = 0; // 前一天前十玩家的最强战力和
let activeTopPlayerCnt = 1; // 前一天最强玩家数量
let activePlayers: ActivePlayer[] = [];
if(serverRecord) {
if(serverRecord.activePlayerCe > 0) activePlayerCe = serverRecord.activePlayerCe;
if(serverRecord.activePlayers?.length > 0) {
activeTopPlayerCnt = serverRecord.activePlayers?.length;
activePlayers = serverRecord.activePlayers||[];
}
if(serverRecord.activeGuildCodes?.length > 0) activeGuildCnt = serverRecord.activeGuildCodes?.length;
if(serverRecord.activeGuildMembers?.length > 0) activePlayerCnt = serverRecord.activeGuildMembers?.length;
}
return { activePlayerCnt, activeGuildCnt, activePlayerCe, activeTopPlayerCnt, activePlayers }
}
export async function declareCity(serverId: number, roleId: string, guildCode: string, cityId: number, isAutoDeclare: boolean, declareIndex: number) {
let declareTime = Date.now();
let declareInfo = await GuildActivityCityDeclareModel.declareIfNot(serverId, guildCode, cityId, roleId, declareTime, isAutoDeclare, declareIndex);
if(!!declareInfo && declareInfo.declareTime == declareTime) { // 确实没有人宣战过,自己是第一个
let cityRec = await GuildActivityCityModel.declare(serverId, cityId, guildCode, declareIndex);
await GuildActivityRecordModel.updateInfo(guildCode, GUILD_ACTIVITY_TYPE.CITY_ACTIVITY, declareIndex, {}, cityId);
await sendGuildCityDeclare(serverId, cityId, guildCode, cityRec.declareCount);
return true;
}
return false;
}
// 非军团长的团员自动宣战
export async function autoDeclareMyCity(serverId: number, roleId: string, guildCode: string, declareIndex: number) {
let checkResult = await GuildActivityCityDeclareModel.checkDeclartion(serverId, guildCode, declareIndex);
if(checkResult) return false
let cityIds = gameData.juniorCities;
let cities = await GuildActivityCityModel.findMinDeclareCountCity(serverId, cityIds, declareIndex);
let notDeclaredCitites = cityIds.filter(curCityId => {
return cities.findIndex(city => city.cityId == curCityId) == -1;
});
let cityId = notDeclaredCitites.length > 0? getRandSingleEelm(notDeclaredCitites): cities[0].cityId;
if(!cityId) return false;
return declareCity(serverId, roleId, guildCode, cityId, true, declareIndex);
}
function getCounterName(aid: GUILD_ACTIVITY_TYPE) {
switch(aid) {
case GUILD_ACTIVITY_TYPE.GATE_ACTIVITY:
return COUNTER.GATE_ACTIVITY;
case GUILD_ACTIVITY_TYPE.CITY_ACTIVITY:
return COUNTER.CITY_ACTIVITY;
case GUILD_ACTIVITY_TYPE.RACE_ACTIVITY:
return COUNTER.RACE_ACTIVITY;
}
}
export async function incCurGuildActivityIndex(aid: number) {
let name = getCounterName(aid);
let index = await CounterModel.getNewCounter(name);
setGuildActivityIndexInPinus(aid, index); // systime
pinus.app.rpc.guild.guildActivityRemote.setGuildActivityIndex.broadcast(aid, index);
}
export async function initGuildActivityIndexInPinus() {
for(let aid = GUILD_ACTIVITY_TYPE.GATE_ACTIVITY; aid <= GUILD_ACTIVITY_TYPE.RACE_ACTIVITY; aid++){
let index = await getCurGuildActivityIndexByDb(aid);
setGuildActivityIndexInPinus(aid, index);
}
}
export async function getCurGuildActivityIndexByDb(aid: number) {
let name = getCounterName(aid);
return await CounterModel.getCounter(name);
}
export function getGAPinusName(aid: number) {
return `guildact${aid}`;
}
export function setGuildActivityIndexInPinus(aid: number, index: number) {
pinus.app.set(getGAPinusName(aid), index);
}
export function getGAIndexInPinus(aid: number) {
return pinus.app.get(getGAPinusName(aid));
}
export function getDeclareIndex() {
let index = getGAIndexInPinus(GUILD_ACTIVITY_TYPE.CITY_ACTIVITY);
let obj = getCityActivityObj();
if(obj.getStatus() == GUILD_ACTIVITY_STATUS.START) return index;
return index + 1;
}
export function getJoinIndex() {
let index = getGAIndexInPinus(GUILD_ACTIVITY_TYPE.RACE_ACTIVITY);
let obj = getRaceActivityObj();
if(obj.getStatus() == GUILD_ACTIVITY_STATUS.START || obj.getStatus() == GUILD_ACTIVITY_STATUS.END) return index;
return index + 1;
}
export async function resetJoinWoodenHorse() {
let obj = getRaceActivityObj();
let joinIndex = getJoinIndex();
let guild = pinus.app.getServersByType('guild');
let recs = await GuildActivityRecordModel.findRecs(GUILD_ACTIVITY_TYPE.RACE_ACTIVITY, joinIndex);
for(let { serverId, guildCode, joinMember } of recs) {
let server = await dispatch(redisClient(), `${serverId}`, guild, 'guild');
if(server.id != pinus.app.getServerId()) continue;
for(let { roleId, roleName, job, code} of joinMember) {
let hasJoin = !!obj.getMember(guildCode, roleId);
if (hasJoin) continue;
await obj.joinWoodenHorse(guildCode, roleId, roleName, serverId, '', job, code);
}
}
return true
}
export async function debugSendGateHp(serverId: number, cityId: number) {
let obj = getCityActivityObj();
let { gateHp, maxHp } = await obj.getGateHpAndInc(serverId, cityId);
await sendMessageToCityWithSuc(serverId, cityId, PUSH_ROUTE.GUILD_CITY_ACT_HP, { cityId, gateHp: gateHp + 1000, maxHp });
}
export async function debugAddHorse(serverId: number, guildCode: string, memberCnt: number, itemInterval: number) {
let obj = getRaceActivityObj();
let dicItem = gameData.raceTypes.get(RACE_EVENT_TYPE.DEFAULT);
let items: number[] = [];
for(let [_, arr] of dicItem) {
items.push(...arr);
};
for(let i = 0; i < memberCnt; i++) {
let roleId = `roleId${i}`;
await obj.joinWoodenHorse(guildCode, roleId, 'roleName', serverId, null, 6, 'code', true);
}
if(itemInterval >= 100) {
let members = obj.getMembersOfGuild(guildCode);
let timer = setInterval(async () => {
await obj.useItem(serverId, members[0]?.roleId, '', guildCode, guildCode, getRandSingleEelm(items), 1, true);
let woodenHorse = await obj.getWoodenHorse(guildCode, serverId, true);
if(woodenHorse.status == RACE_ACTIVITY_STATUS.END) {
clearInterval(timer);
}
}, itemInterval);
setTimeout(() => {
clearInterval(timer);
}, 10 * 60 * 1000);
}
}
export async function leaveRaceActivity(serverId: number, guildCode: string, roleId: string ) {
if(!guildCode) return;
let obj = getRaceActivityObj();
await obj.memberLeave(guildCode, serverId, roleId);
}
export async function leaveRaceActivityToRemote(serverId: number, guildCode: string, roleId: string) {
let guildServers = pinus.app.getServersByType('guild')||[];
let server = await dispatch(redisClient(), `${serverId}`, guildServers, 'guild');
if(server) {
await pinus.app.rpc.guild.guildActivityRemote.leaveRaceActivity.toServer(server.id, serverId, guildCode, roleId);
}
}
export async function leaveRaceWhenQuitGuild(serverId: number, guildCode: string, roleId: string) {
if(!guildCode) return;
let obj = getRaceActivityObj();
await obj.memberQuit(guildCode, serverId, roleId);
let joinIndex = getJoinIndex();
await GuildActivityRecordModel.removeMember(guildCode, serverId, GUILD_ACTIVITY_TYPE.RACE_ACTIVITY, joinIndex, roleId);
}
export async function leaveRaceWhenQuitGuildToRemote(serverId: number, guildCode: string, roleId: string) {
let guildServers = pinus.app.getServersByType('guild')||[];
let server = await dispatch(redisClient(), `${serverId}`, guildServers, 'guild');
if(server) {
await pinus.app.rpc.guild.guildActivityRemote.leaveRaceWhenQuitGuild.toServer(server.id, serverId, guildCode, roleId);
}
let index1 = getGAIndexInPinus(GUILD_ACTIVITY_TYPE.GATE_ACTIVITY);
let gateR = new Rank(REDIS_KEY.USER_GATE_ACTIVITY, { serverId, guildCode, index: index1 }, true);
gateR.removeFromRank({ roleId });
let index2 = getGAIndexInPinus(GUILD_ACTIVITY_TYPE.CITY_ACTIVITY);
let declareIndex = getDeclareIndex();
let obj = getCityActivityObj();
if(obj.getStatus() == GUILD_ACTIVITY_STATUS.START) {
await autoDeclareMyCity(serverId, roleId, guildCode, declareIndex);
}
let city = await GuildActivityCityDeclareModel.findDeclartion(serverId, guildCode, declareIndex)
if (city) {
let cityR = new Rank(REDIS_KEY.CITY_ACTIVITY, { serverId, cityId: city.cityId, index: index2 }, true);
cityR.removeFromRank({ roleId });
}
}
export async function leaveRaceWhenDismiss(guildCode: string, serverId: number) {
if(!guildCode) return;
let obj = getRaceActivityObj();
obj.dismiss(guildCode);
let joinIndex = getJoinIndex();
await GuildActivityRecordModel.dismiss(guildCode, serverId, GUILD_ACTIVITY_TYPE.RACE_ACTIVITY, joinIndex);
}
export async function leaveRaceWhenDismissToRemote(serverId: number, guildCode: string) {
let guildServers = pinus.app.getServersByType('guild')||[];
let server = await dispatch(redisClient(), `${serverId}`, guildServers, 'guild');
if(server) {
await pinus.app.rpc.guild.guildActivityRemote.leaveRaceWhenDismiss.toServer(server.id, guildCode, serverId);
}
}