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 = t.getTimeWithHour(dicGuildActivity.startTime, dicGuildActivity.startMinute, dicGuildActivity.startSeconds); let countdownTime = 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(); 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(); 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'); let rewards = getGuildAuctionRewards(GUILD_ACTIVITY_TYPE.GATE_ACTIVITY, rank, guild?.lv); // console.log('***** rewards', JSON.stringify(rewards)); 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 = 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 = 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'); let rewards = getGuildAuctionRewards(GUILD_ACTIVITY_TYPE.CITY_ACTIVITY, guildRank, guild?.lv, cityId); let members = obj.getMembersOfGuild(guildCode); 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 = 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(); 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 = 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 } = 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, 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 * 10; return { 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); } } 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); } }