Files
ZYZ/game-server/app/services/guildBossService.ts
2023-09-19 20:14:04 +08:00

282 lines
12 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 { BossInstanceType, BossInstanceModel } from '../db/BossInstance';
import { lockData } from '../services/redLockService';
import { findIndex, pick } from 'underscore';
import { sismemberAsync, smembersAsync, saddAsync, delAsync, getRoleOnlineInfo, getServerCreateTime } from '../services/redisService';
import { pinus } from 'pinus';
import { STATUS } from '../consts/statusCode';
import { resResult, shouldRefresh } from '../pubUtils/util';
import { BattleRecordModel } from '../db/BattleRecord';
import { getArmyBossRank, gameData, getBossHpRatio } from '../pubUtils/data';
import { sendMailToGuildByContent } from '../services/mailService';
import { MAIL_TYPE, AUCTION_SOURCE, ABI_TYPE, PUSH_ROUTE, BOSS_HP_RATIO_TYPE } from '../consts';
import { GUILD_BOSS_STATUS } from '../consts/constModules/guildConst';
import { genAuction } from './auctionService';
import { GuildModel, GuildType } from '../db/Guild';
import { UserGuildModel, UserGuildType } from '../db/UserGuild';
import { getZeroPoint, getZeroPointOfTime, nowSeconds } from '../pubUtils/timeUtil';
import { GUILDACTIVITY } from '../pubUtils/dicParam';
import { GuildRecord, ServerRecordModel } from '../db/ServerRecords';
import { sendMessageToGuildWithSuc, sendMessageToUsersWithSuc } from './pushService';
import { AttributeCal } from '../domain/roleField/attribute';
import { saveGuildBossHpLog } from '../pubUtils/logUtil';
import { getHeroesAttributes } from './playerCeService';
/**
* 获得boss界面
* @param bossInstance
* @param roleId
*/
export async function getBossInstanceInfo(userGuild: UserGuildType, guild?: GuildType) {
let bossInstance = await BossInstanceModel.findBossInstance(userGuild.guildCode);
if(!bossInstance) {
bossInstance = await BossInstanceModel.findLastOverBossInstance(userGuild.guildCode);
}
return await getBossInstanceInfoByData(bossInstance, userGuild, guild);
}
export async function getBossInstanceInfoByData(bossInstance: BossInstanceType, userGuild: UserGuildType, guild?: GuildType) {
if(!guild) guild = await GuildModel.findByCode(userGuild.guildCode, null, 'code refOpenBossTime openBossCnt');
let refObj = await getRefBossCnt(guild, userGuild); // 刷新次数
let status = bossInstance? bossInstance.status: GUILD_BOSS_STATUS.WAIT_OPEN;
if(status == GUILD_BOSS_STATUS.CLEAR) status = GUILD_BOSS_STATUS.WAIT_OPEN;
let bossInfo = null;
if(bossInstance) {
let { code, warId, ranks, bossHp, bossTotalHp, ratio, bossLv, encourageCnt } = bossInstance;
let dicBossBase = gameData.bossBaseByBossLv.get(bossLv);
let rankInfo = getRanks(ranks, userGuild.roleId);
bossInfo = { bossCode: code, warId, ...rankInfo, bossHp: zoomOutDamage(bossHp), bossTotalHp: zoomOutDamage(bossTotalHp), bossLv, encourageCnt, encourageMax: dicBossBase.encourageSum, ratio };
}
return { status, bossInfo, ...refObj }
}
export async function pushBossStatus(guildCode: string, result: any) {
await sendMessageToGuildWithSuc(guildCode, PUSH_ROUTE.GUILD_BOSS_OPEN, pick(result, ['status', 'bossInfo', 'leaderOpenCnt']));
}
async function getRefBossCnt(guild: GuildType, userGuild: UserGuildType) {
let guildCnt = await refreshGuildOfBoss(guild);
let userGuildCnt = await refreshUserGuildOfBoss(userGuild);
return { ...guildCnt, ...userGuildCnt }
}
export async function refreshGuildOfBoss(guild: GuildType, inc: number = 0) {
let { refOpenBossTime, openBossCnt, code } = guild;
if(shouldRefresh(refOpenBossTime, new Date())) {
openBossCnt = 0;
}
if(inc != 0) {
guild = await GuildModel.updateInfo(code, { refOpenBossTime: new Date(), openBossCnt: openBossCnt + inc });
openBossCnt = guild.openBossCnt;
}
return { leaderOpenCnt: openBossCnt }
}
export async function refreshUserGuildOfBoss(userGuild: UserGuildType, incEncourage = 0, incChallenge = 0) {
let { refBossTime, encourageCnt, bossChallengeCnt } = userGuild;
if(shouldRefresh(refBossTime, new Date())) {
encourageCnt = 0, bossChallengeCnt = 0;
}
if(incEncourage != 0 || incChallenge != 0) {
userGuild = await UserGuildModel.updateInfo(userGuild.roleId, { refBossTime: new Date(), encourageCnt: encourageCnt + incEncourage, bossChallengeCnt: bossChallengeCnt + incChallenge }, {});
encourageCnt = userGuild.encourageCnt;
bossChallengeCnt = userGuild.bossChallengeCnt;
}
return { myChallengeCnt: bossChallengeCnt, myEncourageCnt: encourageCnt }
}
export function getRanks(ranks: {roleId: string; score: number; time: number; job: number;}[], roleId: string ) {
ranks.sort(function(a, b) {
return b.score - a.score + a.time - b.time;
});
let myRank = {};
let lastRanks = ranks.map(({roleId: battleRoleId, score }, index) => {
if (roleId == battleRoleId) {
myRank = { roleId, score: zoomOutDamageWithoutRadix(score), rankLv: index + 1 };
}
return {roleId: battleRoleId, score: zoomOutDamageWithoutRadix(score), rankLv: index + 1};
});
return { ranks: lastRanks, myRank }
}
/**
* 获得排名区间奖励
* @param rankLv
*/
export function getArmyBossRankReward(rankLv: number) {
let armybossRankReward = getArmyBossRank();
for (let item of armybossRankReward) {
if (item.rankMin <= rankLv && (rankLv <= item.rankMax || item.rankMax == -1)) {
return item.reward;
}
}
}
/**
* 将玩家加入到正在挑战boss队列中
* @param code
* @param serverId
* @param roleId
*/
export async function addBossInstance(code: string, serverId:number, roleId: string) {
let hisOnlineInfo = await getRoleOnlineInfo(roleId);
if(hisOnlineInfo.isOnline) {
let key = 'serverId_' + serverId + 'guildCode_' + code;
let value = roleId+ '|' + hisOnlineInfo.sid;
await saddAsync(key, [value]);
}
}
/**
* 给当前正在挑战的玩家下发血量同步信息
* @param code
* @param serverId
* @param bossHp
* @param isDelKey
*/
export async function pushBossHpMessage(code: string, serverId:number, bossHp:number, isDelKey?: boolean ) {
let key = 'serverId_' + serverId + 'guildCode_' + code;
let members = await smembersAsync(key);
let uids = members.map(member=>{
let arr = member.split('|');
let uid = arr[0];
let sid = arr[1];
return {uid, sid};
});
sendMessageToUsersWithSuc(PUSH_ROUTE.BOSS_HP_UPDATE, { bossHp: zoomOutDamage(bossHp) }, uids);
if (isDelKey) {
delAsync(key);
}
}
/**
* 检查该玩家当前是否正在挑战boss的队列中
* @param code
* @param serverId
* @param roleId
* @param battleCode
*/
export async function checkBossBattleMemberExists(code: string, serverId:number, roleId: string, battleCode:string ) {
let hisOnlineInfo = await getRoleOnlineInfo(roleId);
let key = 'serverId_' + serverId + 'guildCode_' + code ;
let value = roleId+ '|' + hisOnlineInfo.sid;
let flag = await sismemberAsync(key, value);
if (!flag) {
const battleRecord = await BattleRecordModel.getBattleRecordByCode(battleCode, true);
if(!battleRecord || battleRecord.status != 0 || roleId != battleRecord.roleId) {
return false;
}
await addBossInstance(code, serverId, roleId);
flag = true;
}
return flag;
}
/**
* 成员退出删除boss关排行信息
* @param guildCode
* @param roleId
*/
export async function removeBossRank(guildCode: string, roleId: string) {
await BossInstanceModel.removeBossRank(guildCode, roleId);
}
function getBossSubAttrCe(hid: number, secondAttrLevel: number, bossLevel: number) {
let newAttribute = new AttributeCal();
newAttribute.setLv(bossLevel);
let subAttr = gameData.towerPvpSubAttr.get(secondAttrLevel);
if(subAttr) newAttribute.setByWarJson(hid, subAttr.secondAtr);
let newCe = newAttribute.calCe();
return newCe;
}
export async function getBossHp(serverId: number, guildCode: string, dicBossBaseWar: {warId: number, bossHp: number, bossHpRatio: number }, bossLv: number) {
let { warId, bossHp: minBossHp, bossHpRatio } = dicBossBaseWar;
console.log('getBossHp', warId, minBossHp, bossHpRatio)
let serverRecord = await ServerRecordModel.findTodayData(serverId);
if(!serverRecord) return { ratio: 1, bossHp: zoomInDamage(minBossHp) };
let activeGuilds = serverRecord.activeGuilds||[];
let myGuild = activeGuilds.find(cur => cur.guildCode == guildCode);
let playerAtkResult = await getPlayerAtkAvg(myGuild);
if (!playerAtkResult) return { ratio: 1, bossHp: zoomInDamage(minBossHp) };
// *军团的玩家人数=开启前一天军团内登录的玩家数
// *单个玩家的平均攻击力=军团前一天活跃玩家中最强6人排名前10的玩家的最强6人的攻击之和/10
let { playerAtkAvg, playerCnt, activeCe } = playerAtkResult;
// 倍数按开服天数变化
let ratio = await getBossHpRatioByServer(BOSS_HP_RATIO_TYPE.BOSS_RATIO, serverId);
// *单个玩家10回合造成的总伤害=单个玩家的平均攻击力*倍数*10
let player10Damage = playerAtkAvg * ratio * 10;
// boss血量=单个玩家10回合造成的总伤害*军团的玩家人数*2
let bossHp = Math.floor(player10Damage * playerCnt * 2);
let B = getB(warId, bossLv, activeCe, playerCnt);
if(B < 1) {
B = 1;
bossHp = minBossHp;
}
if(bossHp < minBossHp) {
B = 1;
bossHp = minBossHp;
}
saveGuildBossHpLog(serverId, warId, guildCode, { minBossHp, bossHpRatio, ratio, playerAtkAvg, player10Damage, activeCe, playerCnt, B, bossHp })
return { ratio: B, bossHp: zoomInDamage(bossHp) };
}
function getB(warId: number, bossLv: number, activeCe: number, playerCnt: number) {
let dicWar = gameData.war.get(warId);
if (!dicWar) return 1;
let actorId = gameData.heroIdByWar.get(warId);
let subCe = getBossSubAttrCe(actorId, dicWar.secondAttrLevel, bossLv)
let B = (activeCe/playerCnt/6 - subCe)/GUILDACTIVITY.GATEACTIVITY_ENEMYCE;
return B;
}
async function getPlayerAtkAvg(myGuild: GuildRecord) {
if (!myGuild) return false;
let playerAtkSum = 0, playerCnt = 0, activeCe = 0;
if (myGuild) {
let activePlayers = myGuild.players || [];
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 = [], topLineupCe = 0 } = 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++;
activeCe += topLineupCe;
}
}
if (playerCnt == 0) return false;
let playerAtkAvg = playerAtkSum / playerCnt * 10;
return { playerAtkAvg, playerCnt, activeCe };
}
export async function getBossHpRatioByServer(type: BOSS_HP_RATIO_TYPE, serverId: number) {
let serverOpenTime = await getServerCreateTime(serverId);
let serverZeroPoint = getZeroPointOfTime(serverOpenTime);
let todayZeroPoint = getZeroPoint();
let n = Math.floor((todayZeroPoint - serverZeroPoint)/86400) + 1;
return getBossHpRatio(type, n);
}
export function zoomInDamage(damage: number, ratio = 100) {
return Math.floor(damage * ratio);
}
export function zoomOutDamage(damage: number, ratio = 100) {
return Math.floor(damage)/ratio;
}
export function zoomOutDamageWithoutRadix(damage: number, ratio = 100) {
return Math.floor(damage/ratio);
}