Files
ZYZ/game-server/app/services/battleService.ts
T
2020-11-23 16:29:21 +08:00

350 lines
14 KiB
TypeScript

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 } 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, fire} = await HeroModel.findBySeqIdAndRole(seqId, roleId);
if (star + fire >= 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
}