/** * 体力系统 */ import { ActionPointModel, ActionPointType } from '../db/ActionPoint'; import { TASK_TYPE, STATUS, TA_EVENT, ITEM_CHANGE_REASON, PUSH_ROUTE } from '../consts'; import { checkTask } from './task/taskService'; import { getDicApByLv } from '../pubUtils/data'; import { pinus } from 'pinus'; import { resResult, shouldRefresh } from '../pubUtils/util'; import { pick } from 'underscore'; import { AP } from '../pubUtils/dicParam'; import { reportTAEvent } from './sdkService'; import { sendMessageToUserWithSuc } from './pushService'; /** * 获取当前体力 * @param roleId 玩家id * @param lv 玩家等级 */ export async function getAp(roleId: string, ip: string, lv: number, fromGetAp = false) { let dataAp = await ActionPointModel.getAp(roleId); return getApWithDataAp(roleId, ip, lv, dataAp, fromGetAp); } function getApWithDataAp(roleId: string, ip: string, lv: number, dataAp: ActionPointType, fromGetAp = false) { const now = Date.now(); const dicAp = getDicApByLv(lv); const maxAp = dicAp.maxAp; // 最大体力值 const per = AP.PERAPRESTORETIME * 1000; // 恢复时间(ms) let { ap, refTime, buyRefTime = 0, buyTimes = 0, apBefore } = dataAp; let oldAp = ap; if(shouldRefresh(new Date(buyRefTime), new Date())) { buyTimes = 0; } let result; if (ap >= maxAp) { // 体力溢出不需要做时间的处理 result = { ap, maxAp, refTime: now, apRemainTime: 0, apMaxRemainTime: 0, isOver: true, buyTimes, buyRefTime, apBefore }; } else { if (refTime > now) refTime = now; // refTime:每次记录时候最近的一个整的时间点,绝对不会大于now let n = Math.floor((now - refTime) / per); // 上次记录到现在可以增长多少体力 ap += n; // 增加上 if (ap >= maxAp) { // 加上后溢出了 ap = maxAp; result = { ap, maxAp, refTime: now, apRemainTime: 0, apMaxRemainTime: 0, isOver: true, buyTimes, buyRefTime, apBefore }; } else { refTime += n * per; // 更新refTime到离现在最近的一个整的时间点 let apRemainTime = Math.floor((refTime + per - now) / 1000); // 恢复下一点需要多少时间 let apMaxRemainTime = (maxAp - ap - 1) * AP.PERAPRESTORETIME + apRemainTime; result = { ap, maxAp, refTime, apRemainTime, apMaxRemainTime, isOver: false, buyTimes, buyRefTime, apBefore }; } } if(result.ap > oldAp) { reportTAEvent(roleId, TA_EVENT.AP_GET, { change_count: result.ap - oldAp, change_after: result.ap, change_reason: ITEM_CHANGE_REASON.AP_RECOVERY }) } return fromGetAp?result: pick(result, ['ap', 'maxAp', 'apRemainTime', 'apMaxRemainTime', 'buyTimes', 'apBefore']); } /** * 增加或减少体力 * @param roleId 玩家id * @param lv 玩家等级 * @param changeAp 体力变化,正是加,负是减 * @param sid */ export async function setAp(serverId: number, roleId: string, ip: string, lv: number, changeAp: number, sid: string, reason: ITEM_CHANGE_REASON) { // console.log('***** setAp', roleId, ip, lv, changeAp) const now = Date.now(); let ApResult = await getAp(roleId, ip, lv, true); let { ap: apBefore, maxAp, refTime, apRemainTime, apMaxRemainTime, isOver, buyTimes } = ApResult; // 更新ap let ap = apBefore + changeAp; if (ap >= maxAp) { // 溢出 refTime = now; apRemainTime = 0; apMaxRemainTime = 0; } if (ap < 0) return null // 体力不足 let dataAp = await ActionPointModel.saveAp(roleId, ap, apBefore, refTime); if (isOver && ap < maxAp) { // 特殊处理,溢出之后做减少体力的操作时 apRemainTime = AP.PERAPRESTORETIME; apMaxRemainTime = (maxAp - ap) * AP.PERAPRESTORETIME; } if (changeAp < 0) { await checkTask(serverId, roleId, sid, TASK_TYPE.BATTLE_COST_AP, { count: -changeAp }); // reportTAEvent(roleId, TA_EVENT.AP_CONSUME, { change_count: -1 * changeAp, change_after: ap, change_reason: reason }, ip) } else { reportTAEvent(roleId, TA_EVENT.AP_GET, { change_count: changeAp, change_after: ap, change_reason: reason }, ip) } let apJson = await getApWithDataAp(roleId, ip, lv, dataAp); if (changeAp != 0) { sendMessageToUserWithSuc(roleId, PUSH_ROUTE.AP_UPDATE, { apJson: { ...apJson, apBefore } }, sid); } return apJson } export async function setApBuyTimes(roleId: string, ip: string, lv: number, sid: string, incTimes: number) { if(incTimes <= 0) return false; let ApResult = await getAp(roleId, ip, lv, true); let { ap, maxAp, refTime, apRemainTime, apMaxRemainTime, buyTimes, buyRefTime } = ApResult; // 更新ap if(shouldRefresh(new Date(buyRefTime), new Date())) { buyTimes = 0; buyRefTime = new Date(); } buyTimes += incTimes; await ActionPointModel.saveBuyTimes(roleId, buyTimes, buyRefTime); let apJson = { ap, maxAp, refTime, apMaxRemainTime, apRemainTime, buyTimes }; if(incTimes != 0) { sendMessageToUserWithSuc(roleId, PUSH_ROUTE.AP_UPDATE, { apJson }, sid); } return apJson; }