1019 lines
46 KiB
TypeScript
1019 lines
46 KiB
TypeScript
import { clone, result } from "underscore";
|
||
import { ROUGE_CHARA_INITIAL, ROUGE_CHARA_TYPE, ROUGE_EFFECT_TYPE, ROUGE_LIKE_CARD_TYPE, ROUGE_LIKE_CHOOSE_REWARD, ROUGE_LIKE_NODE_TYPE, ROUGE_LIKE_STATUS, SHOP_REFRESH_TYPE } from "../../consts";
|
||
import { Card, RougelikeCharaModel, RougelikeCharaPara, RougelikeCharaType } from "../../db/RougelikeChara";
|
||
import { RougelikeLayerModel, RougelikeLayerType } from "../../db/RougelikeLayer";
|
||
import { RougelikeRecordModel, RougelikeRecordType } from "../../db/RougelikeRecord";
|
||
import { gameData } from "../../pubUtils/data";
|
||
import { ROUGELIKE } from "../../pubUtils/dicParam";
|
||
import { genCode, getRandEelm, getRandEelmWithWeight, getRandEelmWithWeightAndNum, getRandValueByMinMax } from "../../pubUtils/util";
|
||
import { RougelikeCardModel, RougelikeCardType } from "../../db/RougelikeCard";
|
||
import RougelikeRecordDetail, { RougelikeRecordDetailModel, RougelikeRecordDetailPara, RougelikeRecordDetailType } from "../../db/RougelikeRecordDetail";
|
||
import { CollectionReturnParam, CommonCard, CommonChara, CommonNode, CommonReward, RewardInter, layerNode } from "../../pubUtils/interface";
|
||
import { DicRougeQuestionMarkPlan } from "../../pubUtils/dictionary/DicRougeQuestionMarkPlan";
|
||
import { DicRougeRandomEventPlan } from "../../pubUtils/dictionary/DicRougeRandomEventPlan";
|
||
import * as util from 'util';
|
||
import { RougelikeCollectionModel, } from "../../db/RougelikeCollection";
|
||
import { RougelikeScoreModel, RougelikeScorePara } from "../../db/RougelikeScore";
|
||
import { getTechData } from "./rougeTechService";
|
||
import { getZeroPointOfTimeD } from "../../pubUtils/timeUtil";
|
||
import { sendMailByContent } from "../mailService";
|
||
import { MAIL_TYPE, PUSH_ROUTE } from "../../consts";
|
||
import { sendMessageToUserWithSuc } from "../pushService";
|
||
import { RougeEffect, getAddChoosePassive, getAddPassiveWeight, getChooseQualityPassives, getShopDiscount } from "./rougeEffectService";
|
||
import { formateCharasOrCards } from "./rougeCollectService";
|
||
import { errlogger } from "../../util/logger";
|
||
import { RougelikeExtendModel } from "../../db/RougelikeExtend";
|
||
import { isDevelopEnv } from "../utilService";
|
||
import { DicRougeCharaCardPlan } from "../../pubUtils/dictionary/DicRougeCharaCardPlan";
|
||
|
||
export async function getRougeData(roleId: string) {
|
||
|
||
let isPlaying = true, gameCode = '';
|
||
const dbRecord = await RougelikeRecordModel.findByRoleIdAndStatus(roleId, ROUGE_LIKE_STATUS.SUCCESS);
|
||
if (!dbRecord) isPlaying = false;
|
||
else gameCode = dbRecord.gameCode;
|
||
|
||
let dbScore = await RougelikeScoreModel.findByRoleId(roleId);
|
||
let techData = await getTechData(roleId);
|
||
|
||
let dbCollections = await RougelikeCollectionModel.findByRoleId(roleId);
|
||
let collections = dbCollections.map((obj) => new CollectionReturnParam(obj));
|
||
|
||
const dbExtends = await RougelikeExtendModel.findByRoleId(roleId);
|
||
const limitIds = dbExtends.map(cur => cur.limitId);
|
||
const lastMaxLv = await RougelikeRecordModel.getLastMaxLv(roleId);
|
||
return { isPlaying, gameCode, weeklyScore: dbScore?.score || 0, receivedScore: dbScore?.received || [], ...techData, collections, limitIds, takeoutRewardCnt: dbScore?.takeoutRewardCnt, lastMaxLv }
|
||
}
|
||
|
||
/*
|
||
/**
|
||
* 获取初始三名角色卡
|
||
* @param
|
||
* @returns
|
||
*/
|
||
export function getInitCharaCard() {
|
||
let canRandomCharas = gameData.rougeCharaByInitial.get(ROUGE_CHARA_INITIAL.CAN);
|
||
if (!canRandomCharas || canRandomCharas.length < ROUGELIKE.INIT_RANDOM_CHARA_COUNT) {
|
||
console.error("getInitChara--配置表中能初始随机的角色卡不足, canRandomCharas=%s", canRandomCharas);
|
||
return;
|
||
}
|
||
|
||
let randomData = getRandEelm(canRandomCharas, ROUGELIKE.INIT_RANDOM_CHARA_COUNT)
|
||
|
||
return randomData;
|
||
}
|
||
|
||
/**
|
||
* 获取大地图生成数据
|
||
* @param layerPlan
|
||
* @param layerCount
|
||
*/
|
||
export function getMap(layerPlan: number, layerCount: number) {
|
||
let retLayer = getLayerNodeRandom(layerPlan, layerCount);
|
||
if (!retLayer) return [];
|
||
return getLayerNodeLineRandom(retLayer) || [];
|
||
|
||
}
|
||
export function getLayerNodeRandom(layerPlan: number, layerCount: number) {
|
||
if (!layerPlan || !layerCount) return;
|
||
|
||
const layerPlanDatas = gameData.rougeLayerPlanByPlanId.get(layerPlan);
|
||
if (!layerPlanDatas || layerPlanDatas.length != layerCount) return console.error("getMap--获取配置层数不一致, layerPlan=%s, layerCount=%s", layerPlan, layerCount);
|
||
|
||
let retLayer = new Map<number, CommonNode>();
|
||
|
||
//获取可随机到的节点
|
||
for (let data of layerPlanDatas) {
|
||
let layerNodeNumPlanDatas = gameData.rougeLayerNodeNumPlan.get(data.nodeNumPlan);
|
||
if (!layerNodeNumPlanDatas) return console.error("getMap--rougeLayerNodeNumPlan配置错误, planId=%s", data.nodeNumPlan);
|
||
let nodeNum = 0;
|
||
if (layerNodeNumPlanDatas.length == 1) nodeNum = 1;
|
||
else nodeNum = getRandEelmWithWeight(layerNodeNumPlanDatas).dic.nodeNum;
|
||
|
||
let layerNodePlans = gameData.rougeLayerNodePlan.get(data.nodePlan);
|
||
if (!layerNodePlans || layerNodePlans.length == 0) return console.error("getMap--rougeLayerNodePlan配置错误, planId=%s", data.nodePlan);
|
||
|
||
let randomNodes: CommonNode['layerNodes'] = [], tempIndex = 0;
|
||
if (layerNodePlans.length > nodeNum) {
|
||
randomNodes = getRandEelmWithWeightAndNum(layerNodePlans, nodeNum).map((cur) => {
|
||
let nodeId = cur.dic.nodeId;
|
||
let nodeData = gameData.rougeNode.get(nodeId);
|
||
if (!nodeData) errlogger.error(`nodePlane ${data.nodePlan} 's nodeId ${nodeId} not found`);
|
||
return { detailCode: genCode(8), index: tempIndex++, nodeId, preNodeIndexs: [], type: nodeData.nodeType, isChoose: 0 };
|
||
});
|
||
} else {
|
||
randomNodes = layerNodePlans.map((cur) => {
|
||
let nodeId = cur.nodeId;
|
||
let nodeData = gameData.rougeNode.get(nodeId);
|
||
return { detailCode: genCode(8), index: tempIndex++, nodeId: cur.nodeId, preNodeIndexs: [] as number[], type: nodeData.nodeType, isChoose: 0 };
|
||
});
|
||
}
|
||
|
||
retLayer.set(data.layerIndex, { layer: data.layerIndex, layerNodes: randomNodes });
|
||
}
|
||
// console.log('-x-x--x-x-x-x-x-x-x-x-x- retLayer', util.inspect(retLayer, { depth: null }));
|
||
return retLayer;
|
||
}
|
||
|
||
/**
|
||
* 随机节点连线
|
||
* @param retLayer
|
||
* @returns
|
||
*/
|
||
export function getLayerNodeLineRandom(retLayer: Map<number, CommonNode>) {
|
||
for (let [key, value] of retLayer) {
|
||
let preLayer = retLayer.get(key - 1);
|
||
let curLayer = retLayer.get(key);
|
||
if (!preLayer || !curLayer) continue;
|
||
let tempPreNodes = preLayer.layerNodes; // 前一层节点数据
|
||
let tempCurNodes = curLayer.layerNodes; // 当前层节点数据
|
||
let indexMap = new Map<number, { dx: number, index: number }>(); //记录下前一层有那些节点与当前层是否连线
|
||
|
||
//当前层首节点
|
||
tempCurNodes[0].preNodeIndexs.push(tempPreNodes[0].index);
|
||
indexMap.set(tempPreNodes[0].index, { dx: 0, index: tempCurNodes[0].index });
|
||
|
||
//当前层尾节点
|
||
if (!(tempCurNodes.length == 1 && tempPreNodes.length == 1)) {
|
||
tempCurNodes[tempCurNodes.length - 1].preNodeIndexs.push(tempPreNodes[tempPreNodes.length - 1].index);
|
||
indexMap.set(tempPreNodes[tempPreNodes.length - 1].index, { dx: tempCurNodes.length - 1, index: tempCurNodes[tempCurNodes.length - 1].index });
|
||
}
|
||
|
||
for (let i = 0; i < tempCurNodes.length - 1; i++) {
|
||
let minIndex = 0, maxIndex = 0, start = 0;
|
||
if (i != 0) start = minIndex = maxIndex = Math.max(...tempCurNodes[i - 1].preNodeIndexs);
|
||
if (tempPreNodes[start + 1]) maxIndex = tempPreNodes[start + 1].index;
|
||
if (tempPreNodes[start + 2]) maxIndex = tempPreNodes[start + 2].index;
|
||
|
||
let randomIndex = minIndex;
|
||
if (minIndex < maxIndex) randomIndex = getRandValueByMinMax(minIndex, maxIndex + 1, 0);
|
||
|
||
if (tempCurNodes[i].preNodeIndexs.indexOf(randomIndex) != -1) continue;
|
||
tempCurNodes[i].preNodeIndexs.push(randomIndex);
|
||
if (indexMap.get(randomIndex) && indexMap.get(randomIndex).dx < i) continue;
|
||
indexMap.set(randomIndex, { dx: i, index: tempCurNodes[i].index });
|
||
}
|
||
|
||
//处理前一层有节点未连接情况
|
||
for (let i = 1; i < tempPreNodes.length - 1; i++) {
|
||
if (indexMap.get(tempPreNodes[i].index)) continue;
|
||
|
||
let minDx = 0, maxDx = 0;
|
||
let tempMap = new Map<number, number>();
|
||
|
||
if (tempPreNodes[i - 1] && indexMap.get(tempPreNodes[i - 1].index)) {
|
||
minDx = maxDx = indexMap.get(tempPreNodes[i - 1].index).dx
|
||
tempMap.set(minDx, indexMap.get(tempPreNodes[i - 1].index).index);
|
||
}
|
||
if (tempPreNodes[i + 1] && indexMap.get(tempPreNodes[i + 1].index)) {
|
||
maxDx = indexMap.get(tempPreNodes[i + 1].index).dx
|
||
tempMap.set(maxDx, indexMap.get(tempPreNodes[i + 1].index).index);
|
||
}
|
||
|
||
let randomDx = minDx;
|
||
if (minDx < maxDx) randomDx = getRandValueByMinMax(minDx, maxDx + 1, 0);
|
||
|
||
tempCurNodes[randomDx].preNodeIndexs.push(tempPreNodes[i].index);
|
||
if (indexMap.get(tempPreNodes[i].index) && indexMap.get(tempPreNodes[i].index).dx < randomDx) continue;
|
||
indexMap.set(tempPreNodes[i].index, { dx: randomDx, index: tempMap.get(randomDx) });
|
||
}
|
||
}
|
||
|
||
// console.log('-x-x--x-x-x-x-x-x-x-x-x- [...retLayer.values()]', util.inspect([...retLayer.values()], { depth: null }));
|
||
|
||
return [...retLayer.values()];
|
||
}
|
||
|
||
/**
|
||
* 选择节点
|
||
* @param dbRecord
|
||
* @param layerChooseNode
|
||
* @returns
|
||
*/
|
||
export async function chooseNode(dbRecord: RougelikeRecordType, layerChooseNode: layerNode, layer: number) {
|
||
|
||
const { roleId, gameCode, type, grade, curLayer, authorType } = dbRecord;
|
||
|
||
const { detailCode, nodeId, } = layerChooseNode
|
||
let nodeType = layerChooseNode.type;
|
||
|
||
const typeGradeData = gameData.rougeTypeGrade.get(type + '_' + grade);
|
||
const nodeData = gameData.rougeNode.get(nodeId);
|
||
if (!typeGradeData || !nodeData) return;
|
||
|
||
const layerPlanData = gameData.rougeLayerPlan.get(typeGradeData.layerPlan + '_' + layer);
|
||
// console.log("-x--x-x-x-x- nodeData", nodeData)
|
||
// console.log("-x--x-x-x-x- typeGradeData", typeGradeData)
|
||
// console.log("-x--x-x-x-x- layerPlanData", layerPlanData)
|
||
|
||
|
||
if (!layerPlanData) return;
|
||
|
||
|
||
let isReward = false, isShop = false;
|
||
let warId, reward = {} as CommonReward, shops: RougelikeRecordDetailType['shops'] = [],
|
||
challenge = {} as RougelikeRecordDetailType['challenge'], question = {} as RougelikeRecordDetail['question'], restPoints: RougelikeRecordDetail['restPoints'] = [];
|
||
|
||
|
||
const dbDetail = await RougelikeRecordDetailModel.findByCode(gameCode, detailCode);
|
||
let status = 0;
|
||
if (dbDetail) status = dbDetail.status || 0;
|
||
|
||
let dbPara = { roleId, layer, nodeId, nodeType, status } as RougelikeRecordDetailPara;
|
||
|
||
//普通关、精英关、boss关
|
||
if (nodeType == ROUGE_LIKE_NODE_TYPE.ORDINARY || nodeType == ROUGE_LIKE_NODE_TYPE.ELITE || nodeType == ROUGE_LIKE_NODE_TYPE.BOSS) {
|
||
isReward = true;
|
||
warId = dbPara.warId = nodeData.param;
|
||
}
|
||
|
||
//挑战关
|
||
else if (nodeType == ROUGE_LIKE_NODE_TYPE.CHALLENGE) {
|
||
let getChallengeData = getChallenge(typeGradeData.challengePlan);
|
||
if (getChallengeData) {
|
||
challenge = { challengeId: getChallengeData.challengeId, status: 1, progress: 0 } as RougelikeRecordDetailType['challenge'];
|
||
dbPara.challenge = challenge;
|
||
}
|
||
// isReward = true;
|
||
}
|
||
|
||
//商店
|
||
else if (nodeType == ROUGE_LIKE_NODE_TYPE.SHOP) {
|
||
isShop = true;
|
||
}
|
||
|
||
//休整点
|
||
else if (nodeType == ROUGE_LIKE_NODE_TYPE.REST_POINT) {
|
||
isReward = true;
|
||
if (dbDetail && dbDetail.restPoints) restPoints = dbDetail.restPoints || restPoints;
|
||
else dbPara.restPoints = restPoints;
|
||
}
|
||
|
||
//问号点
|
||
else if (nodeType == ROUGE_LIKE_NODE_TYPE.QUEST_POINT) {
|
||
if (dbDetail) {
|
||
question = dbDetail.question || {} as RougelikeRecordDetail['question'];
|
||
warId = dbDetail.warId;
|
||
}
|
||
else {
|
||
const questionMarkPLanData = gameData.rougeQuestionMarkPlan.get(nodeData.param);
|
||
if (!questionMarkPLanData) return;
|
||
|
||
let randomData = {} as DicRougeQuestionMarkPlan;
|
||
if (questionMarkPLanData.length == 1) randomData = questionMarkPLanData[0];
|
||
else randomData = getRandEelmWithWeight(questionMarkPLanData).dic;
|
||
|
||
dbPara.questType = randomData.nodeType;
|
||
if (randomData.nodeType == ROUGE_LIKE_NODE_TYPE.ORDINARY || randomData.nodeType == ROUGE_LIKE_NODE_TYPE.ELITE) {
|
||
isReward = true;
|
||
warId = dbPara.warId = 101110101//randomData.param;
|
||
}
|
||
else if (randomData.nodeType == ROUGE_LIKE_NODE_TYPE.SHOP) {
|
||
isShop = true
|
||
}
|
||
else if (randomData.nodeType == ROUGE_LIKE_NODE_TYPE.EVENT) {
|
||
let random = {} as DicRougeRandomEventPlan;
|
||
const randomEventPlanData = gameData.rougeRandomEventPlan.get(typeGradeData.randomEventPlan);
|
||
if (!randomEventPlanData) return;
|
||
if (randomEventPlanData.length == 1) random = randomEventPlanData[0];
|
||
else random = getRandEelmWithWeight(randomEventPlanData).dic;
|
||
question.randomEventId = random.randomEventId;
|
||
question.EventOptions = [];
|
||
dbPara.question = question;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
let weightRecords = [];
|
||
if ((!dbDetail || !dbDetail.shops || dbDetail.shops.length == 0) && isShop) {
|
||
let result = await getLayerShopReward(roleId, gameCode, authorType, nodeId, layerPlanData.shopPlan);
|
||
dbPara.shops = shops = result.shops;
|
||
weightRecords = dbPara.weightRecords = (result?.weightRecords || [])
|
||
}
|
||
if (dbDetail && dbDetail.shops) { shops = dbDetail.shops || shops; weightRecords = dbDetail.weightRecords }
|
||
|
||
if ((!dbDetail || !dbDetail.rewards || dbDetail.rewards.length == 0) && isReward) {
|
||
let result = await getLayerNodeReward(roleId, gameCode, authorType, nodeId, layerPlanData.rewardPlan, layer, dbPara.questType);
|
||
if (result && result.rewards) {
|
||
reward = result;
|
||
dbPara.rewards = result.rewards;
|
||
}
|
||
|
||
if (isDevelopEnv()) {
|
||
weightRecords = dbPara.weightRecords = (result?.weightRecords || []);
|
||
}
|
||
}
|
||
if (dbDetail && dbDetail.rewards) {
|
||
let tempType = (dbDetail?.questType || 0) > 0 ? dbDetail?.questType : nodeType
|
||
const layerRewardData = gameData.rougeLayerRewardPlan.get(layerPlanData.rewardPlan + '_' + tempType);
|
||
if (!layerRewardData) return;
|
||
let { coin, score, tech } = layerRewardData;
|
||
reward = { rewards: dbDetail.rewards || [], score: score || 0, techScore: tech || 0, takeoutReward: layerPlanData.takeoutReward || [] };
|
||
|
||
if (isDevelopEnv()) {
|
||
weightRecords = dbDetail.weightRecords
|
||
}
|
||
}
|
||
|
||
if (!dbDetail) {
|
||
// console.log('-x-x--x-x-x-x-x-x-x-x-x- dbPara', util.inspect(dbPara, { depth: null }));
|
||
await RougelikeRecordDetailModel.updateByCode(gameCode, detailCode, { $set: dbPara });
|
||
await RougelikeRecordModel.updateByGameCode(gameCode, { $set: { curLayer: layer } })
|
||
await RougelikeLayerModel.updateByGameCodeAndLayer(gameCode, layer, detailCode, ROUGE_LIKE_CHOOSE_REWARD.CHOOSE)
|
||
}
|
||
|
||
let curNode = { detailCode, nodeId, nodeType, status, warId, reward, shops, challenge, question, restPoints, weightRecords }
|
||
// console.log('-x-x--x-x-x-x-x-x-x-x-x- curNode', util.inspect(curNode, { depth: null }));
|
||
return curNode;
|
||
}
|
||
|
||
|
||
/**
|
||
* 获取当前层当前节点奖励
|
||
* @param gameCode
|
||
* @param detailCode
|
||
* @param nodeId 关卡id
|
||
* @param rewardPlan 赠送奖励id
|
||
* @returns
|
||
*/
|
||
export async function getLayerNodeReward(roleId: string, gameCode: string, type: number, nodeId: number, rewardPlan: number, layer: number, nodeType?: number) {
|
||
const nodeData = gameData.rougeNode.get(nodeId);
|
||
if (!nodeData) return;
|
||
if (!nodeType) nodeType = nodeData?.nodeType || 0;
|
||
|
||
const layerRewardData = gameData.rougeLayerRewardPlan.get(rewardPlan + '_' + nodeType);
|
||
if (!layerRewardData) return;
|
||
let { charaPlan, charaRandomNum, charaChooseNum,
|
||
passiveCardPlan, charaPassivePlan, passiveCardRandomNum, passiveCardChooseNum,
|
||
holyCardPlan, holyCardRandomNum, holyCardChooseNum,
|
||
coin, score, tech } = layerRewardData;
|
||
|
||
let dbRougelikeCards = await RougelikeCardModel.findByGameCodeAndType(gameCode, ROUGE_LIKE_CARD_TYPE.PASSIVE);
|
||
|
||
let rewards: RougelikeRecordDetailType['rewards'] = [];
|
||
|
||
let charaCards = getCharaCardPlan(charaPlan, charaRandomNum);
|
||
if (charaCards && charaCards.length > 0) {
|
||
let tempOptions = [], index = 0;
|
||
for (let ele of charaCards) {
|
||
tempOptions.push({
|
||
optionIndex: index++, rewardId: ele.cardId, optionStatus: ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE,
|
||
passiveCardIds: await getSelfPassiveCards(ele.cardId, charaPassivePlan, type, dbRougelikeCards, gameCode, roleId)
|
||
})
|
||
}
|
||
rewards.push({
|
||
groupIndex: rewards.length + 1,
|
||
rewardType: ROUGE_LIKE_CARD_TYPE.CHARA,
|
||
options: tempOptions,
|
||
groupStatus: charaChooseNum > 0 ? ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE : ROUGE_LIKE_CHOOSE_REWARD.CHOOSE,
|
||
chooseNum: charaChooseNum,
|
||
reRandRewardCnt: 0,
|
||
});
|
||
}
|
||
|
||
passiveCardRandomNum = await getPassiveCardRandom(passiveCardChooseNum, passiveCardRandomNum, gameCode, layer, roleId);
|
||
let { passiveCards, passiveWeightRecords } = await getPassiveCardPlan(passiveCardPlan, passiveCardRandomNum, type, dbRougelikeCards, gameCode, roleId);
|
||
if (passiveCards && passiveCards.length > 0) {
|
||
let chooseNum = await getPassiveCardChooseNum(passiveCardChooseNum, passiveCardRandomNum, gameCode, layer, roleId);
|
||
rewards.push({
|
||
groupIndex: rewards.length + 1,
|
||
rewardType: ROUGE_LIKE_CARD_TYPE.PASSIVE,
|
||
options: passiveCards.map((ele, index) => { return { optionIndex: index++, rewardId: ele.cardId, optionStatus: ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE } }),
|
||
groupStatus: chooseNum > 0 ? ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE : ROUGE_LIKE_CHOOSE_REWARD.CHOOSE,
|
||
chooseNum,
|
||
reRandRewardCnt: 0,
|
||
});
|
||
}
|
||
|
||
let { holyCards, holyWeightRecords } = await getHolyCardPlan(holyCardPlan, holyCardRandomNum, dbRougelikeCards, gameCode, roleId);
|
||
if (holyCards && holyCards.length > 0) {
|
||
rewards.push({
|
||
groupIndex: rewards.length + 1,
|
||
rewardType: ROUGE_LIKE_CARD_TYPE.HOLY,
|
||
options: holyCards.map((ele, index) => { return { optionIndex: index++, rewardId: ele.cardId, optionStatus: ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE } }),
|
||
groupStatus: holyCardChooseNum > 0 ? ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE : ROUGE_LIKE_CHOOSE_REWARD.CHOOSE,
|
||
chooseNum: holyCardChooseNum,
|
||
reRandRewardCnt: 0,
|
||
});
|
||
}
|
||
|
||
// rewards.push({ groupIndex: rewards.length + 1, rewardType: 0, groupStatus: (coin || 0) > 0 ? ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE : ROUGE_LIKE_CHOOSE_REWARD.CHOOSE, chooseNum: coin || 0 })
|
||
|
||
return { rewards, score, techScore: tech, weightRecords: [...(passiveWeightRecords || []), ...(holyWeightRecords || [])] };
|
||
}
|
||
|
||
// 处理挑战类型中 接下来X次选择特性卡时,可选择的卡片数量少1
|
||
export async function getPassiveCardRandom(passiveCardChooseNum: number, passiveCardRandomNum: number, gameCode: string, layer: number, roleId: string) {
|
||
let num = passiveCardRandomNum;
|
||
let dbDetails = await RougelikeRecordDetailModel.findByGameCodeAndLtLayer(gameCode, layer);
|
||
if (dbDetails.length == 0) return num;
|
||
for (let { challenge } of dbDetails) {
|
||
if (challenge && Object.entries(challenge).length != 0 && challenge.status == 1) {
|
||
let { challengeId } = challenge;
|
||
const rougeChallengeData = gameData.rougeChallenge.get(challengeId);
|
||
if (!rougeChallengeData) return num;
|
||
for (let effectId of (rougeChallengeData.effectId || [])) {
|
||
const rougeEffectTypeData = gameData.rougeEffect.get(effectId);
|
||
if (rougeEffectTypeData.effectType != ROUGE_EFFECT_TYPE.CHALLENGE_PASSIVE_CARD_REDUCE) continue;
|
||
num -= (rougeEffectTypeData.effectParam[1] || 0);
|
||
}
|
||
}
|
||
}
|
||
|
||
return num >= 0 ? num : 0;
|
||
}
|
||
|
||
export async function getPassiveCardChooseNum(passiveCardChooseNum: number, passiveCardRandomNum: number, gameCode: string, layer: number, roleId: string) {
|
||
let chooseNum = passiveCardChooseNum;
|
||
let dbDetails = await RougelikeRecordDetailModel.findByGameCodeAndLtLayer(gameCode, layer);
|
||
if (dbDetails.length == 0) return chooseNum;
|
||
|
||
// for (let { challenge } of dbDetails) {
|
||
// if (challenge && Object.entries(challenge).length != 0 && challenge.status == 1) {
|
||
// let { challengeId } = challenge;
|
||
// const rougeChallengeData = gameData.rougeChallenge.get(challengeId);
|
||
// if (!rougeChallengeData) return chooseNum;
|
||
// for (let effectId of (rougeChallengeData.effectId || [])) {
|
||
// const rougeEffectTypeData = gameData.rougeEffect.get(effectId);
|
||
// if (rougeEffectTypeData.effectType != ROUGE_EFFECT_TYPE.CHALLENGE_PASSIVE_CARD_REDUCE) continue;
|
||
// chooseNum -= (rougeEffectTypeData.effectParam[1] || 0);
|
||
// }
|
||
// }
|
||
// }
|
||
chooseNum += await getAddChoosePassive(roleId, gameCode);
|
||
|
||
if (chooseNum < 0) chooseNum = 0;
|
||
if (chooseNum > passiveCardRandomNum) chooseNum = passiveCardRandomNum;
|
||
|
||
return chooseNum;
|
||
}
|
||
|
||
/**
|
||
* 获取高级角色卡自带特性
|
||
* @param charaId
|
||
* @param passiveCardPlan
|
||
* @param passiveCardRandomNum
|
||
* @param type
|
||
* @param dbRougelikeCards
|
||
* @returns
|
||
*/
|
||
export async function getSelfPassiveCards(charaId: number, passiveCardPlan: number, type: number, dbRougelikeCards: RougelikeCardType[], gameCode: string, roleId: string) {
|
||
let result: number[] = [];
|
||
let charaData = gameData.rougeChara.get(charaId);
|
||
if (!charaData) return result;
|
||
if (charaData.charaType != ROUGE_CHARA_TYPE.HIGH) return result;
|
||
let { passiveCards } = await getPassiveCardPlan(passiveCardPlan, charaData.initCardCnt, type, dbRougelikeCards, gameCode, roleId);
|
||
if (passiveCards && passiveCards.length > 0) result.push(...passiveCards.map((ele) => { return ele.cardId }),);
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* 获取当前层当前节点商店数据
|
||
* @param gameCode
|
||
* @param detailCode
|
||
* @param nodeId
|
||
* @param shopPlan
|
||
* @returns
|
||
*/
|
||
export async function getLayerShopReward(roleId: string, gameCode: string, type: number, nodeId: number, shopPlan: number) {
|
||
let shops: RougelikeRecordDetailType['shops'] = [];
|
||
let shopPlanData = gameData.rougeShopPlan.get(shopPlan);
|
||
// let nodeData = gameData.rougeNode.get(nodeId);
|
||
|
||
if (!shopPlanData) return { shops };
|
||
|
||
|
||
let dbRougelikeCards = await RougelikeCardModel.findByGameCodeAndType(gameCode, ROUGE_LIKE_CARD_TYPE.PASSIVE);
|
||
|
||
let { passiveCards, passiveWeightRecords } = await getPassiveCardPlan(shopPlanData.passivecardPlanId, shopPlanData.passiveCardRandomNum, type || 0, dbRougelikeCards, gameCode, roleId);
|
||
let index = 0, discount = await getShopDiscount(roleId, gameCode);
|
||
if (passiveCards && passiveCards.length > 0) {
|
||
for (let ele of passiveCards) {
|
||
let price = gameData.rougePassiveCard.get(ele.cardId)?.price || 0
|
||
shops.push({
|
||
optionIndex: shops.length + index,
|
||
rewardType: ROUGE_LIKE_CARD_TYPE.PASSIVE,
|
||
rewardId: ele.cardId,
|
||
optionStatus: ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE,
|
||
price,
|
||
discountPrice: Math.floor(price * discount / 100),
|
||
})
|
||
index++;
|
||
}
|
||
}
|
||
|
||
let { holyCards, holyWeightRecords } = await getHolyCardPlan(shopPlanData?.holyCardPlanId, shopPlanData?.holyCardRandomNum, dbRougelikeCards, gameCode, roleId);
|
||
if (holyCards && holyCards.length > 0) {
|
||
for (let ele of holyCards) {
|
||
let price = gameData.rougeHolyCard.get(ele.cardId)?.purchasePrice || 0;
|
||
shops.push({
|
||
optionIndex: shops.length + index,
|
||
rewardType: ROUGE_LIKE_CARD_TYPE.HOLY,
|
||
rewardId: ele.cardId, optionStatus: ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE,
|
||
price,
|
||
discountPrice: Math.floor(price * discount / 100),
|
||
})
|
||
index++;
|
||
}
|
||
}
|
||
|
||
return { shops, weightRecords: [...(passiveWeightRecords || []), ...(holyWeightRecords || [])] };
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* 检测配置数据是否满足随机数量
|
||
* @param planId
|
||
* @param randomNum
|
||
* @returns
|
||
*/
|
||
export function checkRandomLimit(planId: number, randomNum: number, rewardType: number) {
|
||
let cards: DicRougeCharaCardPlan[] = [];
|
||
if (!planId || planId == 0 || !randomNum || randomNum == 0) return cards;
|
||
|
||
let cardPlanDatas = gameData.rougeCharaCardPlan.get(planId);
|
||
if (rewardType == ROUGE_LIKE_CARD_TYPE.PASSIVE) cardPlanDatas = gameData.rougePassiveCardPlan.get(planId);
|
||
else if (rewardType == ROUGE_LIKE_CARD_TYPE.HOLY) cardPlanDatas = gameData.rougeHolyCardPlan.get(planId);
|
||
|
||
if (!cardPlanDatas) return cards;
|
||
else if (cardPlanDatas.length < randomNum) {
|
||
console.error("checkRandomLimit可随机的角色卡数量少于需要数量, planId=%s, randomNum=%s", planId, randomNum);
|
||
return cardPlanDatas;
|
||
}
|
||
else if (cardPlanDatas.length >= randomNum) return cardPlanDatas;
|
||
|
||
return cards;
|
||
}
|
||
|
||
/**
|
||
* 获取角色卡随机
|
||
* @param planId
|
||
* @param charaRandomNum
|
||
* @returns
|
||
*/
|
||
export function getCharaCardPlan(planId: number, charaRandomNum: number) {
|
||
let cards = checkRandomLimit(planId, charaRandomNum, ROUGE_LIKE_CARD_TYPE.CHARA);
|
||
if (cards.length <= charaRandomNum) return cards;
|
||
let randResult = getRandEelmWithWeightAndNum(cards, charaRandomNum);
|
||
return randResult.map(cur => cur.dic);
|
||
}
|
||
|
||
|
||
/**
|
||
* 获取特性卡随机
|
||
* @param passiveCardPlan
|
||
* @param passiveCardRandomNum
|
||
*/
|
||
export async function getPassiveCardPlan(passiveCardPlan: number, passiveCardRandomNum: number, type: number, dbRougelikeCards: RougelikeCardType[], gameCode: string, roleId: string) {
|
||
let cards = checkRandomLimit(passiveCardPlan, passiveCardRandomNum, ROUGE_LIKE_CARD_TYPE.PASSIVE);
|
||
// if (cards.length <= passiveCardRandomNum) return { passiveCards: cards };
|
||
if (cards.length == 0) return { passiveCards: cards };
|
||
|
||
// 计算变化权重
|
||
let lableMap = new Map<number, number>(); //统计lable数量
|
||
if (dbRougelikeCards && dbRougelikeCards.length > ROUGELIKE.PASSIVE_LABLE_NUM) {
|
||
for (let { cardId } of dbRougelikeCards) {
|
||
if (!cardId) continue;
|
||
|
||
let passiveCardData = gameData.rougePassiveCard.get(cardId);
|
||
if (!passiveCardData || !passiveCardData.passiveLabel || passiveCardData.passiveLabel.length == 0) continue;
|
||
|
||
for (let val of passiveCardData.passiveLabel) {
|
||
if (!lableMap.get(val)) {
|
||
lableMap.set(val, 1);
|
||
continue;
|
||
}
|
||
lableMap.set(val, lableMap.get(val) + 1);
|
||
}
|
||
}
|
||
}
|
||
|
||
let newCards = [];
|
||
let cardsMap = await getCardCount(gameCode, ROUGE_LIKE_CARD_TYPE.PASSIVE);
|
||
const { chooseCardsMap, noChooseCardsMap } = await getIsChooseCard(gameCode);
|
||
for (let obj of cards) {
|
||
let weightRecord: { originalWight?: number, passiveRedWight?: number, holyAddWeight?: number, passiveLableNum?: number, authorAddWeight?: number, passiveLableNumAddWeight?: number, finalWeight?: number } = {};
|
||
if (!obj) continue;
|
||
let { cardId, weight } = obj;
|
||
if (!cardId || !weight) continue;
|
||
|
||
let passiveCardData = gameData.rougePassiveCard.get(cardId);
|
||
if (!passiveCardData) continue;
|
||
const getLimit = cardsMap.get(cardId) || 0;
|
||
if (getLimit >= (passiveCardData?.getLimit || 0)) continue; //处理限制获取数量
|
||
|
||
weightRecord.originalWight = weight;
|
||
|
||
if (chooseCardsMap.has(cardId)) {
|
||
weight = Math.floor(weight * (1 - ROUGELIKE.SELECT_PASSIVECARD_WEIGHT / 100));
|
||
weightRecord.passiveRedWight = Math.floor(weight * ROUGELIKE.SELECT_PASSIVECARD_WEIGHT / 100);
|
||
}
|
||
else if (noChooseCardsMap.has(cardId)) {
|
||
weight = Math.floor(weight * (1 - ROUGELIKE.RANDOM_PASSIVECARD_WEIGHT / 100));
|
||
weightRecord.passiveRedWight = Math.floor(weight * ROUGELIKE.RANDOM_PASSIVECARD_WEIGHT / 100);
|
||
}
|
||
|
||
|
||
const holyAddWeight = await getAddPassiveWeight(roleId, gameCode, type);
|
||
weight += holyAddWeight;
|
||
weightRecord.holyAddWeight = holyAddWeight;
|
||
|
||
const { authorType = 0, quality = 0, lv = 0 } = passiveCardData;
|
||
if (authorType == type) {
|
||
const passiveWeightData = gameData.rougePassiveWeight.get(authorType + '_' + quality + '_' + lv);
|
||
if (passiveWeightData && passiveWeightData.authorTypeWeightAdd) {
|
||
weight += passiveWeightData.authorTypeWeightAdd;
|
||
weightRecord.authorAddWeight = passiveWeightData.authorTypeWeightAdd;
|
||
}
|
||
}
|
||
|
||
|
||
let labelNum = lableMap.get(cardId) || 0;
|
||
if (labelNum >= ROUGELIKE.PASSIVE_LABLE_NUM) {
|
||
weight += ROUGELIKE.PASSIVE_LABLE_ADD_RANDOM * (Math.ceil(labelNum / ROUGELIKE.PASSIVE_LABLE_NUM));
|
||
weightRecord.passiveLableNum = labelNum;
|
||
weightRecord.passiveLableNumAddWeight = ROUGELIKE.PASSIVE_LABLE_ADD_RANDOM * (Math.ceil(labelNum / ROUGELIKE.PASSIVE_LABLE_NUM));
|
||
}
|
||
|
||
weightRecord.finalWeight = weight;
|
||
|
||
newCards.push({ ...obj, weight, weightRecord });
|
||
}
|
||
|
||
let targetPassives = await getChooseQualityPassives(roleId, gameCode, newCards);
|
||
let result = [];
|
||
if (passiveCardRandomNum >= 1 && targetPassives.length > 0) result.push(getRandEelmWithWeight(targetPassives).dic);
|
||
|
||
let randResult = getRandEelmWithWeightAndNum(newCards, passiveCardRandomNum - result.length);
|
||
|
||
return { passiveCards: [...result, ...randResult.map(cur => cur.dic)], passiveWeightRecords: newCards }
|
||
}
|
||
|
||
export async function getIsChooseCard(gameCode: string) {
|
||
const dbDetails = await RougelikeRecordDetailModel.findByGameCode(gameCode);
|
||
let chooseCardsMap = new Map<number, number>();
|
||
let noChooseCardsMap = new Map<number, number>();
|
||
for (const { rewards } of dbDetails) {
|
||
if (!rewards || rewards.length == 0) continue;
|
||
for (const { options } of rewards) {
|
||
if (!options || options.length == 0) continue;
|
||
for (const { rewardId, optionStatus } of options) {
|
||
if (optionStatus != 0) {
|
||
chooseCardsMap.set(rewardId, rewardId);
|
||
continue;
|
||
}
|
||
noChooseCardsMap.set(rewardId, rewardId);
|
||
}
|
||
}
|
||
}
|
||
return { chooseCardsMap, noChooseCardsMap };
|
||
}
|
||
|
||
|
||
export async function getCardCount(gameCode: string, type: number) {
|
||
const dbCards: RougelikeCardType[] = await RougelikeCardModel.findByGameCodeAndType(gameCode, type);
|
||
let cardsMap = new Map<number, number>();
|
||
dbCards.forEach((cur) => { cardsMap.set(cur.cardId, (cardsMap.get(cur.cardId) || 0) + 1); })
|
||
return cardsMap;
|
||
}
|
||
|
||
/**
|
||
* 获取圣物随机
|
||
* @param planId
|
||
* @param holyCardPlan
|
||
*/
|
||
export async function getHolyCardPlan(holyCardPlan: number, holyCardRandomNum: number, dbRougelikeCards: RougelikeCardType[], gameCode: string, roleId: string) {
|
||
|
||
let cards = checkRandomLimit(holyCardPlan, holyCardRandomNum, ROUGE_LIKE_CARD_TYPE.HOLY);
|
||
// if (cards.length <= holyCardRandomNum) return { holyCards: cards };
|
||
if (cards.length == 0) return { holyCards: cards };
|
||
|
||
let lableMap = new Map<number, number>();//统计lable数量
|
||
if (dbRougelikeCards && dbRougelikeCards.length > ROUGELIKE.HOLY_LABLE_NUM) {
|
||
for (let { cardId } of dbRougelikeCards) {
|
||
if (!cardId) continue;
|
||
|
||
let passiveCardData = gameData.rougePassiveCard.get(cardId);
|
||
if (!passiveCardData || !passiveCardData.holyLabel || passiveCardData.holyLabel.length == 0) continue;
|
||
|
||
for (let val of passiveCardData.holyLabel) {
|
||
if (!lableMap.get(val)) {
|
||
lableMap.set(val, 1);
|
||
continue;
|
||
}
|
||
lableMap.set(val, lableMap.get(val) + 1);
|
||
}
|
||
}
|
||
}
|
||
// 计算变化权重
|
||
let newCards = [];
|
||
let cardsMap = await getCardCount(gameCode, ROUGE_LIKE_CARD_TYPE.HOLY);
|
||
const { chooseCardsMap, noChooseCardsMap } = await getIsChooseCard(gameCode);
|
||
for (let obj of cards) {
|
||
let weightRecord: {
|
||
originalWight?: number, passiveRedWight?: number, holyRedWight?: number, authorAddWeight?: number,
|
||
passiveLableNum?: number, passiveLableNumAddWeight?: number, holyLableNum?: number, holyLableNumAddWeight?: number,
|
||
finalWeight?: number
|
||
} = {};
|
||
|
||
if (!obj) continue;
|
||
let { cardId, weight } = obj;
|
||
if (!cardId || !weight) continue;
|
||
|
||
let holyCardData = gameData.rougeHolyCard.get(cardId);
|
||
if (!holyCardData) continue;
|
||
const getLimit = cardsMap.get(cardId) || 0;
|
||
if (getLimit >= (holyCardData?.getLimit || 0)) continue; //处理限制获取数量
|
||
|
||
weightRecord.originalWight = weight;
|
||
|
||
if (chooseCardsMap.has(cardId)) {
|
||
weight = Math.floor(weight * (1 - ROUGELIKE.SELECT_HOLLYCARD_WEIGHT / 100));
|
||
weightRecord.holyRedWight = Math.floor(weight * ROUGELIKE.SELECT_HOLLYCARD_WEIGHT / 100);
|
||
}
|
||
else if (noChooseCardsMap.has(cardId)) {
|
||
weight = Math.floor(weight * (1 - ROUGELIKE.RANDOM_HOLLYCARD_WEIGHT / 100));
|
||
weightRecord.holyRedWight = Math.floor(weight * ROUGELIKE.RANDOM_HOLLYCARD_WEIGHT / 100);
|
||
}
|
||
if (!holyCardData.label) {
|
||
newCards.push({ ...obj });
|
||
weightRecord.finalWeight = weight;
|
||
continue;
|
||
};
|
||
|
||
let labelNum = lableMap.get(holyCardData.label) || 0;
|
||
if (labelNum < ROUGELIKE.HOLY_LABLE_NUM || ROUGELIKE.HOLY_LABLE_NUM == 0) {
|
||
newCards.push({ ...obj });
|
||
weightRecord.finalWeight = weight;
|
||
continue;
|
||
};
|
||
|
||
weight += ROUGELIKE.HOLY_LABLE_ADD_RANDOM * (Math.ceil(labelNum / ROUGELIKE.HOLY_LABLE_NUM));
|
||
|
||
weightRecord.holyLableNum = labelNum;
|
||
weightRecord.holyLableNumAddWeight = ROUGELIKE.HOLY_LABLE_ADD_RANDOM * (Math.ceil(labelNum / ROUGELIKE.HOLY_LABLE_NUM));
|
||
weightRecord.finalWeight = weight;
|
||
|
||
newCards.push({ ...obj, weight, weightRecord });
|
||
}
|
||
|
||
let randResult = getRandEelmWithWeightAndNum(newCards, holyCardRandomNum);
|
||
return { holyCards: randResult.map(cur => cur.dic), holyWeightRecords: newCards }
|
||
}
|
||
|
||
|
||
/**
|
||
* 获取挑战关卡数据
|
||
* @param planId
|
||
* @returns
|
||
*/
|
||
export function getChallenge(planId: number) {
|
||
const randomChallenge = getChallengePlan(planId);
|
||
if (!randomChallenge) return;
|
||
|
||
const rougeChallengeData = gameData.rougeChallenge.get(randomChallenge.challengeId);
|
||
if (!rougeChallengeData) return;
|
||
|
||
return rougeChallengeData;
|
||
}
|
||
|
||
/**
|
||
* 获取挑战关随机
|
||
* @param planId
|
||
* @returns
|
||
*/
|
||
export function getChallengePlan(planId: number) {
|
||
const challengePlanData = gameData.rougeChallengePlan.get(planId);
|
||
if (!challengePlanData) return;
|
||
if (challengePlanData.length == 1) return challengePlanData[0];
|
||
|
||
return getRandEelmWithWeight(challengePlanData).dic;
|
||
}
|
||
|
||
|
||
export async function updateChalleng(dbRecord: RougelikeRecordType, roleId: string, sid: string, gameCode: string, curLayer: number, rougeDamage, isAp?: boolean, isRound?: boolean) {
|
||
let len = rougeDamage.length;
|
||
let challenges: { challengeId: number, status: number, progress: number, detailCode: string }[] = [];
|
||
const { authorType, type, grade } = dbRecord;
|
||
let dbDetails = await RougelikeRecordDetailModel.findByGameCodeAndLtLayer(gameCode, curLayer);
|
||
if (dbDetails.length == 0) return true;
|
||
|
||
let updateChallengs: RougelikeRecordDetailPara[] = [];
|
||
for (let { detailCode, challenge, rewards = [], nodeId, layer } of dbDetails) {
|
||
if (challenge && Object.entries(challenge).length != 0 && challenge.status == 1) {
|
||
let { challengeId } = challenge;
|
||
|
||
const rougeChallengeData = gameData.rougeChallenge.get(challengeId);
|
||
if (!rougeChallengeData) return true;
|
||
for (let effectId of (rougeChallengeData.effectId || [])) {
|
||
const rougeEffectTypeData = gameData.rougeEffect.get(effectId);
|
||
if (len == 0) {
|
||
//接下来X次选择特性卡时,可选择的卡片数量少1
|
||
if (rougeEffectTypeData.effectType != ROUGE_EFFECT_TYPE.CHALLENGE_PASSIVE_CARD_REDUCE) continue;
|
||
} else {
|
||
if (rougeEffectTypeData.effectType == ROUGE_EFFECT_TYPE.CHALLENGE_PASSIVE_CARD_REDUCE) continue;
|
||
if (rougeEffectTypeData.effectType == ROUGE_EFFECT_TYPE.CHALLENGE_CHARA_NO_AP_SKILL && isAp) continue;
|
||
if (rougeEffectTypeData.effectType == ROUGE_EFFECT_TYPE.CHALLENGE_CHARA_NO_ROUND_SKILL && isRound) continue;
|
||
if (rougeEffectTypeData.effectType == ROUGE_EFFECT_TYPE.CHALLENGE_CHARA_HP_LIMIT) {
|
||
let isNext = true;
|
||
for (let obj of rougeDamage) {
|
||
const { maxHp = 0, hp = 0 } = (obj || {});
|
||
if (maxHp == 0 || hp == 0) { isNext = false; break; }
|
||
if (maxHp * (rougeEffectTypeData.effectParam[1] || 0) / 100 > hp) { isNext = false; break; }
|
||
}
|
||
|
||
if (!isNext) continue;
|
||
}
|
||
|
||
if (rougeEffectTypeData.effectType == ROUGE_EFFECT_TYPE.CHALLENGE_CHARA_NUM_LIMIT && (rougeEffectTypeData.effectParam[1] || 0) < len) continue;//接下来X场战斗,每场战斗不超过上阵2名学员
|
||
}
|
||
|
||
challenge.progress += 1;
|
||
|
||
|
||
if (challenge.progress == rougeChallengeData.condition) {
|
||
challenge.status = 2;
|
||
|
||
//处理在挑战进度完成时再随机奖励
|
||
const typeGradeData = gameData.rougeTypeGrade.get(type + '_' + grade);
|
||
if (!typeGradeData) continue;
|
||
const layerPlanData = gameData.rougeLayerPlan.get(typeGradeData.layerPlan + '_' + layer);
|
||
if (!layerPlanData) continue;
|
||
let result = await getLayerNodeReward(roleId, gameCode, authorType, nodeId, layerPlanData.rewardPlan, layer);
|
||
rewards = result.rewards;
|
||
|
||
};
|
||
}
|
||
challenges.push({ challengeId, status: challenge.status, progress: challenge.progress, detailCode });
|
||
updateChallengs.push({ gameCode, detailCode, challenge, status: 1, rewards });
|
||
}
|
||
}
|
||
|
||
await RougelikeRecordDetailModel.bulkWriteUpdate(updateChallengs);
|
||
|
||
await sendMessageToUserWithSuc(roleId, PUSH_ROUTE.ROUGE_CHALLENGE_UPDATE, { challenges }, sid);
|
||
|
||
return true;
|
||
}
|
||
|
||
export function getLayerRewardOneData(type: number, grade: number, layer: number, nodeType: number) {
|
||
let result: { takeoutReward?: RewardInter[], coin?: number, score?: number, tech?: number, spiritPlan?: RewardInter[] } = {};
|
||
const typeGradeData = gameData.rougeTypeGrade.get(type + '_' + grade);
|
||
if (!typeGradeData) return result;
|
||
const layerPlanData = gameData.rougeLayerPlan.get(typeGradeData.layerPlan + '_' + layer);
|
||
if (!layerPlanData) return result;
|
||
result = { takeoutReward: layerPlanData.takeoutReward, spiritPlan: layerPlanData.spiritPlan }
|
||
|
||
const layerRewardData = gameData.rougeLayerRewardPlan.get(layerPlanData.rewardPlan + '_' + nodeType);
|
||
if (!layerRewardData) return result;
|
||
result = { ...layerRewardData, ...result };
|
||
|
||
return result;
|
||
}
|
||
|
||
export function getRandomSpirit(spiritPlan: number, randomNum: number) {
|
||
let spiritId: number[] = [];
|
||
const spiritPlanData = gameData.spiritPlan.get(spiritPlan);
|
||
if (randomNum == 0 || !spiritPlanData || spiritPlanData.length == 0) return spiritId;
|
||
let random = getRandEelmWithWeightAndNum(spiritPlanData, randomNum);
|
||
spiritId = random.map(cur => { return cur.dic.spiritId });
|
||
|
||
return spiritId;
|
||
}
|
||
|
||
/**
|
||
* 获取
|
||
* @param authorType
|
||
* @param cards
|
||
* @returns
|
||
*/
|
||
export function getAuthorTypeCardNum(authorType: number, cards: Card[]) {
|
||
return cards.filter(card => {
|
||
let dicCard = card.cardId == 0 ? null : gameData.rougePassiveCard.get(card.cardId);
|
||
if (!dicCard) return false;
|
||
return dicCard.authorType == authorType;
|
||
}).length;
|
||
}
|
||
|
||
export async function repaireSendScoreReward() {
|
||
let refTime = new Date(getZeroPointOfTimeD(Date.now() - 86400000, SHOP_REFRESH_TYPE.WEEKLY).getTime() - (86400000 * 7));
|
||
let allRewards = await RougelikeScoreModel.findByRefTime(refTime);
|
||
let updateArr: RougelikeScorePara[] = [];
|
||
|
||
const roleIds = allRewards.map(cur => { return cur.roleId });
|
||
const lastMaxLvMap = await RougelikeRecordModel.getLastMaxLvMap(roleIds);
|
||
for (let { roleId, received, score, receiveNum } of allRewards) {
|
||
if (!lastMaxLvMap.has(roleId)) continue;
|
||
let goods: RewardInter[] = [];
|
||
const rougeScoreRewardByLvData = gameData.rougeScoreRewardByLv.get(lastMaxLvMap.get(roleId));
|
||
if (receiveNum >= rougeScoreRewardByLvData.size) continue;
|
||
for (let [index, { reward, score: targetScore }] of rougeScoreRewardByLvData) {
|
||
if (score >= targetScore && !received.includes(index)) { goods.push(...reward); }
|
||
}
|
||
await sendMailByContent(MAIL_TYPE.ROUGE_SCORE_REPAIRE, roleId, { goods });
|
||
updateArr.push({ roleId, refTime, receiveNum: rougeScoreRewardByLvData.size });
|
||
}
|
||
await RougelikeScoreModel.bulkWriteUpdate(updateArr);
|
||
}
|
||
|
||
/**
|
||
* 获取最大血量
|
||
* @param charaId
|
||
* @param type
|
||
* @param grade
|
||
* @returns
|
||
*/
|
||
export async function getMaxHp(roleId: string, gameCode: string, charaId: number, type: number, grade: number,) {
|
||
let maxHp = 0;
|
||
const charaData = gameData.rougeChara.get(charaId);
|
||
if (!charaData || !charaData.heroId) return maxHp;
|
||
const heroData = gameData.hero.get(charaData.heroId);
|
||
// console.log("x-x-x-x--x-xx- heroData", heroData);
|
||
if (!heroData || !heroData.hp) return maxHp;
|
||
|
||
const typeGradeData = gameData.rougeTypeGrade.get(type + '_' + grade);
|
||
// console.log("x-x-x-x--x-xx- typeGradeData", typeGradeData);
|
||
|
||
if (!typeGradeData || !typeGradeData.heroValue) return maxHp;
|
||
|
||
let rougeEffect = new RougeEffect(roleId, gameCode);
|
||
const holyMaxHp = await rougeEffect.getEffectMaxHp();
|
||
|
||
|
||
maxHp = heroData.hp * typeGradeData.heroValue / 10000 * (1 + holyMaxHp / 100);
|
||
|
||
return Math.floor(maxHp);
|
||
}
|
||
|
||
export async function updateMaxHp(roleId: string, gameCode: string, type: number, grade: number, updateCharasMap?: Map<string, RougelikeCharaPara>) {
|
||
let dbCharas = await RougelikeCharaModel.findByGameCode(gameCode);
|
||
if (dbCharas.length == 0) return [];
|
||
|
||
let result: RougelikeCharaType[] = [];
|
||
for (let val of dbCharas) {
|
||
if (updateCharasMap && updateCharasMap.has(val.charaCode)) {
|
||
val = { ...val, ...updateCharasMap.get(val.charaCode) }
|
||
}
|
||
let tempMaxHp = await getMaxHp(roleId, gameCode, val.charaId, type, grade);
|
||
if (tempMaxHp == val.maxHp && updateCharasMap && !updateCharasMap.has(val.charaCode)) continue;
|
||
let preMaxHp = val.maxHp;
|
||
val.maxHp = tempMaxHp;
|
||
val.hp = Math.min(val.hp + tempMaxHp - preMaxHp, tempMaxHp);
|
||
result.push(val);
|
||
}
|
||
await RougelikeCharaModel.bulkWriteUpdate(result);
|
||
let { charas } = formateCharasOrCards(result, ROUGE_LIKE_CARD_TYPE.CHARA)
|
||
return charas || [];
|
||
}
|
||
|
||
|
||
// 获取当前层之前所有未完成挑战关
|
||
export async function getPreCurLayerChallengs(gameCode: string, layer: number) {
|
||
let challenges: { challengeId: number, status: number, progress: number, detailCode: string, reward: CommonReward }[] = [];
|
||
let dbDetails = await RougelikeRecordDetailModel.findByGameCodeAndLtLayer(gameCode, layer);
|
||
if (dbDetails.length == 0) return challenges;
|
||
for (let { detailCode, challenge, rewards } of dbDetails) {
|
||
if (!challenge) continue;
|
||
const { challengeId, status, progress } = challenge;
|
||
if (status == 3) continue;
|
||
challenges.push({ challengeId, status, progress, detailCode, reward: { rewards } });
|
||
}
|
||
|
||
return challenges;
|
||
}
|
||
|
||
export async function getGame(roleId: string) {
|
||
let isPlaying = true, nodes: RougelikeLayerType[] = [], hasPass = false, curNode = {};
|
||
const dbRecord = await RougelikeRecordModel.findByRoleIdAndStatus(roleId, ROUGE_LIKE_STATUS.SUCCESS);
|
||
if (!dbRecord) {
|
||
isPlaying = false;
|
||
return { isPlaying };
|
||
}
|
||
const { gameCode, grade, type, authorType = 0, curLayer = 0, maxLayer = 0, coin = 0, score = 0, techScore = 0, coinTotal = 0 } = dbRecord;
|
||
|
||
const dbNodes = await RougelikeLayerModel.findByGameCode(gameCode);
|
||
let dbCurLayerChooseNode = {} as layerNode;
|
||
if (dbNodes) nodes = dbNodes.map((obj) => {
|
||
const { layer, layerNodes, hasPass: dbHasPass = false } = obj;
|
||
if (layer == curLayer) {
|
||
hasPass = dbHasPass;
|
||
dbCurLayerChooseNode = layerNodes.find(cur => cur.isChoose == ROUGE_LIKE_CHOOSE_REWARD.CHOOSE);
|
||
}
|
||
return { layer, layerNodes } as RougelikeLayerType
|
||
})
|
||
|
||
const charas: CommonChara[] = formateCharasOrCards(await RougelikeCharaModel.findByGameCode(gameCode), ROUGE_LIKE_CARD_TYPE.CHARA)?.charas || [];
|
||
const cards: CommonCard[] = formateCharasOrCards(await RougelikeCardModel.findByGameCode(gameCode), ROUGE_LIKE_CARD_TYPE.PASSIVE | ROUGE_LIKE_CARD_TYPE.HOLY)?.cards || [];
|
||
|
||
// console.log("x-x-x-x-x-x-x-x- dbCurLayerChooseNode", dbCurLayerChooseNode)
|
||
if (Object.entries(dbCurLayerChooseNode).length != 0) curNode = await chooseNode(dbRecord, dbCurLayerChooseNode, curLayer)
|
||
|
||
return {
|
||
isPlaying, gameCode, grade, type, authorType,
|
||
curLayer, hasPass, maxLayer, coin, coinTotal, score, techScore, nodes: nodes || [], charas, cards, curNode,
|
||
preChallengs: await getPreCurLayerChallengs(gameCode, curLayer)
|
||
};
|
||
} |