Files
ZYZ/game-server/app/services/battleService.ts
2020-12-09 17:23:15 +08:00

390 lines
15 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 { HeroModel } from './../db/Hero';
import { HangUpRecordModel } from './../db/HangUpRecord';
import { ChannelService } from 'pinus';
import { HANG_UP_CONSTS, TOWER_TASK_CONST, REDIS_KEY } from './../consts/consts';
import { BattleRecordModel } from './../db/BattleRecord';
import { TowerRecordModel } from './../db/TowerRecord';
import { RoleModel } from './../db/Role';
import { getHeroInfoById, getJobInfoById, getTowerDataByLv, getTaskById, getGamedata, getRandExpedition, getWarById, getWarJsons } from "../pubUtils/gamedata"
import { decodeArrayStr, shouldRefresh, resResult, decodeStr, cal, getRandomWithWeight, getRefTime, decodeStrSingle, genCode } from '../pubUtils/util';
import { handleFixedReward } from './rewardService';
import { STATUS } from '../consts/statusCode';
import { HangUpSpdUpRecModel } from '../db/HangUpSpdUpRec';
import { TowerTaskRecModel } from '../db/TowerTaskRec';
import { setRank } from './redisService';
export async function checkTowerWar(roleId: string, battleId: number, heroes: Array<number>) {
const battleIdStr = `${battleId}`;
let { towerLv } = await RoleModel.findByRoleId(roleId);
const towerInfo = getTowerDataByLv(towerLv);
if (!towerInfo) {
console.error(`天梯层数异常lv ${towerLv} by ${roleId}`);
return { status: -1, resResult: resResult(STATUS.TOWER_INFO_NOT_FOUND) };
}
const warIds = decodeArrayStr(towerInfo.warArray, '&') || [];
console.log(warIds, battleIdStr);
if (warIds.indexOf(battleIdStr) === -1) {
return { status: -1, resResult: resResult(STATUS.TOWER_WRONG_BATTLE_ID) };
}
const tower = await TowerRecordModel.getRecordByLv(roleId, towerLv);
if(!tower) {
return { status: -1, resResult: resResult(STATUS.TOWER_NOT_FOUND) };
}
let { heroes: recHeroes = [], warStatus = [] } = tower;
for (let hid of heroes) {
if (recHeroes.indexOf(hid) !== -1) {
return { status: -1, resResult: resResult(STATUS.TOWER_DUPLICATE_HERO) };
}
}
const curWarStatus = warStatus.find(elem => elem.warId == battleId);
if (curWarStatus && curWarStatus.status) {
return { status: -1, resResult: resResult(STATUS.TOWER_DUPLICATE_CHALLENGE) };
}
return { status: 0, data: {
heroes: recHeroes, warStatus: curWarStatus
}};
}
export async function towerBattleEnd(channelService: ChannelService, sid: string, roleId: string, serverId: number, battleCode: string, battleId: number, succeed: boolean, heroes: Array<number>) {
if (succeed) {
let battleRec = await BattleRecordModel.getBattleRecordByCode(battleCode);
if (battleRec.battleId != battleId) {
return { status: -1, resResult: resResult(STATUS.BATTLE_ID_NOT_MATCH) };
}
let { towerLv, roleName } = await RoleModel.findByRoleId(roleId);
let { warStatus, heroes: recHeroes } = await TowerRecordModel.getRecordByLv(roleId, towerLv);
for (let hid of heroes) {
if (recHeroes.indexOf(hid) !== -1) {
return { status: -1, resResult: resResult(STATUS.TOWER_DUPLICATE_CHALLENGE) };
}
}
let inc = 1;
warStatus.forEach(st => {
if (st.warId !== battleId && st.status === false) {
inc = 0;
}
})
let newRec = await TowerRecordModel.updateRecord(roleId, towerLv, battleCode, battleId, heroes, inc);
let towerReward = null;
if (inc === 1) {
let role = await RoleModel.towerLvUp(roleId);
// 更新redis
let { roleName, towerLv, towerUpTime, lv, vLv } = role;
await setRank(REDIS_KEY.TOWER_RANK, serverId, roleId, towerLv, towerUpTime.getTime(), {roleName, lv, vLv, guildName:"", head: "zhaoyun"});
const nextTowerInfo = getTowerDataByLv(towerLv + 1);
if (nextTowerInfo) {
const { warArray } = nextTowerInfo;
const sts = decodeArrayStr(warArray, '&').map(id => {
return {warId: parseInt(id), status: false};
});
await TowerRecordModel.createRecord({roleId, lv: towerLv + 1, warStatus: sts});
}
const { reward } = getTowerDataByLv(towerLv);
if (reward) towerReward = reward;
if (towerLv == HANG_UP_CONSTS.ENABLE_LV) {
await startHangUp(roleId, roleName);
channelService.pushMessageByUids('hangUpEnable', {code: 200, data: {enable: true}}, [{uid: roleId, sid}]);
}
}
return {
status: 0,
data: {
newRec,
towerReward,
towerStatus: !!inc
}
};
}
}
async function startHangUp(roleId: string, roleName: string) {
await HangUpRecordModel.initRecord(roleId, roleName);
}
export async function checkHangUpSpdUpCnt(roleId: string, cnt: number, curTime: Date) {
const role = await RoleModel.findByRoleId(roleId);
let {hangUpSpdUpCnt, gold, lastSpdUpTime} = role;
if (!lastSpdUpTime || (shouldRefresh(lastSpdUpTime, curTime, HANG_UP_CONSTS.REFRESH_TIME, 1) && hangUpSpdUpCnt <= HANG_UP_CONSTS.MAX_SPD_UP_CNT)) {
hangUpSpdUpCnt = HANG_UP_CONSTS.MAX_SPD_UP_CNT;
}
if (cnt > hangUpSpdUpCnt) {
return {status: -1, resResult:resResult(STATUS.TOWER_NOT_ENOUGH_HANG_UP_TIME)}
}
return {status: 0, data: {hangUpSpdUpCnt, gold, lastSpdUpTime}}
}
export async function calcuHangUpReward(roleId: string, speedUp = false, speedUpCnt = 1, curTime = new Date()) {
let { towerLv = 1, hangUpSpdUpCnt = 0, lastSpdUpTime } = await RoleModel.findByRoleId(roleId);
if(towerLv < HANG_UP_CONSTS.ENABLE_LV) {
return {status: -1, resResult: resResult(STATUS.TOWER_HANG_UP_NOT_START)}
}
let towerInfo = getTowerDataByLv(towerLv - 1); // towerLv 是当前层,奖励计算按照已经通过的层,即上一层
let timeReward = []; // 奖励
let needReceiveGoods = []; // 由于小数,未能领取的奖励
let baseReward = decodeStr('decimalReward', towerInfo.rewardOfcollect);
let { startTime } = await HangUpRecordModel.getCurRec(roleId);
let endTime = curTime; // 挂机结束时间现在到开始时间经历了10的倍数的时间
let deltaTime = curTime.getTime() - startTime.getTime(); // 累计的挂机时间,受最大时间限制
if (deltaTime > HANG_UP_CONSTS.MAX_TIME) {
deltaTime = HANG_UP_CONSTS.MAX_TIME;
endTime = curTime; // 累积到超过24小时那么结束时间和下一次开启时间就取整了
} else {
let multiReal = Math.floor(deltaTime / HANG_UP_CONSTS.UNIT_TIME);// 距开始挂机实际过去的时间单位
endTime = new Date(startTime.getTime() + multiReal * HANG_UP_CONSTS.UNIT_TIME)
}
if (speedUp) { // 加速直接收取6小时收益小数的累积和普通收取独立
if (hangUpSpdUpCnt >= speedUpCnt || !lastSpdUpTime || shouldRefresh(lastSpdUpTime, new Date, HANG_UP_CONSTS.REFRESH_TIME, 1)) { // 可加速
let multi = Math.floor(HANG_UP_CONSTS.SPD_UP_REC_TIME / HANG_UP_CONSTS.UNIT_TIME);
let spdUpRec = await HangUpSpdUpRecModel.getSpdUpRec(roleId, towerLv - 1);
let goods = [];
if(spdUpRec) {
let { notReceivedGoodsList = [], cnt } = spdUpRec;
let notReceivedGoods = notReceivedGoodsList.find(cur => cur.cnt == cnt );
goods = notReceivedGoods?notReceivedGoods.goods:[];
}
for(let {gid, count} of baseReward) {
let newCount = cal.mul(count, multi);
let oldGoods = goods.find(cur => cur.gid == gid);
if(oldGoods) newCount = cal.add(newCount, oldGoods.count);
let roundCount = Math.floor(newCount);
if(newCount > roundCount) {
needReceiveGoods.push({gid, count: cal.sub(newCount, roundCount)});
}
if(roundCount > 0) {
timeReward.push({gid, count: roundCount})
}
}
}
} else {
let lastRec = await HangUpRecordModel.getLastRec(roleId);
let notReceivedGoods = lastRec?lastRec.notReceivedGoods: [];
let multi = Math.floor(deltaTime / HANG_UP_CONSTS.UNIT_TIME); // 结算奖励的倍数,受最大时间限制
// console.log(deltaTime, multi, baseReward);
for(let {gid, count} of baseReward) {
let newCount = cal.mul(count, multi);
let oldGoods = notReceivedGoods.find(cur => cur.gid == gid);
if(oldGoods) newCount = cal.add(newCount, oldGoods.count);
let roundCount = Math.floor(newCount);
if(newCount > roundCount) {
needReceiveGoods.push({gid, count: cal.sub(newCount, roundCount)});
}
if(roundCount > 0) {
timeReward.push({gid, count: roundCount})
}
}
}
return {
status: 0,
data: {
endLv: towerLv - 1,
startTime,
deltaTime,
endTime,
timeReward,
needReceiveGoods
}
};
}
async function checkCond(roleId: string, heroes, type: number, param: number, cnt: number) {
let heroCnt = 0;
switch (type) {
case 1:
for(let seqId of heroes) {
const {star, colorStar} = await HeroModel.findBySeqIdAndRole(seqId, roleId);
if (star + colorStar >= param) {
heroCnt++;
}
}
break;
case 2:
for(let seqId of heroes) {
let {hid} = await HeroModel.findBySeqIdAndRole(seqId, roleId);
const hInfo = getHeroInfoById(hid);
if (hInfo.camp === param) {
heroCnt++;
}
}
break;
case 3:
for(let seqId of heroes) {
let {hid} = await HeroModel.findBySeqIdAndRole(seqId, roleId);
const hInfo = getHeroInfoById(hid);
if (getJobInfoById(hInfo.jobid).job_class === param) {
heroCnt++;
}
}
break;
default:
break;
}
if (heroCnt >= cnt) {
return true;
}
return false;
}
export async function checkTaskConditions(roleId: string, heroes: Array<number>, conditionsStr: string) {
let condition = decodeStr('towerTaskCondition', conditionsStr);
let res = true;
for (let {type, param, cnt} of condition) {
const checkRes = await checkCond(roleId, heroes, type, param, cnt);
if (!checkRes) {
res = false;
break;
}
}
return res;
}
/**
* 创建新的派遣任务
* @param towerLv 玩家层数
* @param roleId 玩家id
* @param roleName 玩家名
* @param hideNum 隐藏的任务数量
*/
export async function createCurTasks(towerLv: number, batchCode: string, roleId: string, roleName: string, hideNum: number, showNum: number, rids: Array<number>) {
let randomList = [];
let dicTask = getGamedata('dic_zyz_search');
for(let task of dicTask) {
let {suitFloor} = task;
let {min, max} = decodeStrSingle('suitLevelSingle', suitFloor);
let flag = max?(towerLv >= min && towerLv <= max): (towerLv >= min);
if(flag) {
randomList.push(task);
}
}
let returnTasks = new Array();
const arr = [{refreshStatus: 0, num: hideNum}, {refreshStatus: 1, num: showNum}];
for(let {refreshStatus, num} of arr) {
let taskIds = [];
for(let i = 0; i < num; i++) {
let list = randomList.filter(cur => !rids.includes(cur.taskId));
let {dic: tmp} = getRandomWithWeight(list);
if(tmp) {
taskIds.push(tmp.taskId);
rids.push(tmp.taskId)
}
}
const curTasks = await TowerTaskRecModel.createTasks(roleId, roleName, batchCode, taskIds, refreshStatus);
console.log(curTasks.length)
if(refreshStatus == 1) {
returnTasks = curTasks;
}
}
return returnTasks;
}
export function getRemainTime(curTime: Date) {
let nextTime = getRefTime(curTime, TOWER_TASK_CONST.REFRESH_TIME, 1);
return Math.floor((nextTime.getTime() - curTime.getTime())/1000);
}
export function treatTask(recs: Array<any>, curTime: Date) {
return recs.map(cur => {
let { heroes, batchCode, taskId, taskCode, status, completeTime} = cur;
let getStatusResult = getTaskStatus(status, completeTime, curTime);
return { heroes, batchCode, taskId, taskCode, completeTime, ...getStatusResult }
});
}
// 刷新任务,正在进行中的部分保留,没有进行中的刷掉
export function getDoingOrWaitingTasks (taskList: Array<any>, curTime: Date) {
let doingTaskCode = new Array<string>(), waitingTaskCode = new Array<string>(), doingIds = new Array<number>();
for(let task of taskList) {
let {status} = getTaskStatus(task.status, task.completeTime, curTime);
if(status == 1||status == 2) {
doingTaskCode.push(task.taskCode);
doingIds.push(task.taskId);
} else if(status == 0|| status == 3) {
waitingTaskCode.push(task.taskCode);
}
}
return {doingTaskCode, waitingTaskCode, doingIds}
}
export function getTaskStatus(status: number, completeTime: Date, curTime: Date) {
let remainTime = 0;
if(status == 1) {
// console.log(curTime.getTime(), completeTime.getTime())
remainTime = Math.floor((completeTime.getTime() - curTime.getTime())/1000);
if(remainTime < 0) {
status = 2; remainTime = 0;
}
}
return {status, remainTime}
}
export async function getTasksReward(roleId: string, curTime: Date) {
let oldTasks = await TowerTaskRecModel.getCurTasks(roleId);
let goods = [];
for(let task of oldTasks) {
let {completeTime, reward, termsForAdd, additionalReward} = getTaskById(task.taskId);
if (task.sendTime && task.sendTime.getTime() + completeTime * 1000 < curTime.getTime()) {
goods = goods.concat(decodeStr('fixReward', reward));
if(termsForAdd) {
const result = checkTaskConditions(roleId, task.heroes, termsForAdd);
goods = goods.concat(decodeStr('fixReward', result?additionalReward:''));
}
}
}
return goods
}
/**
* 获取随机机器人数据
* @param cnt 机器人数量
* @param withAttr 是否返回属性false: 仅返回阵容
*/
export function getRandRobot(cnt = 1, withAttr = false) {
let setInfo = getRandExpedition(cnt);
if (!setInfo || setInfo.length !== cnt) return null;
let robots = [];
for (let info of setInfo) {
if (!info || !info.warId) continue;
const warInfo = getWarJsons(info.warId).json;
if (!warInfo || !warInfo.length) continue;
let heroes = [];
for(let hero of warInfo) {
if (hero && hero.relation === 2 && hero.actorId) {
heroes.push(hero.actorId);
}
}
robots.push(heroes);
}
return robots;
}
/**
* 拷贝敌军数组并添加当前血量字段
* @param source 原敌军数组,不包含当前血量字段
*/
export function transBossHpArr(source: Array<{dataId: number, hp: number, actorId: number}>): Array<{dataId: number, hp: number, curHp: number, actorId: number}> {
let desArr = [];
source.forEach(elem => {
let { hp } = elem;
desArr.push(Object.assign(elem, {curHp: hp}));
});
return desArr;
}