Files
ZYZ/game-server/app/servers/battle/handler/rougeHandler.ts
T

1185 lines
55 KiB
TypeScript

import { Application, BackendSession, pinus, HandlerService, } from 'pinus';
import { RougelikeRecordModel } from '../../../db/RougelikeRecord';
import { genCode, getRandEelmWithWeight, resResult } from '../../../pubUtils/util';
import { COLLECTION_TYPE, ITEM_CHANGE_REASON, REST_POINT_TYPE, ROUGE_LIKE_CARD_TYPE, ROUGE_LIKE_CHOOSE_REWARD, ROUGE_LIKE_NODE_TYPE, ROUGE_LIKE_STATUS } from '../../../consts';
import { Quest, RestPoint, RougelikeRecordDetailModel } from '../../../db/RougelikeRecordDetail';
import { STATUS } from '../../../consts/statusCode';
import { RougelikeCardModel, RougelikeCardPara, RougelikeCardType } from '../../../db/RougelikeCard';
import { Card, RougelikeCharaModel, RougelikeCharaPara, RougelikeCharaType } from '../../../db/RougelikeChara';
import { CollectionReturnParam, CommonCard, CommonChara, RewardInter, RewardOption, RougeDamageInter, SlotCard, layerNode } from '../../../pubUtils/interface';
import { clone } from 'underscore';
import { RougelikeScoreModel } from '../../../db/RougelikeScore';
import { RougelikeTechModel } from '../../../db/RougelikeTech';
import { RougelikeCollectionModel } from '../../../db/RougelikeCollection';
import { RougelikeLayerModel, RougelikeLayerType } from '../../../db/RougelikeLayer';
import { RoleModel } from '../../../db/Role';
import { gameData } from '../../../pubUtils/data';
import { chooseNode, getGame, getInitCharaCard, getLayerNodeReward, getLayerRewardOneData, getMap, getMaxHp, getRandomSpirit, getRougeData, repaireSendScoreReward, updateChalleng, updateMaxHp } from '../../../services/battle/rougeService';
import { checkPreRougeTech, getCurTechData, updateEffectId } from '../../../services/battle/rougeTechService';
import { BattleRecordModel } from '../../../db/BattleRecord';
import { HeroModel } from '../../../db/Hero';
import { ROUGELIKE } from '../../../pubUtils/dicParam';
import { HandleAddCard, addSameTypeCollect, addSingleCollect, formateCharasOrCards } from '../../../services/battle/rougeCollectService';
import { DicRougePassiveCollect } from '../../../pubUtils/dictionary/DicRougePassiveCollect';
import { DicRougeHolyCard } from '../../../pubUtils/dictionary/DicRougeHolyCard';
import { DicRougeSkillCard } from '../../../pubUtils/dictionary/DicRougeSkillCard';
import { DicRougeOptionGroup } from '../../../pubUtils/dictionary/DicRougeOptionGroup';
import { addItems, getRougeTechScoreObject, handleCost } from '../../../services/role/rewardService';
import { getEffectWhenGameStart, getCharaHp, getAddCoin, getNoBossRecoveryHp, getBattleRecoveryNum, getRecoveryExtendHp, getTrainCardDiscount, checkCanChooseSkillCard, checkCanReRandomReward } from '../../../services/battle/rougeEffectService';
import { RougelikeExtendModel } from '../../../db/RougelikeExtend';
import * as util from 'util';
import { DicRougePassiveCard } from '../../../pubUtils/dictionary/DicRougePassiveCard';
export default function (app: Application) {
new HandlerService(app, {});
return new RougeHandler(app);
}
export class RougeHandler {
constructor(private app: Application) {
}
/**
* 获取大界面数据(即进入游戏获取当前是否有进行中的一场数据)
* @param msg
* @param session
* @returns
*/
async getData(msg: {}, session: BackendSession) {
let roleId = session.get('roleId');
let data = await getRougeData(roleId);
return resResult(STATUS.SUCCESS, data);
}
/**
* 获取一场试炼正在进行中的游戏数据
* @param msg
* @param session
*/
async getGame(msg: {}, session: BackendSession) {
let roleId = session.get('roleId');
return resResult(STATUS.SUCCESS, { ...await getGame(roleId) })
}
/**
* 获取初始角色卡
* @param msg
* @param session
* @returns
*/
async getInitCharaCard(msg: { type: number, grade: number }, session: BackendSession) {
let roleId = session.get('roleId');
let sid = session.get('sid');
const { type, grade } = msg;
const dbRecord = await RougelikeRecordModel.findByRoleIdAndStatus(roleId, ROUGE_LIKE_STATUS.SUCCESS)
// 存在一场正在进行中,不能开启新一场
if (dbRecord) return resResult(STATUS.ROUGELIKE_GAME_PLAYING);
let typeGradeData = gameData.rougeTypeGrade.get(type + '_' + grade);
if (!typeGradeData) return resResult(STATUS.NO_TYPE_GRADE);
const { lv = 0 } = await RoleModel.findByRoleId(roleId, 'lv');
if (lv < (typeGradeData.lvLimit || 0)) return resResult(STATUS.LIMIT_LV);
// 开启新一场
const gameCode = genCode(8);
const charaCards = getInitCharaCard() || [];
let handleAddFun = new HandleAddCard(roleId, sid, gameCode);
for (let ele of charaCards) {
handleAddFun.pushChara(ele.id, await getMaxHp(roleId, gameCode, ele.id, type, grade), []);
}
let result = await handleAddFun.save();
await RougelikeRecordModel.updateByGameCode(gameCode, {
$set: {
roleId, grade, type, authorType: 0, curLayer: 0,
maxLayer: typeGradeData.layerCount, status: 0, takeoutReward: [],
},
$inc: { score: 0, coin: 0, techScore: 0 }
})
return resResult(STATUS.SUCCESS, { gameCode, ...result })
}
/**
* 开启一场游戏
* @param msg
* @param session
* @returns
*/
async startGame(msg: { gameCode: string, authorType: number }, session: BackendSession) {
let roleId = session.get('roleId');
let sid = session.get('sid');
const { gameCode, authorType } = msg;
// 检测流派
const authorTypeData = gameData.rougeAuthorType.get(authorType);
if (!authorTypeData) return resResult(STATUS.NO_AUTHOR_TYPE);
let dbRecord = await RougelikeRecordModel.findByGameCode(gameCode)
// 未选角色
if (!dbRecord) return resResult(STATUS.NO_ROUGELIKE_GAME)
// 存在一场正在进行中,不能开启新一场
if (dbRecord.status != ROUGE_LIKE_STATUS.CHOOSECHARA) return resResult(STATUS.ROUGELIKE_GAME_PLAYING);
const { type, grade, curLayer, maxLayer, } = dbRecord
const typeGradeData = gameData.rougeTypeGrade.get(type + '_' + grade);
if (!typeGradeData) return resResult(STATUS.NO_TYPE_GRADE);
const typeGradeByIdData = gameData.rougeTypeGradeById.get(typeGradeData.limitId);
if (typeGradeByIdData) {
const dbExtend = await RougelikeExtendModel.findByRoleIdAndLimitId(roleId, typeGradeData.limitId)
if (!dbExtend) return resResult(STATUS.TYPE_UNLOCK);
}
let nodes = getMap(typeGradeData.layerPlan, typeGradeData.layerCount);
await RougelikeLayerModel.bulkWriteUpdate(nodes.map(cur => { return { ...cur, gameCode, roleId, status: 0 }; }));
await RougelikeRecordModel.updateByGameCode(gameCode, { $set: { authorType, status: ROUGE_LIKE_STATUS.INPROGRESS } });
let { addCoin, cardIds } = await getEffectWhenGameStart(roleId, gameCode, authorType);
dbRecord = await RougelikeRecordModel.updateByGameCode(gameCode, { $inc: { coin: addCoin, coinTotal: addCoin } });
const charas: CommonChara[] = formateCharasOrCards(await RougelikeCharaModel.findByGameCode(gameCode), ROUGE_LIKE_CARD_TYPE.CHARA)?.charas || [];
let handleAddFun = new HandleAddCard(roleId, sid, gameCode);
handleAddFun.pushHolyCards(cardIds);
let result = await handleAddFun.save();
result = await handleAddFun.getHolyEffect();
return resResult(STATUS.SUCCESS, { gameCode, grade, coin: dbRecord.coin, coinTotal: dbRecord.coinTotal, type, authorType, curLayer, maxLayer, nodes, charas: [...charas, ...result.addCharas], cards: result.addCards })
}
/**
* 结束游戏
* @param msg
* @param session
* @returns
*/
async gameEnd(msg: { gameCode: string }, session: BackendSession) {
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let sid = session.get('sid');
const { gameCode } = msg;
let dbRecord = await RougelikeRecordModel.findByGameCode(gameCode)
if (!dbRecord) return resResult(STATUS.NO_ROUGELIKE_GAME);
let { type, grade, status = 0, takeoutReward = [], hasReceivedTakeout = false, curLayer = 0, } = dbRecord;
if (status == ROUGE_LIKE_STATUS.SUCCESS) return resResult(STATUS.ROUGELIKE_GAME_END);
status = ROUGE_LIKE_STATUS.SUCCESS;
const dbLayers = await RougelikeLayerModel.findByGameCode(gameCode);
let takeoutRewardMap = takeoutReward.reduce((map, cur) => { map.set(cur.id, cur.count); return map; }, new Map<number, number>());
let spiritIds: number[] = [];
let addCoin = 0, addScore = 0, addTech = 0, isFirstReward = true;
if (dbLayers.length == 0) isFirstReward = false;
for (const { layer, hasPass = false, layerNodes } of dbLayers) {
if (layer > dbRecord.curLayer) {
isFirstReward = false;
continue;
};
const layerNodeOne = layerNodes.find(cur => cur.isChoose == 1);
let nodeType = layerNodeOne?.type || 0;
const detailCode = layerNodeOne?.detailCode;
//忽略挑战关
if (!hasPass && nodeType != ROUGE_LIKE_NODE_TYPE.CHALLENGE) {
isFirstReward = false;
continue;
}
if (nodeType == ROUGE_LIKE_NODE_TYPE.QUEST_POINT) {
const dbDetail = await RougelikeRecordDetailModel.findByCode(gameCode, detailCode)
nodeType = dbDetail?.questType || 0;
}
const layerReward = getLayerRewardOneData(type, grade, layer, nodeType);
const { takeoutReward = [], coin = 0, score = 0, tech = 0, spiritPlan } = clone(layerReward);
addCoin += coin, addScore += score, addTech += tech;
for (const { id, count } of takeoutReward) takeoutRewardMap.set(id, takeoutRewardMap.get(id) || 0 + count);
spiritIds.push(...getRandomSpirit(spiritPlan));
}
let spiritMap = new Map<number, RewardInter>();
spiritIds.forEach((spiritId) => {
spiritMap.set(spiritId, { id: spiritId, count: (spiritMap.get(spiritId)?.count || 0) + 1 });
})
takeoutReward = [...Array.from(takeoutRewardMap, ([id, count]) => ({ id, count })), ...spiritMap.values()];
if (!dbRecord) return resResult(STATUS.NO_ROUGELIKE_GAME);
dbRecord = await RougelikeRecordModel.updateByGameCode(gameCode, { $set: { status, takeoutReward }, $inc: { score: addScore, coin: addCoin, techScore: addTech } });
let { score = 0, coin = 0, techScore = 0 } = dbRecord;
let dbScore = await RougelikeScoreModel.incScore(roleId, score);
let goods = await addItems(roleId, roleName, sid, [getRougeTechScoreObject(techScore)], ITEM_CHANGE_REASON.ROUGE_TECH_SCORE);
let firstReward = [];
if (isFirstReward) {
const typeGradeData = gameData.rougeTypeGrade.get(type + '_' + grade);
if (!typeGradeData || !typeGradeData.id) return resResult(STATUS.NO_TYPE_GRADE);
let dbExtend = await RougelikeExtendModel.findByRoleIdAndLimitId(roleId, typeGradeData.id);
if ((dbExtend?.limitId || 0) != typeGradeData.id) {
firstReward = await addItems(roleId, roleName, sid, typeGradeData?.firstReward || [], ITEM_CHANGE_REASON.ROUGE_FIRST_REWARD);
await RougelikeExtendModel.update(roleId, typeGradeData.id, firstReward, gameCode);
}
}
return resResult(STATUS.SUCCESS, {
gameCode, goods, score, techScore, coin, hasReceivedTakeout, firstReward,
takeoutReward, weeklyScore: dbScore?.score || 0, takeoutRewardCnt: dbScore?.takeoutRewardCnt || 0
});
}
/**
* 选择外带奖励
* @param msg
* @param session
*/
async takeoutReward(msg: { gameCode: string }, session: BackendSession) {
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let sid = session.get('sid');
const { gameCode } = msg;
let dbRecord = await RougelikeRecordModel.findByGameCode(gameCode)
if (!dbRecord) return resResult(STATUS.NO_ROUGELIKE_GAME);
let { takeoutReward, hasReceivedTakeout } = dbRecord;
if (hasReceivedTakeout) return resResult(STATUS.ROUGELIKE_TAKEOUT_HAS_RECEIVED);
let dbScore = await RougelikeScoreModel.receiveTakeoutReward(roleId, ROUGELIKE.TAKEOUT_REWARD_CNT);
if (!dbScore) return resResult(STATUS.ROUGELIKE_TAKEOUT_CNT_NOT_ENOUGH);
dbRecord = await RougelikeRecordModel.takeout(gameCode);
let goods = await addItems(roleId, roleName, sid, takeoutReward, ITEM_CHANGE_REASON.ROUGE_TAKE_OUT_REWARD)
return resResult(STATUS.SUCCESS, { gameCode, hasReceivedTakeout: dbRecord?.hasReceivedTakeout || false, takeoutRewardCnt: dbScore?.takeoutRewardCnt || 0, goods });
}
/**
* 选择关卡节点
* @param msg
* @param session
*/
async chooseNode(msg: { gameCode: string, layer: number, detailCode: string }, session: BackendSession) {
let roleId = session.get('roleId');
const { gameCode, layer, detailCode } = msg;
const dbRecord = await RougelikeRecordModel.findByGameCode(gameCode)
if (!dbRecord) return resResult(STATUS.NO_ROUGELIKE_GAME);
if (dbRecord.status != ROUGE_LIKE_STATUS.INPROGRESS) return resResult(STATUS.ROUGELIKE_GAME_END);
const { curLayer, maxLayer, type, grade } = dbRecord;
if (layer < curLayer || layer > maxLayer) return resResult(STATUS.NODE_NO_CHOOSE);
let dbCurLayer = {} as RougelikeLayerType, dbPreLayer = {} as RougelikeLayerType;
let dbLayerNodes = await RougelikeLayerModel.findByGameCodeAndLayers(gameCode, [layer, layer - 1]);
if (!dbLayerNodes) return resResult(STATUS.NODE_NO_CHOOSE);
for (let val of dbLayerNodes) {
if (val.layer == layer) {
if (val.hasPass) return resResult(STATUS.NODE_NO_CHOOSE);//当前关完成
dbCurLayer = val;
}
// 注意过滤挑战点
if ((val.layer || 0) == layer - 1 && layer - 1 > 0) {
let dbDetail = await RougelikeRecordDetailModel.findByGameCodeAndLayer(gameCode, layer - 1);
if (!val.hasPass && (!dbDetail || dbDetail.nodeType != ROUGE_LIKE_NODE_TYPE.CHALLENGE)) return resResult(STATUS.NODE_NO_CHOOSE);//前一关未完成
dbPreLayer = val;
}
}
let dbIsChoose = dbCurLayer.layerNodes.find(cur => cur.isChoose == ROUGE_LIKE_CHOOSE_REWARD.CHOOSE);
if (dbIsChoose && dbIsChoose.detailCode != detailCode) return resResult(STATUS.NODE_NO_CHOOSE); //该层已经选择过一关卡,不能再次选择其他关卡
let dbCurLayerChooseNode: layerNode = dbCurLayer.layerNodes.find(cur => cur.detailCode == detailCode);
if (!dbCurLayerChooseNode) return resResult(STATUS.NODE_NO_CHOOSE);
if (dbPreLayer && Object.keys(dbPreLayer).length > 0) {
let dbPreLayerChooseNode = dbPreLayer.layerNodes.find(cur => cur.isChoose != 0);
if (dbCurLayerChooseNode.preNodeIndexs.indexOf(dbPreLayerChooseNode.index) == -1) return resResult(STATUS.NODE_NO_CHOOSE);
}
return resResult(STATUS.SUCCESS, { detailCode, layer, curNode: await chooseNode(dbRecord, dbCurLayerChooseNode, layer) })
}
// 挑战关卡
async checkBattle(msg: { gameCode: string, detailCode: string, warId: number, charaCodes: string[] }, session: BackendSession) {
let roleId = session.get('roleId');
let roleName = session.get('roleName');
const { gameCode, detailCode, warId, charaCodes } = msg;
const dbRecord = await RougelikeRecordModel.findByGameCode(gameCode)
if (!dbRecord) return resResult(STATUS.NO_ROUGELIKE_GAME);
if (dbRecord.status != ROUGE_LIKE_STATUS.INPROGRESS) return resResult(STATUS.ROUGELIKE_GAME_END);
let dbDetail = await RougelikeRecordDetailModel.findByCode(gameCode, detailCode);
if (!dbDetail) return resResult(STATUS.REWARD_NO_CHOOSE);
let { status = 0, rewards, layer, nodeType, warId: detailWarId = 0 } = dbDetail;
if (status != 0 || warId != detailWarId) return resResult(STATUS.WAR_NO_CHOOSE);
let dicWar = gameData.war.get(detailWarId);
if (!dicWar) return resResult(STATUS.DIC_DATA_NOT_FOUND);
const battleCode = genCode(8); // 关卡唯一值
const dbCharas = await RougelikeCharaModel.findByCodes(gameCode, charaCodes);
if (!dbCharas || dbCharas.length == 0) return resResult(STATUS.REWARD_NO_CHOOSE);
await BattleRecordModel.updateBattleRecordByCode(battleCode, {
$set: {
roleId, roleName, battleId: warId, status: 0, warName: dicWar.gk_name, warType: dicWar.warType,
record: {
rougeOriginal: dbCharas.map(cur => {
const { charaId, cards = [], hp = 0, ap = 0, shield = 0, roundSkill = 0, apSkill = 0 } = cur;
return { charaId, cards, hp, ap, roundSkill, apSkill }
})
}
}
}, true);
return resResult(STATUS.SUCCESS, { gameCode, battleCode });
}
/**
* 结束关卡
* @param msg
* @param session
* @returns
*/
async battleEnd(msg: { gameCode: string, detailCode: string, battleCode: string, warId: number, status: number, round: number, rougeDamage: RougeDamageInter[], isAp: boolean, isRound: boolean }, session: BackendSession) {
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let sid = session.get('sid');
let { gameCode, detailCode, battleCode, warId, status, round, rougeDamage, isAp, isRound } = msg;
let dbDetail = await RougelikeRecordDetailModel.findByCode(gameCode, detailCode);
if (!dbDetail || (dbDetail.warId || 0) != warId || warId == 0 || (dbDetail.status || 0) != 0) return resResult(STATUS.WAR_NO_CHOOSE);
let { layer, nodeType, questType = 0 } = dbDetail;
const dbRecord = await RougelikeRecordModel.findByGameCode(gameCode)
if (!dbRecord) return resResult(STATUS.NO_ROUGELIKE_GAME);
if (dbRecord.status != ROUGE_LIKE_STATUS.INPROGRESS) return resResult(STATUS.ROUGELIKE_GAME_END);
const dbCharas = await RougelikeCharaModel.findByCodes(gameCode, rougeDamage.map(cur => { return cur.charaCode }));
if (!dbCharas || dbCharas.length == 0 || dbCharas.length != rougeDamage.length) return resResult(STATUS.REWARD_NO_CHOOSE);
await BattleRecordModel.findOneAndUpdate({ battleCode }, {
$set: { status, 'record.round': round, 'record.rougeDamage': rougeDamage, }
}, { new: true, upsert: true }).lean(true);
await updateChalleng(dbRecord, roleId, sid, gameCode, layer, rougeDamage, isAp, isRound);
const dbCharaMap = dbCharas.reduce((result, cur) => { result.set(cur.charaCode, { ...cur }); return result; }, new Map<string, RougelikeCharaType>());
let updateCharas: RougelikeCharaPara[] = [], charas: CommonChara[] = [];
let recoveryHp = false;
if (status == 0 && nodeType != ROUGE_LIKE_NODE_TYPE.BOSS) {
recoveryHp = await getNoBossRecoveryHp(roleId, gameCode);
if (recoveryHp) status = 1;
}
let hpRatio = 0;
if (status == 1) {
hpRatio = await getCharaHp(roleId, gameCode);
}
let recoveryNum = await getBattleRecoveryNum(roleId, gameCode);
for (let { charaCode, hp, ap, shield } of rougeDamage) {
const chara = dbCharaMap.get(charaCode);
if (!chara) return resResult(STATUS.BATTLE_ABNORMAL)
if (chara.maxHp < hp) hp = chara.maxHp;
if (recoveryHp) hp = chara.maxHp;
if (hpRatio > 0) hp = Math.min(Math.floor(hp * (1 + hpRatio / 100)), chara.maxHp);
if (recoveryNum-- > 0 && hp == 0) hp = chara.maxHp;
charas.push({ charaCode, charaId: chara.charaId, seqId: chara.seqId, cards: chara.cards, hp, maxHp: chara.maxHp, ap, shield, apSkill: chara.apSkill, roundSkill: chara.roundSkill })
updateCharas.push({ gameCode, charaCode, hp, ap, shield });
}
let incCoin = 0;
if (status == 1) {
let { coinRatio, coinAdd } = await getAddCoin(roleId, gameCode, nodeType);
let newNodeType = nodeType;
if (questType > 0) newNodeType = questType;
const layerReward = getLayerRewardOneData(dbRecord.type, dbRecord.grade, layer, newNodeType);
incCoin = Math.floor((layerReward.coin || 0) * (1 + coinRatio / 100) + coinAdd);
await RougelikeRecordModel.updateByGameCode(gameCode, { $inc: { coin: incCoin, coinTotal: incCoin } });
}
// let coinReward = rewards.find(cur => cur.rewardType == 0);
// if (coinReward) coinReward.chooseNum = Math.floor(coinReward.chooseNum * (1 + coinRatio / 100) + coinAdd);
// if (coinRatio != 0 || coinAdd != 0) {
// await RougelikeRecordDetailModel.findOneAndUpdate({ gameCode, detailCode, 'rewards.rewardType': 0 }, { 'rewards.$.chooseNum': coinReward.chooseNum, }, { new: true, upsert: true }).lean(true);
// }
await RougelikeCharaModel.bulkWriteUpdate(updateCharas);
await RougelikeRecordDetailModel.updateByCode(gameCode, detailCode, { $set: { status } })
return resResult(STATUS.SUCCESS, { status, gameCode, detailCode, charas, incCoin });
}
// 重置
async reRandomReward(msg: { gameCode: string, detailCode: string, rewardType: number }, session: BackendSession) {
const roleId: string = session.get('roleId');
const { gameCode, detailCode, rewardType } = msg;
// 检查数量
let { canReRandom, costCoin } = await checkCanReRandomReward(roleId, gameCode, rewardType);
if (!canReRandom) return resResult(STATUS.ROUGE_TECH_NOT_UNLOCKED);
const dbRecord = await RougelikeRecordModel.findByGameCode(gameCode)
if (!dbRecord) return resResult(STATUS.NO_ROUGELIKE_GAME);
if (dbRecord.status != ROUGE_LIKE_STATUS.INPROGRESS) return resResult(STATUS.ROUGELIKE_GAME_END);
let dbDetail = await RougelikeRecordDetailModel.findByCode(gameCode, detailCode);
if (!dbDetail) return resResult(STATUS.REWARD_NO_CHOOSE);
if (dbDetail.reRandRewardCnt > 0) return resResult(STATUS.ROUGE_RE_RANDOM_CNT_OVER);
const typeGradeData = gameData.rougeTypeGrade.get(dbRecord.type + '_' + dbRecord.grade);
const nodeData = gameData.rougeNode.get(dbDetail.nodeId);
if (!typeGradeData || !nodeData) return resResult(STATUS.DIC_DATA_NOT_FOUND);
const layerPlanData = gameData.rougeLayerPlan.get(typeGradeData.layerPlan + '_' + dbDetail.layer);
if (!layerPlanData) return resResult(STATUS.DIC_DATA_NOT_FOUND);
let costResult = await RougelikeRecordModel.costCoin(gameCode, costCoin);
if (!costResult) return resResult(STATUS.COIN_NOT_ENOUGH);
let replaceReward = await getLayerNodeReward(roleId, gameCode, dbRecord.authorType, dbDetail.nodeId, layerPlanData.rewardPlan, dbDetail.layer);
let { rewards } = dbDetail;
let newRewards = [...rewards.filter(reward => reward.rewardType != rewardType), ...replaceReward.rewards.filter(reward => reward.rewardType == rewardType)].sort((a, b) => a.groupIndex - b.groupIndex);
dbDetail = await RougelikeRecordDetailModel.updateByCode(gameCode, detailCode, { $set: { rewards: newRewards }, $inc: { reRandRewardCnt: 1 } });
return resResult(STATUS.SUCCESS, { rewards: dbDetail.rewards, reRandRewardCnt: dbDetail.reRandRewardCnt });
}
/**
* 选择奖励
* @param msg
* @param session
* @returns
*/
async chooseReward(msg: { gameCode: string, detailCode: string, groupIndex: number, optionIndexs: number[] }, session: BackendSession) {
let roleId = session.get('roleId');
let sid = session.get('sid');
const { gameCode, detailCode, groupIndex, optionIndexs } = msg;
let dbDetail = await RougelikeRecordDetailModel.findByCode(gameCode, detailCode);
if (!dbDetail) return resResult(STATUS.REWARD_NO_CHOOSE);
let { status, rewards, layer, nodeType, warId = 0, challenge } = dbDetail;
const dbRecord = await RougelikeRecordModel.findByGameCode(gameCode)
if (!dbRecord) return resResult(STATUS.NO_ROUGELIKE_GAME);
if (dbRecord.status != ROUGE_LIKE_STATUS.INPROGRESS) return resResult(STATUS.ROUGELIKE_GAME_END);
// 检测有关卡的是否挑战成功
if (warId != 0 && status != 1) return resResult(STATUS.REWARD_NO_CHOOSE);
if (!rewards || rewards.length == 0) return resResult(STATUS.REWARD_NO_CHOOSE);
let { rewardType, options, groupStatus, chooseNum } = rewards.find((obj) => obj.groupIndex == groupIndex);
if (groupStatus == ROUGE_LIKE_CHOOSE_REWARD.CHOOSE) return resResult(STATUS.REWARD_NO_CHOOSE);
let handleAddFun = new HandleAddCard(roleId, sid, gameCode, dbDetail);
let incCoin = 0, redCoin = 0;
// //处理下试炼币
// if (rewardType == 0) {
// incCoin = chooseNum;
// groupStatus = ROUGE_LIKE_CHOOSE_REWARD.CHOOSE;
// const result = await RougelikeRecordDetailModel.findOneAndUpdate({ gameCode, detailCode, 'rewards.groupIndex': groupIndex }, { 'rewards.$.groupStatus': groupStatus, }, { new: true, upsert: true }).lean(true);
// if (result.rewards.find((obj) => obj.groupStatus != ROUGE_LIKE_CHOOSE_REWARD.CHOOSE) == undefined) {
// await RougelikeLayerModel.updateByGameCode(gameCode, layer, { $set: { hasPass: true } })
// }
// await RougelikeRecordModel.updateByGameCode(gameCode, { $inc: { coin: incCoin, coinTotal: incCoin } })
// return resResult(STATUS.SUCCESS, { addCharas: await updateMaxHp(roleId, gameCode, dbRecord.type, dbRecord.grade), addCards: [], incCoin, redCoin });
// }
// 特性卡可以选多次
let passiveChooseCount = 0;
if (rewardType == ROUGE_LIKE_CARD_TYPE.PASSIVE || rewardType == ROUGE_LIKE_CARD_TYPE.CHARA) {
passiveChooseCount = options.reduce((accumulator, obj) => {
if (obj.optionStatus === ROUGE_LIKE_CHOOSE_REWARD.CHOOSE) return accumulator + 1;
return accumulator;
}, 0);
if (chooseNum - passiveChooseCount < optionIndexs.length) return resResult(STATUS.REWARD_NO_CHOOSE);
}
if (optionIndexs.length > chooseNum) return resResult(STATUS.REWARD_NO_CHOOSE);
let tempOptions: RewardOption[] = options.filter(opt => optionIndexs.includes(opt.optionIndex));
if (tempOptions.length > chooseNum) return resResult(STATUS.REWARD_NO_CHOOSE);
for (let { rewardId, passiveCardIds, optionStatus, optionIndex } of tempOptions) {
if (optionStatus != 0) return resResult(STATUS.REWARD_NO_CHOOSE);
let cardCode = genCode(8);
if (rewardType == ROUGE_LIKE_CARD_TYPE.CHARA) {
// 更新角色卡
handleAddFun.pushChara(rewardId, await getMaxHp(roleId, gameCode, rewardId, dbRecord.type, dbRecord.grade), passiveCardIds || []);
//休整点 消耗
if (nodeType == ROUGE_LIKE_NODE_TYPE.REST_POINT) {
let charaData = gameData.rougeChara.get(rewardId);
if (!charaData) return;
redCoin += charaData.recruitConsume || 0;
}
} else {
// 更新特性卡or圣物
handleAddFun.pushCard(rewardId, rewardType);
}
optionStatus = ROUGE_LIKE_CHOOSE_REWARD.CHOOSE;
options.forEach((ele) => { if (ele.optionIndex == optionIndex) ele.optionStatus = optionStatus; });
}
if ((dbRecord.coin || 0) < redCoin) return resResult(STATUS.COIN_NOT_ENOUGH);
if (redCoin > 0) await RougelikeRecordModel.updateByGameCode(gameCode, { $inc: { coin: -redCoin } });
//处理特性卡组
groupStatus = ROUGE_LIKE_CHOOSE_REWARD.CHOOSE;
if (rewardType == ROUGE_LIKE_CARD_TYPE.PASSIVE || rewardType == ROUGE_LIKE_CARD_TYPE.CHARA) {
groupStatus = ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE;
if (chooseNum - passiveChooseCount == optionIndexs.length) {
groupStatus = ROUGE_LIKE_CHOOSE_REWARD.CHOOSE;
await updateChalleng(dbRecord, roleId, sid, gameCode, layer, []); // 更新挑战进度
}
}
rewards.forEach((ele) => { if (ele.rewardType == rewardType) ele.groupStatus = groupStatus; });
// 挑战领奖
let dbPara = {};
if (rewards.find((obj) => obj.groupStatus != ROUGE_LIKE_CHOOSE_REWARD.CHOOSE) == undefined) {
if (nodeType == ROUGE_LIKE_NODE_TYPE.CHALLENGE) {
challenge.status = 3;
dbPara['challenge'] = challenge;
}
await RougelikeLayerModel.updateByGameCode(gameCode, layer, { $set: { hasPass: true } })
}
await RougelikeRecordDetailModel.updateRewardByGroupIndex(gameCode, detailCode, groupIndex, groupStatus, options, { $set: dbPara });
let addResult = await handleAddFun.save();
addResult = await handleAddFun.getHolyEffect();
return resResult(STATUS.SUCCESS, { ...addResult, incCoin, redCoin });
}
/**
* 商店购买
* @param msg
* @param session
* @returns
*/
async shopBuy(msg: { gameCode: string, detailCode: string, optionIndex: number }, session: BackendSession) {
let roleId = session.get('roleId');
let sid = session.get('sid');
let { gameCode, detailCode, optionIndex } = msg;
let dbDetail = await RougelikeRecordDetailModel.findByCode(gameCode, detailCode);
if (!dbDetail) return resResult(STATUS.SHOP_NO_BUY);
let { status = 0, shops, layer, nodeType } = dbDetail;
if (status == 1 || !shops || shops.length == 0) return resResult(STATUS.SHOP_NO_BUY);
let shop = shops.find((obj) => obj.optionIndex == optionIndex);
if (!shop || shop.optionStatus != ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE) return resResult(STATUS.SHOP_NO_BUY);
let dbRecord = await RougelikeRecordModel.findByGameCode(gameCode);
if (!dbRecord || (dbRecord.coin || 0) < shop.price) return resResult(STATUS.COIN_NOT_ENOUGH);
shop.optionStatus = ROUGE_LIKE_CHOOSE_REWARD.CHOOSE;
await RougelikeRecordDetailModel.updateShopByCode(gameCode, detailCode, optionIndex, shop.optionStatus);
await RougelikeRecordModel.updateByGameCode(gameCode, { $set: { coin: (dbRecord.coin || 0) - shop.price } });
let handleAddFun = new HandleAddCard(roleId, sid, gameCode, dbDetail);
handleAddFun.pushCard(shop.rewardId, shop.rewardType);
let result = await handleAddFun.save();
result = await handleAddFun.getHolyEffect();
return resResult(STATUS.SUCCESS, { curShop: shop, ...result, redCoin: -shop.price });
}
/**
* 结束这一节点
* @param msg
* @param session
* @returns
*/
async nodeEnd(msg: { gameCode: string, detailCode: string }, session: BackendSession) {
let roleId = session.get('roleId');
const { gameCode, detailCode } = msg;
let dbDetail = await RougelikeRecordDetailModel.findByCode(gameCode, detailCode);
if (!dbDetail) return resResult(STATUS.NO_EXIT_NODE);
let { layer, nodeType, status = 0, shops, warId = 0 } = dbDetail;
if ((warId != 0 && status != 1)) {
//检测关卡是否挑战成功
return resResult(STATUS.NODE_NO_END)
}
status = 1;
await RougelikeRecordDetailModel.updateByCode(gameCode, detailCode, { $set: { status } });
if (nodeType != ROUGE_LIKE_NODE_TYPE.CHALLENGE) {
await RougelikeLayerModel.updateByGameCode(gameCode, layer, { $set: { hasPass: true } });
}
return resResult(STATUS.SUCCESS, { gameCode, detailCode, status, ...await getGame(roleId) })
}
/**
* 问号点选择题
* @param msg
* @param session
* @returns
*/
async chooseOption(msg: { gameCode: string, detailCode: string, eventOptions: number[] }, session: BackendSession) {
let roleId = session.get('roleId');
let sid = session.get('sid');
const { gameCode, detailCode, eventOptions } = msg;
let dbDetail = await RougelikeRecordDetailModel.findByCode(gameCode, detailCode);
if (!dbDetail) return resResult(STATUS.NODE_NO_CHOOSE);
let { layer, nodeType, status = 0, question = {} as Quest } = dbDetail;
if (status == 1) return resResult(STATUS.NODE_NO_CHOOSE);
let checkAfterGroup = 0, optionGroupIds: number[] = [];
let handleAddFun = new HandleAddCard(roleId, sid, gameCode, dbDetail);
for (let [index, id] of eventOptions.entries()) {
const rougeEventOptionData = gameData.rougeEventOption.get(id);
if (!rougeEventOptionData) return resResult(STATUS.NODE_NO_CHOOSE);
const { randomEventId, optionGroup, afterGroup, holyCardPlan } = rougeEventOptionData;
if (randomEventId != (question.randomEventId || 0)) return resResult(STATUS.NODE_NO_CHOOSE);
if (index != 0 && checkAfterGroup != optionGroup) return resResult(STATUS.NODE_NO_CHOOSE);
if (!optionGroupIds.includes(optionGroup)) optionGroupIds.push(optionGroup);
if (!question.EventOptions) question.EventOptions = [];
question.EventOptions.push(id);
checkAfterGroup = afterGroup;
let cardId = 0;
const rougeHolyCardPlanData = gameData.rougeHolyCardPlan.get(holyCardPlan);
if (!rougeHolyCardPlanData || rougeHolyCardPlanData.length == 0) continue;
if (rougeHolyCardPlanData.length == 1) cardId = rougeHolyCardPlanData[0].cardId;
else cardId = getRandEelmWithWeight(rougeHolyCardPlanData).dic.cardId;
handleAddFun.pushHolyCard(cardId);
}
status = 1;
await RougelikeRecordDetailModel.updateByCode(gameCode, detailCode, { $set: { question, status } })
await RougelikeLayerModel.updateByGameCode(gameCode, layer, { $set: { hasPass: true } })
let result = await handleAddFun.save();
result = await handleAddFun.getHolyEffect();
await addSameTypeCollect(roleId, sid, gameCode, COLLECTION_TYPE.EVENT, optionGroupIds);
return resResult(STATUS.SUCCESS, { ...result })
}
/**
* 休整点恢复
* @param msg
* @param session
* @returns
*/
async recovery(msg: { gameCode: string, detailCode: string }, session: BackendSession) {
let roleId = session.get('roleId');
const { gameCode, detailCode } = msg;
const dbRecord = await RougelikeRecordModel.findByGameCode(gameCode)
if (!dbRecord) return resResult(STATUS.NO_ROUGELIKE_GAME);
if (dbRecord.status != ROUGE_LIKE_STATUS.INPROGRESS) return resResult(STATUS.ROUGELIKE_GAME_END);
let dbDetail = await RougelikeRecordDetailModel.findByCode(gameCode, detailCode);
if (!dbDetail) return resResult(STATUS.NODE_NO_CHOOSE);
let { restPoints = [], nodeType, status, rewards } = dbDetail;
if (status == 1 || nodeType != ROUGE_LIKE_NODE_TYPE.REST_POINT) return resResult(STATUS.NODE_NO_CHOOSE);
let restPoint = restPoints.find(cur => cur.restType == REST_POINT_TYPE.RECOVERY) || new RestPoint();
if (restPoint.recoveryCnt && restPoint.recoveryCnt > 0) return resResult(STATUS.NO_TIME_RECOVERY);
restPoint.recoveryCnt = 1;
restPoint.restType = REST_POINT_TYPE.RECOVERY;
restPoint.recoveryCharas = [];
let dbCharas = await RougelikeCharaModel.findByGameCode(gameCode);
let updateCharas: RougelikeCharaPara[] = [];
let hpRatio = await getRecoveryExtendHp(roleId, gameCode);
for (let { gameCode, charaCode, charaId, cards, hp, maxHp = 0, ap, shield, roundSkill, apSkill } of dbCharas) {
let beforeHp = hp;
hp = Math.floor(Math.min(hp + maxHp * ROUGELIKE.RECOVERY_RATIO / 100 + hp * hpRatio / 100, maxHp));
updateCharas.push({ gameCode, charaCode, hp });
restPoint.recoveryCharas.push({ charaCode, charaId, beforeHp, afterHp: hp });
}
restPoints.push({ restType: restPoint.restType, recoveryCnt: restPoint.recoveryCnt, recoveryCharas: restPoint.recoveryCharas });
await RougelikeRecordDetailModel.updateByCode(gameCode, detailCode, { $set: { restPoints } });
await RougelikeCharaModel.bulkWriteUpdate(updateCharas);
const charas: CommonChara[] = formateCharasOrCards(dbCharas, ROUGE_LIKE_CARD_TYPE.CHARA)?.charas || [];
return resResult(STATUS.SUCCESS, { restPoints, charas, reward: { rewards } })
}
/**
* 休整点强化
* @param msg
* @param session
*/
async trainCard(msg: { gameCode: string, detailCode: string, cardCode: string }, session: BackendSession) {
let roleId = session.get('roleId');
const { gameCode, detailCode, cardCode } = msg;
const dbRecord = await RougelikeRecordModel.findByGameCode(gameCode)
if (!dbRecord) return resResult(STATUS.NO_ROUGELIKE_GAME);
if (dbRecord.status != ROUGE_LIKE_STATUS.INPROGRESS) return resResult(STATUS.ROUGELIKE_GAME_END);
let dbDetail = await RougelikeRecordDetailModel.findByCode(gameCode, detailCode);
if (!dbDetail) return resResult(STATUS.NODE_NO_CHOOSE);
let { layer, nodeType, status = 0, question, restPoints = [], rewards } = dbDetail;
if (status == 1 || nodeType != ROUGE_LIKE_NODE_TYPE.REST_POINT) return resResult(STATUS.NODE_NO_CHOOSE);
let dbCard = await RougelikeCardModel.findByCode(gameCode, cardCode);
if (!dbCard) return resResult(STATUS.NO_CARD);
let { type, cardId, charaId, lv = 0 } = dbCard;
const passiveCardData = gameData.rougePassiveCard.get(cardId);
if (!passiveCardData) return resResult(STATUS.NO_CARD);
const passiveCardByGroupData = gameData.rougePassiveCardByGroup.get(passiveCardData.group || 0);
if (passiveCardByGroupData.length == 0 || passiveCardByGroupData.length == 1) return resResult(STATUS.HIGH_LV);
let passiveCardDataMap = passiveCardByGroupData.reduce((result, cur) => { result.set(cur.lv, cur); return result; }, new Map<number, DicRougePassiveCard>());
if (!passiveCardDataMap.has(lv + 1)) return resResult(STATUS.HIGH_LV);
const strengthConsume = passiveCardData.strengthConsume || 0;
const { lv: cardLv, id } = passiveCardDataMap.get(lv + 1);
if (lv == cardLv) return resResult(STATUS.HIGH_LV);
let realConsume = Math.floor(strengthConsume * await getTrainCardDiscount(roleId, gameCode) / 100);
if ((dbRecord.coin || 0) < realConsume) return (STATUS.COIN_NOT_ENOUGH);
let restPoint = restPoints.find(cur => cur.restType == REST_POINT_TYPE.TRAIN) || new RestPoint();
restPoint.restType = REST_POINT_TYPE.TRAIN;
if (!restPoint.trainCardCnt) restPoint.trainCardCnt = 0;
restPoint.trainCardCnt += 1;
if (!restPoint.trainCards) restPoint.trainCards = [];
restPoint.trainCards.push({ cardCode, cardId: id, beforeLv: lv, afterLv: lv + 1 });
if (restPoints.find(cur => cur.restType == restPoint.restType) == undefined) {
restPoints.push({ restType: restPoint.restType, trainCardCnt: restPoint.trainCardCnt, trainCards: restPoint.trainCards })
}
else restPoints.forEach(obj => {
if (obj.restType == restPoint.restType) {
obj.trainCardCnt = restPoint.trainCardCnt;
obj.trainCards = restPoint.trainCards;
}
})
await RougelikeRecordModel.updateByGameCode(gameCode, { $inc: { coin: -realConsume } });
await RougelikeRecordDetailModel.updateByCode(gameCode, detailCode, { $set: { restPoints } });
const newDbCard = await RougelikeCardModel.updateByCode(gameCode, cardCode, { $set: { cardId: id }, $inc: { lv: 1 } });
const cards: CommonCard[] = formateCharasOrCards([newDbCard], ROUGE_LIKE_CARD_TYPE.PASSIVE)?.cards || [];
return resResult(STATUS.SUCCESS, { restPoints, cards, reward: { rewards }, redCoin: -realConsume, })
}
/**
* 选择一张技能卡
* @param msg
* @returns
*/
async chooseSkillCard(msg: { gameCode: string, charaCode: string, skillType: number, id: number }, session: BackendSession) {
let roleId: string = session.get('roleId');
let sid: string = session.get('sid');
const { gameCode, charaCode, skillType, id } = msg;
let dbChara = await RougelikeCharaModel.findByCode(gameCode, charaCode);
if (!dbChara) return resResult(STATUS.NO_CARD);
if (id > 0) {
const dicSkillCard = gameData.rougeSkillCard.get(id);
if (!dicSkillCard) return resResult(STATUS.DIC_DATA_NOT_FOUND);
if (dicSkillCard.skillType != skillType) return resResult(STATUS.WRONG_PARMS);
// 检查数量
if (!await checkCanChooseSkillCard(roleId, gameCode, id, dbChara.cards))
return resResult(STATUS.ROUGE_PASSIVE_CARD_NOT_ENOUGH);
}
let chara = await RougelikeCharaModel.putOnOrOffSkillCard(gameCode, charaCode, skillType, id);
if (!dbChara) return resResult(STATUS.NO_CARD);
// 更新图鉴
await addSingleCollect(roleId, sid, gameCode, COLLECTION_TYPE.SKILL_CARD, id);
return resResult(STATUS.SUCCESS, {
curChara: new CommonChara(chara)
})
}
/**
* 安装或者卸下特性卡
* @param msg
* @param session
*/
async putOnOrOffCard(msg: { gameCode: string, charaCode: string, cards: SlotCard[] }, session: BackendSession) {
let roleId: string = session.get('roleId');
let { gameCode, charaCode, cards } = msg;
// 获取角色卡db数据
let dbChara = await RougelikeCharaModel.findByCode(gameCode, charaCode);
if (!dbChara) return resResult(STATUS.NO_CARD);
if (!dbChara.cards || dbChara.cards.length == 0) return resResult(STATUS.SLOT_UNLOCK);
let dbCharaCardsMap = dbChara.cards.reduce((result, cur) => { result.set(cur.index, cur); return result; }, new Map<number, Card>());
// 获取需要安装、卸下的特性卡db数据
let cardCodes: string[] = [];
cards.forEach((ele) => { cardCodes.push(ele.cardCode); });
dbChara.cards.forEach((ele) => { cardCodes.push(ele.cardCode); })
let dbCards: RougelikeCardType[] = await RougelikeCardModel.findByGameCodeAndCardCodes(gameCode, cardCodes);
if (dbCards.length == 0) return resResult(STATUS.NO_CARD);
let dbCardsMap = dbCards.reduce((result, cur) => { result.set(cur.cardCode, cur); return result; }, new Map<string, RougelikeCardType>());
let newCardsMap = new Map<string, RougelikeCardType>();
for (let { index, cardCode } of cards) {
// 检测卡槽解锁
let slot = dbCharaCardsMap.get(index)
if (!slot) return resResult(STATUS.SLOT_UNLOCK);
//处理旧的cardCode
let oldSotCardCode = clone(slot.cardCode);
let updateObj = dbCardsMap.get(oldSotCardCode);
if (updateObj) {
updateObj.charaId = 0;
dbCardsMap.set(oldSotCardCode, updateObj);
newCardsMap.set(oldSotCardCode, updateObj);
}
//处理新的cardCode安装
let update = dbCardsMap.get(cardCode);
dbCharaCardsMap.set(index, { index, cardCode: cardCode, cardId: update?.cardId || 0 });
if (update) {
if (update.type != ROUGE_LIKE_CARD_TYPE.PASSIVE) return resResult(STATUS.NO_PASSIVE);
update.charaId = dbChara.charaId;
dbCardsMap.set(cardCode, update);
newCardsMap.set(cardCode, update);
}
}
// 如果卸下之后技能卡需要的被动卡不够,需要把技能卡卸下
let newCards = Array.from(dbCharaCardsMap.values());
let { apSkill, roundSkill } = dbChara;
if (apSkill > 0 && !await checkCanChooseSkillCard(roleId, gameCode, apSkill, newCards)) apSkill = 0;
if (roundSkill > 0 && !await checkCanChooseSkillCard(roleId, gameCode, roundSkill, newCards)) roundSkill = 0;
//更新角色卡db, 特性卡db
let newChara = await RougelikeCharaModel.updateByCode(gameCode, charaCode, { $set: { cards: newCards, apSkill, roundSkill } });
await RougelikeCardModel.bulkWriteUpdate(Array.from(newCardsMap.values()).map(obj => ({ gameCode, cardCode: obj.cardCode, charaId: obj.charaId })))
let curCards = Array.from(dbCardsMap.values()).map(obj => ({ cardCode: obj.cardCode, type: obj.type, charaId: obj.charaId, lv: obj.lv }));
return resResult(STATUS.SUCCESS, { curCards, curChara: new CommonChara(newChara) })
}
async exchangeChara(msg: { gameCode: string, oldCharaCode: string, newCharaCode: string }, session: BackendSession) {
let roleId: string = session.get('roleId');
const { gameCode, oldCharaCode, newCharaCode } = msg;
const result = await RougelikeCharaModel.findByCodes(gameCode, [oldCharaCode, newCharaCode]);
if (result.length != 2) return (STATUS.NO_CARD);
let oldChara = {} as RougelikeCharaType, newChara = {} as RougelikeCharaType;
for (let val of result) {
if (val.charaCode == oldCharaCode) oldChara = val;
if (val.charaCode == newCharaCode) newChara = val;
}
let temp = clone(newChara.seqId);
newChara.seqId = clone(oldChara.seqId);
oldChara.seqId = temp;
// 更新角色卡
await RougelikeCharaModel.bulkWriteUpdate([oldChara, newChara]);
let charas = formateCharasOrCards([oldChara, newChara], ROUGE_LIKE_CARD_TYPE.CHARA).charas;
// // 处理新卡
// let { charaCode, charaId, maxHp, seqId } = newChara;
// newChara = clone(oldChara);
// newChara.charaCode = charaCode;
// newChara.charaId = charaId;
// newChara.maxHp = maxHp;
// let cardCodes = [];
// let updateArr: RougelikeCardPara[] = [];
// for (let val of newChara.cards) {
// cardCodes.push(val.cardCode);
// updateArr.push({ gameCode, cardCode: val.cardCode, charaId });
// }
// // 处理旧卡
// oldChara.cards.forEach((cur) => { cur.cardCode = '', cur.cardId = 0 });
// oldChara.ap = oldChara.apSkill = oldChara.roundSkill = 0;
// oldChara.seqId = seqId;
// // 更新角色卡
// await RougelikeCharaModel.bulkWriteUpdate([oldChara, newChara]);
// let cards = formateCharasOrCards(await RougelikeCardModel.findByGameCodeAndCardCodes(gameCode, cardCodes), ROUGE_LIKE_CARD_TYPE.PASSIVE).cards;
// // 更新card
// await RougelikeCardModel.bulkWriteUpdate(updateArr);
// let charas = formateCharasOrCards([oldChara, newChara], ROUGE_LIKE_CARD_TYPE.CHARA).charas;
return resResult(STATUS.SUCCESS, { charas });
}
/**
* 解锁科技点
* @param msg
* @param session
*/
async unlockTech(msg: { techId: number }, session: BackendSession) {
let roleId: string = session.get('roleId');
let sid: string = session.get('sid');
const { techId } = msg;
let dicTech = gameData.rougeTech.get(techId);
if (!dicTech) return resResult(STATUS.DIC_DATA_NOT_FOUND);
let techRecord = await RougelikeTechModel.findByRoleId(roleId);
let { unlockedTech = [] } = techRecord || {};
if (unlockedTech.includes(techId)) return resResult(STATUS.ROUGE_TECH_HAS_UNLOCKED);
if (!checkPreRougeTech(techId, unlockedTech)) return resResult(STATUS.ROUGE_TECH_PRE_NOT_UNLOCKED);
// 检查消耗
let costResult = await handleCost(roleId, sid, dicTech.cost, ITEM_CHANGE_REASON.ROUGE_UNLOCK_TECH);
if (!costResult) return resResult(STATUS.ROLE_MATERIAL_NOT_ENOUGH);
let circleIds = gameData.rougeCircleByTech.get(techId) || [];
techRecord = await RougelikeTechModel.unlockTech(roleId, techId, circleIds);
if (!techRecord) return resResult(STATUS.ROUGE_TECH_SCORE_NOT_ENOUGH);
await updateEffectId(techRecord);
let resultData = getCurTechData(techRecord, techId);
return resResult(STATUS.SUCCESS, {
...resultData
});
}
/**
* 放置法阵
* @param msg
* @param session
* @returns
*/
async putOnCircle(msg: { circleId: number, hid: number }, session: BackendSession) {
let roleId: string = session.get('roleId');
const { circleId, hid } = msg;
let techId = gameData.rougeTechCircle.get(circleId);
if (!techId) return resResult(STATUS.DIC_DATA_NOT_FOUND);
let dicTech = gameData.rougeTech.get(techId);
if (!dicTech) return resResult(STATUS.DIC_DATA_NOT_FOUND);
let techRecord = await RougelikeTechModel.findByRoleId(roleId);
if (!techRecord) return resResult(STATUS.ROUGE_CIRCLE_NOT_UNLOCK);
let { unlockedTech = [] } = techRecord;
if (!unlockedTech.includes(techId)) return resResult(STATUS.ROUGE_CIRCLE_NOT_UNLOCK);
let ce = 0;
if (hid != 0) {
let hero = await HeroModel.findByHidAndRole(hid, roleId, 'ce');
if (!hero) return resResult(STATUS.HERO_NOT_FIND);
ce = hero.ce || 0;
}
techRecord = await RougelikeTechModel.putOnCircle(roleId, circleId, hid, ce);
if (!techRecord) return resResult(STATUS.ROUGE_CIRCLE_NOT_UNLOCK);
await updateEffectId(techRecord);
let resultData = getCurTechData(techRecord, techId);
return resResult(STATUS.SUCCESS, {
...resultData
});
}
/**
* 领取图鉴奖励
* @param msg
* @param session
* @returns
*/
async receiveCollectionReward(msg: { type: number, id: number }, session: BackendSession) {
let roleId: string = session.get('roleId');
let roleName: string = session.get('roleName');
let sid: string = session.get('sid');
let { type, id } = msg;
let dic: DicRougePassiveCollect | DicRougeHolyCard | DicRougeSkillCard | DicRougeOptionGroup;
let num = 1;
if (type == COLLECTION_TYPE.PASSIVE_CARD_SUM) {
dic = gameData.rougePassiceCollect.get(id);
num = dic?.num || 0;
} else if (type == COLLECTION_TYPE.HOLY_CARD) {
dic = gameData.rougeHolyCard.get(id);
} else if (type == COLLECTION_TYPE.SKILL_CARD) {
dic = gameData.rougeSkillCard.get(id);
} else if (type == COLLECTION_TYPE.EVENT) {
dic = gameData.rougeOptionGroup.get(id);
}
if (!dic) return resResult(STATUS.DIC_DATA_NOT_FOUND);
let collect = await RougelikeCollectionModel.findByRoleAndId(roleId, type, id);
if (!collect) return resResult(STATUS.ROUGE_COLLECT_NOT_ENOUGH);
if (collect.received.includes(id)) return resResult(STATUS.ROUGE_COLLECT_HAS_RECEIVED);
collect = await RougelikeCollectionModel.receive(roleId, type, id, num);
if (!collect) return resResult(STATUS.ROUGE_COLLECT_NOT_ENOUGH);
let goods = await addItems(roleId, roleName, sid, dic.collectReward, ITEM_CHANGE_REASON.RECEIVE_COLLECT_REWARD);
return resResult(STATUS.SUCCESS, {
goods, curCollection: new CollectionReturnParam(collect)
});
}
/**
* 领取积分奖励
* @param msg
* @param session
* @returns
*/
async receiveScore(msg: { index: number }, session: BackendSession) {
let roleId: string = session.get('roleId');
let sid: string = session.get('sid');
let roleName: string = session.get('roleName');
let { index } = msg;
let dicScore = gameData.rougeScoreReward.get(index);
if (!dicScore) return resResult(STATUS.DIC_DATA_NOT_FOUND);
let scoreData = await RougelikeScoreModel.findByRoleId(roleId);
if (!scoreData || scoreData.score < dicScore.score) return resResult(STATUS.ROUGE_SCORE_NOT_ENOUGH);
if (scoreData.received.includes(index)) return resResult(STATUS.ROUGE_SCORE_HAS_RECEIVED);
scoreData = await RougelikeScoreModel.receive(roleId, dicScore.score, index);
if (!scoreData) return resResult(STATUS.ROUGE_SCORE_NOT_ENOUGH);
let goods = await addItems(roleId, roleName, sid, dicScore.reward, ITEM_CHANGE_REASON.RECEIVE_ROUGE_SCORE_REWARD);
return resResult(STATUS.SUCCESS, {
receivedScore: scoreData.received,
goods
});
}
/**
* debug接口,清空科技树
* @param msg
* @param session
* @returns
*/
async debugClearTech(msg: {}, session: BackendSession) {
let roleId: string = session.get('roleId');
await RougelikeTechModel.clearTech(roleId);
return resResult(STATUS.SUCCESS);
}
async debugAddCard(msg: { type: number, id: number }, session: BackendSession) {
let { type, id } = msg;
let roleId: string = session.get('roleId');
let sid: string = session.get('sid');
const dbRecord = await RougelikeRecordModel.findByRoleIdAndStatus(roleId, ROUGE_LIKE_STATUS.SUCCESS);
if (!dbRecord) {
return resResult(STATUS.NO_ROUGELIKE_GAME);
}
let handleAddFun = new HandleAddCard(roleId, sid, dbRecord.gameCode);
if (type == ROUGE_LIKE_CARD_TYPE.CHARA) {
handleAddFun.pushChara(id, await getMaxHp(roleId, dbRecord?.gameCode || '', id, dbRecord.type, dbRecord.grade), []);
} else if (type == ROUGE_LIKE_CARD_TYPE.HOLY) {
handleAddFun.pushHolyCard(id);
} else if (type == ROUGE_LIKE_CARD_TYPE.PASSIVE) {
handleAddFun.pushPassiveCard(id);
} else {
return resResult(STATUS.WRONG_PARMS);
}
let result = await handleAddFun.save();
result = await handleAddFun.getHolyEffect();
return resResult(STATUS.SUCCESS, result);
}
// debug接口
async debugAddCollection(msg: { type: number, id: number }, session: BackendSession) {
let { type, id } = msg;
let roleId: string = session.get('roleId');
let sid: string = session.get('sid');
const dbRecord = await RougelikeRecordModel.findByRoleIdAndStatus(roleId, ROUGE_LIKE_STATUS.SUCCESS);
if (!dbRecord) {
return resResult(STATUS.NO_ROUGELIKE_GAME);
}
await addSingleCollect(roleId, sid, dbRecord.gameCode, type, id);
return resResult(STATUS.SUCCESS);
}
async debugAddScore(msg: { score: number }, session: BackendSession) {
let { score } = msg;
let roleId: string = session.get('roleId');
let result = await RougelikeScoreModel.incScore(roleId, score);
return resResult(STATUS.SUCCESS, { weeklyScore: result.score })
}
async debugRepaireScoreReward() {
await repaireSendScoreReward();
return resResult(STATUS.SUCCESS);
}
/**
* debug添加试炼通关
* @param msg
* @param session
* @returns
*/
async debugAddLimitId(msg: { id: number }, session: BackendSession) {
const { id } = msg;
const roleId: string = session.get('roleId');
const typeGradeByIdData = gameData.rougeTypeGradeById.get(id);
if (typeGradeByIdData) {
// for (let i = 3; i <= 42; i++) {
await RougelikeExtendModel.update(roleId, id, [], genCode(8));
// }
}
return resResult(STATUS.SUCCESS);
}
}