✨ feat(稷下学宫): ff931afe4到7421822f6
This commit is contained in:
1185
game-server/app/servers/battle/handler/rougeHandler.ts
Normal file
1185
game-server/app/servers/battle/handler/rougeHandler.ts
Normal file
File diff suppressed because it is too large
Load Diff
184
game-server/app/services/battle/rougeCollectService.ts
Normal file
184
game-server/app/services/battle/rougeCollectService.ts
Normal file
@@ -0,0 +1,184 @@
|
||||
import { RougelikeRecordDetailType } from '../../db/RougelikeRecordDetail';
|
||||
import { COLLECTION_TYPE, PUSH_ROUTE, ROUGE_LIKE_CARD_TYPE } from '../../consts';
|
||||
import { genCode } from '../../pubUtils/util';
|
||||
import { Card, RougelikeCharaModel, RougelikeCharaPara, RougelikeCharaType } from '../../db/RougelikeChara';
|
||||
import { RougelikeCardPara, RougelikeCardModel } from '../../db/RougelikeCard';
|
||||
import { CommonCard, CommonChara } from '../../pubUtils/interface';
|
||||
import { RougelikeCollectionModel } from '../../db/RougelikeCollection';
|
||||
import { sendMessageToUserWithSuc } from '../pushService';
|
||||
import { gameData } from '../../pubUtils/data';
|
||||
import { clone } from 'underscore';
|
||||
import { RougeEffect, getSlotUnlockPoint } from './rougeEffectService';
|
||||
|
||||
export class HandleAddCard {
|
||||
roleId: string;
|
||||
sid: string;
|
||||
gameCode: string;
|
||||
getLayer: number = 0;
|
||||
getWay: number = 0;
|
||||
addCharas: RougelikeCharaPara[] = []; // 需要更新的角色
|
||||
addPassiveCards: RougelikeCardPara[] = []; // 需要更新的特性卡
|
||||
addHolyCards: RougelikeCardPara[] = []; // 需要更新的圣物
|
||||
addCoin: number = 0; // 需要增加的试炼币
|
||||
|
||||
constructor(roleId: string, sid: string, gameCode: string, recordDetail?: RougelikeRecordDetailType) {
|
||||
this.roleId = roleId;
|
||||
this.sid = sid;
|
||||
this.gameCode = gameCode;
|
||||
if (recordDetail) {
|
||||
this.getLayer = recordDetail.layer;
|
||||
this.getWay = recordDetail.nodeType;
|
||||
}
|
||||
}
|
||||
|
||||
private getCommonParam() {
|
||||
let { roleId, gameCode, getLayer, getWay } = this;
|
||||
return { roleId, gameCode, getLayer, getWay };
|
||||
}
|
||||
|
||||
public pushChara(id: number, maxHp: number, passiveCardIds: number[]) {
|
||||
let cards: Card[] = [];
|
||||
for (let index = 0; index < passiveCardIds.length; index++) {
|
||||
let cardId = passiveCardIds[index];
|
||||
let cardCode = this.pushPassiveCard(cardId, id);
|
||||
cards.push({ index, cardCode, cardId });
|
||||
}
|
||||
let charaCode = genCode(8);
|
||||
this.addCharas.push({ ...this.getCommonParam(), cards, charaCode, charaId: id, maxHp, hp: maxHp, ap: 0, shield: 0, roundSkill: 0, apSkill: 0 });
|
||||
return charaCode;
|
||||
}
|
||||
|
||||
public pushCard(id: number, rewardType: ROUGE_LIKE_CARD_TYPE, charaId: number = 0) {
|
||||
if (rewardType == ROUGE_LIKE_CARD_TYPE.PASSIVE) {
|
||||
return this.pushPassiveCard(id, charaId);
|
||||
} else if (rewardType == ROUGE_LIKE_CARD_TYPE.HOLY) {
|
||||
return this.pushHolyCard(id);
|
||||
}
|
||||
}
|
||||
|
||||
public pushPassiveCard(id: number, charaId: number = 0) {
|
||||
let cardCode = genCode(8);
|
||||
this.addPassiveCards.push({
|
||||
...this.getCommonParam(), cardCode, cardId: id, type: ROUGE_LIKE_CARD_TYPE.PASSIVE, lv: gameData.rougePassiveCard.get(id)?.lv || 0, charaId
|
||||
});
|
||||
return cardCode
|
||||
}
|
||||
|
||||
public pushHolyCards(ids: number[]) {
|
||||
for (let id of ids) this.pushHolyCard(id);
|
||||
}
|
||||
|
||||
public pushHolyCard(id: number) {
|
||||
let cardCode = genCode(8);
|
||||
this.addHolyCards.push({
|
||||
...this.getCommonParam(), cardCode, cardId: id, type: ROUGE_LIKE_CARD_TYPE.HOLY, useCount: this.getHolyUseCount(id)
|
||||
});
|
||||
return cardCode
|
||||
}
|
||||
|
||||
private getHolyUseCount(holyId: number) {
|
||||
const holyCardData = gameData.rougeHolyCard.get(holyId);
|
||||
return holyCardData?.useCount || 0;
|
||||
}
|
||||
|
||||
public async save() {
|
||||
let result: { addCharas?: CommonChara[], addCards?: CommonCard[] } = {};
|
||||
if (this.addCharas.length > 0) {
|
||||
let updateParams = this.addCharas || [];
|
||||
let resultArrs = await RougelikeCharaModel.createCharas(updateParams);
|
||||
this.addCharas = resultArrs;
|
||||
result.addCharas = resultArrs.map(param => new CommonChara(param));
|
||||
}
|
||||
if (this.addPassiveCards.length > 0 || this.addHolyCards.length > 0) {
|
||||
let updateParams = [...(this.addPassiveCards || []), ...(this.addHolyCards || [])];
|
||||
// await RougelikeCardModel.bulkWriteUpdate(updateParams);
|
||||
updateParams.map(async param => {
|
||||
const { gameCode, cardCode } = param;
|
||||
await RougelikeCardModel.updateByCode(gameCode, cardCode, { $set: param })
|
||||
});
|
||||
result.addCards = updateParams.map(param => new CommonCard(param));
|
||||
}
|
||||
let collections: { type: number, id: number, addNum?: number }[] = [];
|
||||
for (let { cardId, type } of result.addCards || []) {
|
||||
if (type == ROUGE_LIKE_CARD_TYPE.PASSIVE) {
|
||||
collections.push({ type: COLLECTION_TYPE.PASSIVE_CARD, id: cardId });
|
||||
}
|
||||
if (type == ROUGE_LIKE_CARD_TYPE.HOLY) collections.push({ type: COLLECTION_TYPE.HOLY_CARD, id: cardId });
|
||||
}
|
||||
if (collections.length > 0) await addCollection(this.roleId, this.sid, this.gameCode, collections);
|
||||
|
||||
if (this.addCharas.length > 0) {
|
||||
result.addCharas = await this.getCharasByHolyEffect();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 处理获得角色卡时拥有圣物效果
|
||||
public async getCharasByHolyEffect() {
|
||||
let result = await getSlotUnlockPoint(this.roleId, this.gameCode, this.addCharas || []);
|
||||
this.addCharas = result.dbCharas;
|
||||
if (result.isUpdate) {
|
||||
await RougelikeCharaModel.bulkWriteUpdate(this.addCharas || []);
|
||||
}
|
||||
return this.addCharas.map(param => new CommonChara(param));
|
||||
}
|
||||
|
||||
// 处理圣物效果
|
||||
public async getHolyEffect() {
|
||||
let result: { addCharas?: CommonChara[], addCards?: CommonCard[] } = {};
|
||||
let charasMap = (this.addCharas || []).reduce((result, cur) => { result.set(cur.charaCode, cur); return result; }, new Map<string, RougelikeCharaPara>());
|
||||
let cardsMap = [...(this.addPassiveCards || []), ...(this.addHolyCards || [])].reduce((result, cur) => { result.set(cur.cardCode, cur); return result; }, new Map<string, RougelikeCardPara>());
|
||||
if ((this.addHolyCards || []).length > 0) {
|
||||
let rougeEffect = new RougeEffect(this.roleId, this.gameCode);
|
||||
let holyIds = clone(this.addHolyCards.map(cur => { return { cardCode: cur.cardCode, cardId: cur.cardId, useCount: cur.useCount } }));
|
||||
|
||||
let { charas, cards } = await rougeEffect.getEffectImmediate(holyIds);
|
||||
if (charas && charas.size > 0) {
|
||||
await RougelikeCharaModel.bulkWriteUpdate([...charas.values()]);
|
||||
charasMap = new Map([...charasMap, ...charas])
|
||||
}
|
||||
if (cards && Object.entries(cards).length > 0) {
|
||||
cardsMap = new Map([...cardsMap, ...cards])
|
||||
}
|
||||
}
|
||||
result.addCharas = [...charasMap.values()].map(param => new CommonChara(param));
|
||||
result.addCards = [...cardsMap.values()].map(param => new CommonCard(param));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export function formateCharasOrCards(params: RougelikeCharaPara[] | RougelikeCardPara[], type: number) {
|
||||
let result: { charas?: CommonChara[], cards?: CommonCard[] } = {};
|
||||
if (!params || params.length == 0) return result;
|
||||
const updateParams = params || [];
|
||||
if (type == ROUGE_LIKE_CARD_TYPE.CHARA) result.charas = updateParams.map(param => new CommonChara(param));
|
||||
else result.cards = updateParams.map(param => new CommonCard(param));
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function addCollection(roleId: string, sid: string, gameCode: string, arr: { type: number, id: number, addNum?: number }[]) {
|
||||
let collections: { type: number, id: number, num: number }[] = [], passiveCnt = 0;
|
||||
for (let { type, id, addNum = 1 } of arr) {
|
||||
if (type == COLLECTION_TYPE.PASSIVE_CARD_SUM) continue;
|
||||
let collection = await RougelikeCollectionModel.addRec(roleId, type, id, gameCode, addNum);
|
||||
if (!collection || collection.num > 1) continue;
|
||||
if (collection.num == 1) passiveCnt++;
|
||||
collections.push({ type, id, num: collection.num });
|
||||
}
|
||||
if (passiveCnt > 0) {
|
||||
let collection = await RougelikeCollectionModel.addRec(roleId, COLLECTION_TYPE.PASSIVE_CARD_SUM, 0, gameCode, passiveCnt);
|
||||
collections.push({ type: COLLECTION_TYPE.PASSIVE_CARD, id: 0, num: collection.num });
|
||||
}
|
||||
await sendMessageToUserWithSuc(roleId, PUSH_ROUTE.ROUGE_COLLECT_UPDATE, { collections }, sid);
|
||||
return collections;
|
||||
}
|
||||
|
||||
export async function addSingleCollect(roleId: string, sid: string, gameCode: string, type: number, id: number) {
|
||||
return await addCollection(roleId, sid, gameCode, [{ type, id }]);
|
||||
}
|
||||
|
||||
export async function addSameTypeCollect(roleId: string, sid: string, gameCode: string, type: number, ids: number[]) {
|
||||
return await addCollection(roleId, sid, gameCode, ids.map(id => ({ type, id })));
|
||||
}
|
||||
536
game-server/app/services/battle/rougeEffectService.ts
Normal file
536
game-server/app/services/battle/rougeEffectService.ts
Normal file
@@ -0,0 +1,536 @@
|
||||
import { ABI_TYPE } from "../../consts/constModules/abilityConst";
|
||||
import { ROUGELIKE_SKILLTYPE, ROUGE_EFFECT_TYPE, ROUGE_EFFECT_TYPE_KIND, ROUGE_LIKE_CARD_TYPE, ROUGE_SLOT_LIMIT } from "../../consts";
|
||||
import { RougelikeCardModel, RougelikeCardPara, RougelikeCardType } from "../../db/RougelikeCard";
|
||||
import { Card, RougelikeCharaModel, RougelikeCharaPara, RougelikeCharaType } from "../../db/RougelikeChara";
|
||||
import { RougelikeRecordModel } from "../../db/RougelikeRecord";
|
||||
import { gameData, getRougeEffectTypeKind } from "../../pubUtils/data";
|
||||
import { DicRougePassiveCardPlan } from "../../pubUtils/dictionary/DicRougePassiveCardPlan";
|
||||
import { getRandEelm } from "../../pubUtils/util";
|
||||
import { RougelikeTechModel } from "../../db/RougelikeTech";
|
||||
import { getAuthorTypeCardNum } from "./rougeService";
|
||||
import * as util from 'util';
|
||||
|
||||
|
||||
|
||||
export class holyId {
|
||||
cardCode: string;
|
||||
cardId: number;
|
||||
useCount: number;
|
||||
}
|
||||
|
||||
|
||||
export class RougeEffect {
|
||||
roleId: string;
|
||||
gameCode: string;
|
||||
newEffect: { effectType: number, effectParam: number[], cardCode?: string }[] = [];
|
||||
holyMap = new Map<string, { cardCode: string, cardId: number, useCount: number }>();
|
||||
updateHolyMap = new Map<string, RougelikeCardType>();
|
||||
updateCharaMap = new Map<string, RougelikeCharaType>();
|
||||
updateCardMap = new Map<string, RougelikeCardType>();
|
||||
dbCharas: RougelikeCharaType[] = [];
|
||||
dbCards: RougelikeCardType[] = [];
|
||||
|
||||
constructor(roleId: string, gameCode: string) {
|
||||
this.roleId = roleId || '';
|
||||
this.gameCode = gameCode || '';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据类型获取effectId
|
||||
* @param effectTypes
|
||||
* @param holyIds
|
||||
* @returns
|
||||
*/
|
||||
public async getEffectData(effectTypes: number[], holyIds?: holyId[]) {
|
||||
let kinds = getRougeEffectTypeKind(effectTypes);
|
||||
if (kinds.includes(ROUGE_EFFECT_TYPE_KIND.HOLY)) {
|
||||
if (!holyIds || holyIds.length == 0) {
|
||||
const dbCards = await RougelikeCardModel.findByGameCodeAndType(this.gameCode, ROUGE_LIKE_CARD_TYPE.HOLY);
|
||||
holyIds = dbCards.map((cur) => { return { cardCode: cur.cardCode, cardId: cur.cardId, useCount: cur.useCount || 0 } });
|
||||
}
|
||||
if (!holyIds || holyIds.length == 0) return { newEffect: this.newEffect, holyMap: this.holyMap };
|
||||
|
||||
for (const { cardCode, cardId, useCount } of holyIds) {
|
||||
let effectIds = gameData.rougeHolyCard.get(cardId)?.effectId || [];
|
||||
if (effectIds.length == 0) continue;
|
||||
|
||||
for (const effectId of effectIds) {
|
||||
const effectDataOne = gameData.rougeEffect.get(effectId);
|
||||
if (!effectDataOne) continue;
|
||||
const effectParam = effectDataOne.effectParam || [];
|
||||
for (let effectType of effectTypes) {
|
||||
if (effectType != effectDataOne.effectType || 0) continue;
|
||||
this.newEffect.push({ effectType, effectParam, cardCode });
|
||||
this.holyMap.set(cardCode, { cardCode, cardId, useCount })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (kinds.includes(ROUGE_EFFECT_TYPE_KIND.TECH)) {
|
||||
let tech = await RougelikeTechModel.findByRoleId(this.roleId, 'effectIds');
|
||||
for (let effectId of (tech?.effectIds || [])) {
|
||||
const effectDataOne = gameData.rougeEffect.get(effectId);
|
||||
if (!effectDataOne) continue;
|
||||
for (let effectType of effectTypes) {
|
||||
if (effectType != effectDataOne.effectType || 0) continue;
|
||||
this.newEffect.push({ effectType, effectParam: effectDataOne.effectParam || [] });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { newEffect: this.newEffect, holyMap: this.holyMap }
|
||||
}
|
||||
|
||||
/* **
|
||||
* 获取圣物时生效
|
||||
* @param gameCode
|
||||
*/
|
||||
public async getEffectImmediate(holyIds?: holyId[]) {
|
||||
let result: { charas?: Map<string, RougelikeCharaType>, cards?: Map<string, RougelikeCardType> } = {};
|
||||
this.dbCharas = await RougelikeCharaModel.findByGameCode(this.gameCode);
|
||||
this.dbCards = await RougelikeCardModel.findByGameCode(this.gameCode);
|
||||
|
||||
await this.getEffectData([
|
||||
ROUGE_EFFECT_TYPE.HOLY_CHARA_SLOT_UNLOCK_ALL, //2002
|
||||
ROUGE_EFFECT_TYPE.HOLY_CHARA_SLOT_UNLOCK_RAND, //2003
|
||||
ROUGE_EFFECT_TYPE.HOLY_PASSIVE_UPDATE_RAND, //2006
|
||||
ROUGE_EFFECT_TYPE.HOLY_UPDATE_PASSIVE_BY_LV, //2012
|
||||
ROUGE_EFFECT_TYPE.HOLY_REPAIRE_HOLY, //2015
|
||||
], holyIds)
|
||||
|
||||
await this.getCharaSlot();
|
||||
|
||||
await this.getRandCharaSlot();
|
||||
|
||||
await this.getRandomCardLv()
|
||||
|
||||
await this.getPassiveLv();
|
||||
|
||||
await this.getRecoveryHoly();
|
||||
|
||||
result = { charas: this.updateCharaMap, cards: this.updateCardMap };
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// 获得该圣物时,所有学员立刻解锁X个特性槽 2002
|
||||
private async getCharaSlot() {
|
||||
if (this.newEffect.length == 0 || this.dbCharas.length == 0) return;
|
||||
for (const { effectParam, effectType } of this.newEffect) {
|
||||
if (effectType != ROUGE_EFFECT_TYPE.HOLY_CHARA_SLOT_UNLOCK_ALL) continue;
|
||||
if (effectParam.length == 0) continue;
|
||||
for (let val of this.dbCharas) {
|
||||
let { charaCode, cards = [] } = val;
|
||||
let unlockNum = effectParam[0] || 0;
|
||||
for (let i = 0; i < unlockNum; i++) {
|
||||
unlockNum = effectParam[0] || 0;
|
||||
if (cards.length >= ROUGE_SLOT_LIMIT) continue;
|
||||
for (let index = 0; index < ROUGE_SLOT_LIMIT; index++) {
|
||||
if (cards.find(cur => cur.index == index) != undefined || unlockNum == 0) continue;
|
||||
cards.push({ index, cardCode: '', cardId: 0 });
|
||||
this.updateCharaMap.set(charaCode, val);
|
||||
unlockNum--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获得该圣物时,随机解锁X个学员的Y个特性槽 2003
|
||||
private async getRandCharaSlot() {
|
||||
if (this.newEffect.length == 0 || this.dbCharas.length == 0) return;
|
||||
for (const { effectParam, effectType } of this.newEffect) {
|
||||
if (effectType != ROUGE_EFFECT_TYPE.HOLY_CHARA_SLOT_UNLOCK_RAND) continue;
|
||||
if (effectParam.length == 0) continue;
|
||||
const randomNum = effectParam[0] || 0;
|
||||
let unlockNum = effectParam[1] || 0;
|
||||
let charas = getRandEelm(this.dbCharas.filter(cur => cur.cards.length < ROUGE_SLOT_LIMIT), randomNum);
|
||||
for (let val of charas) {
|
||||
unlockNum = effectParam[1] || 0;
|
||||
let { charaCode, cards = [] } = val;
|
||||
for (let index = 0; index < ROUGE_SLOT_LIMIT; index++) {
|
||||
if (cards.find(cur => cur.index == index) != undefined || unlockNum == 0) continue;
|
||||
cards.push({ index, cardCode: '', cardId: 0 });
|
||||
this.updateCharaMap.set(charaCode, val);
|
||||
unlockNum--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 随机升级X个已装备的特性 2006
|
||||
private async getRandomCardLv() {
|
||||
let cards: RougelikeCardType[] = [];
|
||||
if (this.newEffect.length == 0 || this.dbCards.length == 0) return cards;
|
||||
for (const { effectParam, effectType } of this.newEffect) {
|
||||
if (effectType != ROUGE_EFFECT_TYPE.HOLY_PASSIVE_UPDATE_RAND) continue;
|
||||
if (effectParam.length == 0) continue;
|
||||
const randomNum = effectParam[0] || 0;
|
||||
let random = this.dbCards.filter(cur => cur.type == ROUGE_LIKE_CARD_TYPE.PASSIVE && cur.charaId != 0 && cur.lv < (gameData.rougePassiveCard.get(cur.cardId)?.lv || 0))
|
||||
let cards = getRandEelm(random, randomNum);
|
||||
cards.forEach(cur => {
|
||||
cur.lv += 1;
|
||||
this.updateCardMap.set(cur.cardCode, cur);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 获得该圣物时立即升级所有X星特性卡 2012
|
||||
private async getPassiveLv() {
|
||||
if (this.newEffect.length == 0) return;
|
||||
for (const { effectParam, effectType } of this.newEffect) {
|
||||
if (effectType != ROUGE_EFFECT_TYPE.HOLY_UPDATE_PASSIVE_BY_LV) continue;
|
||||
if (effectParam.length == 0) continue;
|
||||
const level = effectParam[0] || 0;
|
||||
for (let val of this.dbCards) {
|
||||
let { lv, cardId, cardCode } = val;
|
||||
const passiveCardData = gameData.rougePassiveCard.get(cardId);
|
||||
if (level != passiveCardData?.quality || 0 || lv >= passiveCardData?.lv || 0) continue;
|
||||
lv += 1;
|
||||
this.updateCardMap.set(cardCode, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获得该圣物时,随机修复X个已损毁的圣物 2015
|
||||
private async getRecoveryHoly() {
|
||||
if (this.newEffect.length == 0) return;
|
||||
for (const { effectParam, effectType } of this.newEffect) {
|
||||
if (effectType != ROUGE_EFFECT_TYPE.HOLY_REPAIRE_HOLY) continue;
|
||||
if (effectParam.length == 0) continue;
|
||||
const num = effectParam[0] || 0;
|
||||
let canRandomCards: RougelikeCardType[] = []
|
||||
this.dbCards.forEach(cur => {
|
||||
const { cardCode, cardId, useCount = 0, type } = cur;
|
||||
const holyCardData = gameData.rougeHolyCard.get(cardId);
|
||||
let tempUseCount = holyCardData?.useCount || 0;
|
||||
if (tempUseCount > 0 && useCount < tempUseCount && type == ROUGE_LIKE_CARD_TYPE.HOLY) canRandomCards.push(cur);
|
||||
})
|
||||
|
||||
let randomCards = getRandEelm(canRandomCards, num);
|
||||
for (let val of randomCards) {
|
||||
let { cardCode, cardId } = val;
|
||||
val.useCount += 1;
|
||||
// if (this.holyMap.has(cardCode)) this.holyMap.set(cardCode, { cardCode, cardId, useCount });
|
||||
this.updateCardMap.set(cardCode, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 和圣物相关maxhp
|
||||
public async getEffectMaxHp() {
|
||||
let addRatio = 0;
|
||||
await this.getEffectData([
|
||||
ROUGE_EFFECT_TYPE.HOLY_CHARA_MAIN_ATTR_UP_BY_COIN, // 2005
|
||||
ROUGE_EFFECT_TYPE.HOLY_CHARA_MAIN_ATTR_UP, // 2020
|
||||
ROUGE_EFFECT_TYPE.TECH_CHARA_MAIN_ATTR_UP, // 3001
|
||||
])
|
||||
|
||||
addRatio = await this.getMaxHpByCoin();
|
||||
|
||||
addRatio += await this.getMaxHpByBase();
|
||||
|
||||
return addRatio;
|
||||
}
|
||||
|
||||
// 每有X个试炼币,全员基础属性id提高Y 2005
|
||||
private async getMaxHpByCoin() {
|
||||
let addRatio = 0;
|
||||
const dbRecord = await RougelikeRecordModel.findByGameCode(this.gameCode);
|
||||
let coinTotal = dbRecord?.coin || 0;
|
||||
if (this.newEffect.length == 0) return addRatio;
|
||||
for (const { effectParam, effectType } of this.newEffect) {
|
||||
if (effectType != ROUGE_EFFECT_TYPE.HOLY_CHARA_MAIN_ATTR_UP_BY_COIN) continue;
|
||||
if (effectParam.length == 0) continue;
|
||||
const count = effectParam[0] || 0;
|
||||
const id = effectParam[1] || 0;
|
||||
const value = effectParam[2] || 0;
|
||||
if (count == 0 || id != ABI_TYPE.ABI_HP || value == 0) continue;
|
||||
addRatio += Math.floor(coinTotal / count * value)
|
||||
}
|
||||
|
||||
return addRatio;
|
||||
}
|
||||
|
||||
// 基础属性Id&num 2020
|
||||
private async getMaxHpByBase() {
|
||||
let addRatio = 0;
|
||||
if (this.newEffect.length == 0) return addRatio;
|
||||
for (const { effectParam, effectType } of this.newEffect) {
|
||||
if (effectType != ROUGE_EFFECT_TYPE.HOLY_CHARA_MAIN_ATTR_UP && effectType != ROUGE_EFFECT_TYPE.TECH_CHARA_MAIN_ATTR_UP) continue;
|
||||
if (effectParam.length == 0) continue;
|
||||
const id = effectParam[0] || 0;
|
||||
const value = effectParam[1] || 0;
|
||||
if (id != ABI_TYPE.ABI_HP || value == 0) continue;
|
||||
addRatio += value;
|
||||
}
|
||||
return addRatio;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 每场战斗结束后,学员恢复血量上限X%的生命 2001
|
||||
export async function getCharaHp(roleId: string, gameCode: string) {
|
||||
let hpRatio = 0;
|
||||
let rougeEffect = new RougeEffect(roleId, gameCode);
|
||||
|
||||
let { newEffect, holyMap } = await rougeEffect.getEffectData([
|
||||
ROUGE_EFFECT_TYPE.HOLY_CHARA_HP_RECOVERY_UP,// 2001
|
||||
]);
|
||||
if (newEffect.length == 0) return hpRatio;
|
||||
for (const { effectType, effectParam } of newEffect) {
|
||||
if (effectParam.length == 0) continue;
|
||||
hpRatio += (effectParam[0] || 0);
|
||||
}
|
||||
return hpRatio;
|
||||
}
|
||||
|
||||
|
||||
// 战斗胜利后,获得的试炼币增加X 2004
|
||||
export async function getAddCoin(roleId: string, gameCode: string, nodeType: number) {
|
||||
let coinRatio = 0, coinAdd = 0;
|
||||
let rougeEffect = new RougeEffect(roleId, gameCode);
|
||||
let { newEffect, holyMap } = await rougeEffect.getEffectData([
|
||||
ROUGE_EFFECT_TYPE.HOLY_COIN_UP, //2004
|
||||
ROUGE_EFFECT_TYPE.TECH_COIN_UP_BY_NODE_TYPE, //3007
|
||||
]);
|
||||
if (newEffect.length == 0) return { coinRatio, coinAdd };
|
||||
for (const { effectType, effectParam } of newEffect) {
|
||||
if (effectParam.length == 0) continue;
|
||||
if (effectType == ROUGE_EFFECT_TYPE.HOLY_COIN_UP) {
|
||||
const type = effectParam[0] || 0;
|
||||
const value = effectParam[1] || 0;
|
||||
if (type == 1) coinAdd += value;
|
||||
else if (type == 2) coinRatio += value;
|
||||
}
|
||||
if (effectType == ROUGE_EFFECT_TYPE.TECH_COIN_UP_BY_NODE_TYPE) {
|
||||
let [targetNodeType = 0, value = 0] = effectParam;
|
||||
if (targetNodeType == nodeType) coinRatio += value;
|
||||
}
|
||||
|
||||
}
|
||||
return { coinRatio, coinAdd };
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 获得圣物后,X流派特性卡的权重增加Y 2007
|
||||
export async function getAddPassiveWeight(roleId: string, gameCode: string, authorType: number) {
|
||||
let addPassiveWeight = 0;
|
||||
let rougeEffect = new RougeEffect(roleId, gameCode);
|
||||
let { newEffect, holyMap } = await rougeEffect.getEffectData([
|
||||
ROUGE_EFFECT_TYPE.HOLY_PASSIVE_WEIGHT_UP_BY_AUTHOR,//2007
|
||||
]);
|
||||
if (newEffect.length == 0) return addPassiveWeight;
|
||||
for (const { effectParam } of newEffect) {
|
||||
if (effectParam.length == 0) continue;
|
||||
const type = effectParam[0] || 0;
|
||||
const value = effectParam[1] || 0;
|
||||
if (type != authorType) continue;
|
||||
addPassiveWeight += value;
|
||||
}
|
||||
return addPassiveWeight;
|
||||
}
|
||||
|
||||
// 非boss战斗失败视为胜利,并且满血复活 2009
|
||||
export async function getNoBossRecoveryHp(roleId: string, gameCode: string) {
|
||||
let rougeEffect = new RougeEffect(roleId, gameCode);
|
||||
let { newEffect, holyMap } = await rougeEffect.getEffectData([
|
||||
ROUGE_EFFECT_TYPE.HOLY_REVIVE_ALL,//2009
|
||||
]);
|
||||
if (newEffect.length == 0) return false;
|
||||
return true; // 拿到true 将所有学员更新和hp=maxHp
|
||||
}
|
||||
|
||||
// 战斗胜利后若有学员死亡,则满血复活X名死亡学员 2010
|
||||
export async function getBattleRecoveryNum(roleId: string, gameCode: string) {
|
||||
let recoveryNum = 0;
|
||||
let rougeEffect = new RougeEffect(roleId, gameCode);
|
||||
|
||||
let { newEffect, holyMap } = await rougeEffect.getEffectData([
|
||||
ROUGE_EFFECT_TYPE.HOLY_REVIVE_CHARA_RAND,//2010
|
||||
]);
|
||||
if (newEffect.length == 0) return recoveryNum;
|
||||
|
||||
for (const { effectParam } of newEffect) {
|
||||
if (effectParam.length == 0) continue;
|
||||
recoveryNum += (effectParam[0] || 0)
|
||||
}
|
||||
return recoveryNum;
|
||||
}
|
||||
|
||||
// 试炼商店中所有商品X折出售 2011
|
||||
export async function getShopDiscount(roleId: string, gameCode: string) {
|
||||
let discount = 100;
|
||||
let rougeEffect = new RougeEffect(roleId, gameCode);
|
||||
|
||||
let { newEffect, holyMap } = await rougeEffect.getEffectData([
|
||||
ROUGE_EFFECT_TYPE.HOLY_SHOP_DISCOUNT,//2011
|
||||
]);
|
||||
if (newEffect.length == 0) return discount;
|
||||
for (const { effectParam } of newEffect) {
|
||||
if (effectParam.length == 0) continue;
|
||||
const tempDiscount = effectParam[0] || 0;
|
||||
discount *= (tempDiscount / 100);
|
||||
}
|
||||
return Math.floor(discount);
|
||||
}
|
||||
|
||||
|
||||
// 下次选择特性卡时必定出现X星特性卡 2013
|
||||
export async function getChooseQualityPassives(roleId: string, gameCode: string, passiveCards: DicRougePassiveCardPlan[]) {
|
||||
let targetPassives: DicRougePassiveCardPlan[] = [];
|
||||
let rougeEffect = new RougeEffect(roleId, gameCode);
|
||||
let { newEffect, holyMap } = await rougeEffect.getEffectData([
|
||||
ROUGE_EFFECT_TYPE.HOLY_PASSIVE_CHOOSE_FIX,//2013
|
||||
]);
|
||||
if (newEffect.length == 0) return targetPassives;
|
||||
for (const { effectParam } of newEffect) {
|
||||
if (effectParam.length == 0) continue;
|
||||
const level = effectParam[0] || 0;
|
||||
for (let val of passiveCards) {
|
||||
const { cardId } = val;
|
||||
const passiveCardData = gameData.rougePassiveCard.get(cardId);
|
||||
if (level != passiveCardData?.lv || 0) continue;
|
||||
targetPassives.push(val);
|
||||
}
|
||||
}
|
||||
return targetPassives;
|
||||
}
|
||||
|
||||
// 下次选择特性卡时可多选X张特性卡 2014
|
||||
export async function getAddChoosePassive(roleId: string, gameCode: string) {
|
||||
let addChooseNum = 0;
|
||||
let rougeEffect = new RougeEffect(roleId, gameCode);
|
||||
let { newEffect, holyMap } = await rougeEffect.getEffectData([
|
||||
ROUGE_EFFECT_TYPE.HOLY_PASSIVE_CHOOSE_NUM_UP,//2014
|
||||
]);
|
||||
for (const { effectParam } of newEffect) {
|
||||
if (effectParam.length == 0) continue;
|
||||
const num = effectParam[0] || 0;
|
||||
addChooseNum += num;
|
||||
}
|
||||
return addChooseNum
|
||||
}
|
||||
|
||||
// 获得该圣物后,所有角色解锁X号位置的特性槽 2023
|
||||
export async function getSlotUnlockPoint(roleId: string, gameCode: string, dbCharas: RougelikeCharaPara[]) {
|
||||
let isUpdate = false;
|
||||
let rougeEffect = new RougeEffect(roleId, gameCode);
|
||||
let { newEffect, holyMap } = await rougeEffect.getEffectData([
|
||||
ROUGE_EFFECT_TYPE.HOLY_CHARA_SLOT_UNLOCK_POINT,//2023
|
||||
]);
|
||||
for (const { effectParam } of newEffect) {
|
||||
if (effectParam.length == 0) continue;
|
||||
const index = effectParam[0] || 0;
|
||||
for (let { cards = [] } of dbCharas) {
|
||||
if (cards.length == 0) {
|
||||
cards.push({ index, cardCode: '', cardId: 0 });
|
||||
isUpdate = true;
|
||||
continue;
|
||||
}
|
||||
if (cards.find(cur => cur.index == index) == undefined) {
|
||||
isUpdate = true
|
||||
cards.push({ index, cardCode: '', cardId: 0 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { isUpdate, dbCharas };
|
||||
}
|
||||
|
||||
|
||||
// 休整点额外恢复X%的生命 2017 3006
|
||||
export async function getRecoveryExtendHp(roleId: string, gameCode: string) {
|
||||
let hpRatio = 0;
|
||||
let rougeEffect = new RougeEffect(roleId, gameCode);
|
||||
let { newEffect, holyMap } = await rougeEffect.getEffectData([
|
||||
ROUGE_EFFECT_TYPE.HOLY_RECOVERY_POINT_UP, // 2017
|
||||
ROUGE_EFFECT_TYPE.TECH_RECOVERY_POINT_UP, // 3006
|
||||
]);
|
||||
if (newEffect.length == 0) return hpRatio;
|
||||
for (const { effectType, effectParam } of newEffect) {
|
||||
if (effectParam.length == 0) continue;
|
||||
hpRatio += (effectParam[0] || 0);
|
||||
}
|
||||
return hpRatio;
|
||||
}
|
||||
|
||||
// 休整点特训价格X折 2018 3009
|
||||
export async function getTrainCardDiscount(roleId: string, gameCode: string) {
|
||||
let discount = 100;
|
||||
let rougeEffect = new RougeEffect(roleId, gameCode);
|
||||
|
||||
let { newEffect, holyMap } = await rougeEffect.getEffectData([
|
||||
ROUGE_EFFECT_TYPE.HOLY_TRAIN_POINT_DISCOUNT, // 2018
|
||||
ROUGE_EFFECT_TYPE.TECH_TRAIN_POINT_DISCOUNT, // 3009
|
||||
]);
|
||||
if (newEffect.length == 0) return discount;
|
||||
for (const { effectParam } of newEffect) {
|
||||
if (effectParam.length == 0) continue;
|
||||
const tempDiscount = effectParam[0] || 0;
|
||||
discount *= (tempDiscount / 100);
|
||||
}
|
||||
return Math.floor(discount);
|
||||
}
|
||||
|
||||
// 初始获得试炼币&圣物 3003 3005
|
||||
export async function getEffectWhenGameStart(roleId: string, gameCode: string, authorType: number) {
|
||||
let rougeEffect = new RougeEffect(roleId, gameCode);
|
||||
|
||||
let addCoin = 0, cardIds: number[] = [];
|
||||
let { newEffect } = await rougeEffect.getEffectData([
|
||||
ROUGE_EFFECT_TYPE.TECH_INIT_HOLY_BY_AUTHOR,
|
||||
ROUGE_EFFECT_TYPE.TECH_INIT_COIN,
|
||||
]);
|
||||
if (newEffect.length == 0) return { addCoin, cardIds };
|
||||
for (const { effectType, effectParam } of newEffect) {
|
||||
if (effectParam.length == 0) continue;
|
||||
if (effectType == ROUGE_EFFECT_TYPE.TECH_INIT_HOLY_BY_AUTHOR) {
|
||||
for (let cardId of effectParam) {
|
||||
let dicCard = gameData.rougeHolyCard.get(cardId);
|
||||
if (!dicCard || dicCard.authorType != authorType) continue;
|
||||
cardIds.push(cardId);
|
||||
}
|
||||
}
|
||||
if (effectType == ROUGE_EFFECT_TYPE.TECH_INIT_COIN) addCoin += effectParam[0];
|
||||
}
|
||||
return { addCoin, cardIds };
|
||||
}
|
||||
|
||||
// 是否可以选择技能卡 3004
|
||||
export async function checkCanChooseSkillCard(roleId: string, gameCode: string, skillId: number, cards: Card[]) {
|
||||
let rougeEffect = new RougeEffect(roleId, gameCode);
|
||||
let { newEffect } = await rougeEffect.getEffectData([
|
||||
ROUGE_EFFECT_TYPE.TECH_CAN_CHOOSE_SKILL_CARD, // 3004
|
||||
]);
|
||||
let dicSkillCard = gameData.rougeSkillCard.get(skillId);
|
||||
if (!dicSkillCard) return false;
|
||||
let { authorType, skillType } = dicSkillCard;
|
||||
let num = getAuthorTypeCardNum(authorType, cards);
|
||||
|
||||
let curParam = newEffect.find(({ effectParam }) => {
|
||||
return effectParam[1] == skillType;
|
||||
});
|
||||
if (!curParam || num < curParam.effectParam[0]) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 是否可以重置
|
||||
export async function checkCanReRandomReward(roleId: string, gameCode: string, rewardType: number) {
|
||||
let rougeEffect = new RougeEffect(roleId, gameCode);
|
||||
let { newEffect } = await rougeEffect.getEffectData([
|
||||
ROUGE_EFFECT_TYPE.TECH_PASSIVE_RANDOM_AGAIN, // 3008
|
||||
]);
|
||||
|
||||
let curParam = newEffect.find(({ effectParam }) => {
|
||||
return effectParam[0] == rewardType;
|
||||
});
|
||||
if (!curParam) return { canReRandom: false, costCoin: 0 }
|
||||
return { canReRandom: true, costCoin: curParam.effectParam[1] || 0 };
|
||||
}
|
||||
958
game-server/app/services/battle/rougeService.ts
Normal file
958
game-server/app/services/battle/rougeService.ts
Normal file
@@ -0,0 +1,958 @@
|
||||
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, 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 } from "../../db/RougelikeScore";
|
||||
import { getTechData } from "./rougeTechService";
|
||||
import { getZeroPointOfTimeD } from "../../pubUtils/timeUtil";
|
||||
import { sendMailByContent } from "../mailService";
|
||||
import { DicRougeCharaCardPlan } from "../../pubUtils/DicRougeCharaCardPlan";
|
||||
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";
|
||||
|
||||
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);
|
||||
|
||||
return { isPlaying, gameCode, weeklyScore: dbScore?.score || 0, receivedScore: dbScore?.received || [], ...techData, collections, limitIds }
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* 获取初始三名角色卡
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((!dbDetail || !dbDetail.shops || dbDetail.shops.length == 0) && isShop) {
|
||||
shops = await getLayerShopReward(roleId, gameCode, authorType, nodeId, layerPlanData.shopPlan);
|
||||
dbPara.shops = shops;
|
||||
}
|
||||
if (dbDetail && dbDetail.shops) shops = dbDetail.shops || shops;
|
||||
|
||||
if ((!dbDetail || !dbDetail.rewards || dbDetail.rewards.length == 0) && isReward) {
|
||||
let result = await getLayerNodeReward(roleId, gameCode, authorType, nodeId, layerPlanData.rewardPlan, layer, dbPara.questType);
|
||||
if (result) {
|
||||
reward = result;
|
||||
dbPara.rewards = result.rewards;
|
||||
}
|
||||
}
|
||||
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 (!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, }
|
||||
// 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,
|
||||
});
|
||||
}
|
||||
|
||||
let passiveCards = 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, weightRecord: ele.weightRecord } }),
|
||||
groupStatus: chooseNum > 0 ? ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE : ROUGE_LIKE_CHOOSE_REWARD.CHOOSE,
|
||||
chooseNum
|
||||
});
|
||||
}
|
||||
|
||||
let holyCards = 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, weightRecord: ele.weightRecord } }),
|
||||
groupStatus: holyCardChooseNum > 0 ? ROUGE_LIKE_CHOOSE_REWARD.NOCHOOSE : ROUGE_LIKE_CHOOSE_REWARD.CHOOSE,
|
||||
chooseNum: holyCardChooseNum,
|
||||
});
|
||||
}
|
||||
|
||||
// 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 };
|
||||
}
|
||||
|
||||
// 处理挑战类型中 接下来X次选择特性卡时,可选择的卡片数量少1
|
||||
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 = 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 = 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 检测配置数据是否满足随机数量
|
||||
* @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 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, 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
weight += await getAddPassiveWeight(roleId, gameCode, type);
|
||||
if ((passiveCardData?.authorType || 0) == type) weight += ROUGELIKE.AUTHOR_ADD_RANDOM;
|
||||
|
||||
weightRecord.authorAddWeight = ROUGELIKE.AUTHOR_ADD_RANDOM;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
// if (!passiveCardData.passiveLabel || passiveCardData.passiveLabel.length == 0) continue;
|
||||
// for (let val of passiveCardData.passiveLabel) {
|
||||
// let labelNum = lableMap.get(val) || 0;
|
||||
// if (labelNum < ROUGELIKE.PASSIVE_LABLE_NUM || ROUGELIKE.PASSIVE_LABLE_NUM == 0) continue;
|
||||
|
||||
// weight += 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 [...result, ...randResult.map(cur => cur.dic)]
|
||||
}
|
||||
|
||||
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 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 });
|
||||
continue;
|
||||
};
|
||||
|
||||
let labelNum = lableMap.get(holyCardData.label) || 0;
|
||||
if (labelNum < ROUGELIKE.HOLY_LABLE_NUM || ROUGELIKE.HOLY_LABLE_NUM == 0) {
|
||||
newCards.push({ ...obj });
|
||||
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 randResult.map(cur => cur.dic);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取挑战关卡数据
|
||||
* @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;
|
||||
const minHp = rougeDamage.reduce((min, cur) => { return Math.min(min, cur.hp); }, Infinity);
|
||||
|
||||
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 && (rougeEffectTypeData.effectParam[1] || 0) > minHp) 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?: number } = {};
|
||||
const typeGradeData = gameData.rougeTypeGrade.get(type + '_' + grade);
|
||||
if (!typeGradeData) return result;
|
||||
const layerPlanData = gameData.rougeLayerPlan.get(typeGradeData.layerPlan + '_' + layer);
|
||||
if (!layerPlanData) return result;
|
||||
|
||||
const layerRewardData = gameData.rougeLayerRewardPlan.get(layerPlanData.rewardPlan + '_' + nodeType);
|
||||
if (!layerRewardData) return result;
|
||||
|
||||
return { ...layerRewardData, takeoutReward: layerPlanData.takeoutReward, spiritPlan: layerPlanData.spiritPlan };
|
||||
}
|
||||
|
||||
export function getRandomSpirit(spiritPlan: number) {
|
||||
let spiritId: number[] = [];
|
||||
const spiritPlanData = gameData.spiritPlan.get(spiritPlan);
|
||||
if (ROUGELIKE.SPIRIT_RANDOM_NUM == 0 || !spiritPlanData || spiritPlanData.length == 0) return spiritId;
|
||||
let random = getRandEelmWithWeightAndNum(spiritPlanData, ROUGELIKE.SPIRIT_RANDOM_NUM);
|
||||
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 maxNum = gameData.rougeScoreNum.num || 0;
|
||||
let refTime = getZeroPointOfTimeD(Date.now() - 86400000, SHOP_REFRESH_TYPE.WEEKLY);
|
||||
let allRewards = await RougelikeScoreModel.findByReceiveNum(refTime, maxNum);
|
||||
let _ids: string[] = [];
|
||||
for (let { roleId, received, _id, score } of allRewards) {
|
||||
let goods: RewardInter[] = [];
|
||||
for (let [index, { reward, score: targetScore }] of gameData.rougeScoreReward) {
|
||||
if (score >= targetScore && !received.includes(index)) goods.push(...reward);
|
||||
}
|
||||
await sendMailByContent(MAIL_TYPE.ROUGE_SCORE_REPAIRE, roleId, { goods });
|
||||
_ids.push(_id);
|
||||
}
|
||||
await RougelikeScoreModel.receiveAll(_ids, maxNum + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最大血量
|
||||
* @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) {
|
||||
let dbCharas = await RougelikeCharaModel.findByGameCode(gameCode);
|
||||
if (dbCharas.length == 0) return [];
|
||||
|
||||
let result: RougelikeCharaType[] = [];
|
||||
for (let val of dbCharas) {
|
||||
let tempMaxHp = await getMaxHp(roleId, gameCode, val.charaId, type, grade);
|
||||
if (tempMaxHp == val.maxHp) continue;
|
||||
val.maxHp = 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)
|
||||
};
|
||||
}
|
||||
121
game-server/app/services/battle/rougeTechService.ts
Normal file
121
game-server/app/services/battle/rougeTechService.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import { Circle, RougelikeTechModel, RougelikeTechType } from '../../db/RougelikeTech';
|
||||
import { gameData } from '../../pubUtils/data';
|
||||
import { HeroModel } from '../../db/Hero';
|
||||
import { compareNumberArray } from '../../pubUtils/util';
|
||||
|
||||
/**
|
||||
* 首页获得的科技树数据
|
||||
* @param techData
|
||||
* @returns
|
||||
*/
|
||||
export async function getTechData(roleId: string) {
|
||||
let techData = await RougelikeTechModel.findByRoleId(roleId);
|
||||
if(!techData) return { techTrees: [], sumTechScore: 0 };
|
||||
let { unlockedTech = [], circles = [] } = techData;
|
||||
circles = await calCircleCe(roleId, unlockedTech, circles);
|
||||
let techTrees = unlockedTech.map(techId => getSingleTechData(techId, circles));
|
||||
return {
|
||||
techTrees
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从首页重新进入,重新计算他的战力
|
||||
* @param roleId
|
||||
* @param circles
|
||||
* @returns
|
||||
*/
|
||||
async function calCircleCe(roleId: string, unlockedTech: number[], circles: Circle[]) {
|
||||
let hids: number[] = circles.map(circle => circle.hid).filter(hid => hid > 0);
|
||||
if(hids.length <= 0) return circles
|
||||
let heroes = await HeroModel.findByHidRange(hids, roleId);
|
||||
let newCircle = circles.map(circle => {
|
||||
if(circle.hid == 0) return circle;
|
||||
let hero = heroes.find(cur => cur.hid == circle.hid);
|
||||
return { ...circle, ce: hero?.ce||0 }
|
||||
});
|
||||
let effectIds = getTechEffectIds(unlockedTech, circles)
|
||||
await RougelikeTechModel.updateCircle(roleId, newCircle, effectIds);
|
||||
return newCircle;
|
||||
}
|
||||
|
||||
export async function updateEffectId(techData: RougelikeTechType) {
|
||||
let effectIds = getTechEffectIdsByData(techData);
|
||||
if(!compareNumberArray(effectIds, techData.effectIds||[])) {
|
||||
await RougelikeTechModel.updateEffectId(techData.roleId, effectIds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理后单个科技点的数据
|
||||
* @param techData
|
||||
* @param techId
|
||||
* @returns
|
||||
*/
|
||||
export function getCurTechData(techData: RougelikeTechType, techId: number) {
|
||||
if(!techData || !techId) return { curTechTree: { techId, circles: [] } }
|
||||
let { circles = [] } = techData;
|
||||
return {
|
||||
curTechTree: getSingleTechData(techId, circles)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单片科技树数据
|
||||
* @param techId
|
||||
* @param circles
|
||||
* @returns
|
||||
*/
|
||||
function getSingleTechData(techId: number, circles: Circle[]) {
|
||||
let result: { circleId: number, hid: number, ce: number }[] = [];
|
||||
for(let { techId: curTechId, hid, circleId, ce } of circles) {
|
||||
if(curTechId == techId) result.push({ hid, circleId, ce });
|
||||
}
|
||||
return { techId, circles: result };
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查前置科技点是否解锁
|
||||
* @param techId
|
||||
* @param unlockedTech
|
||||
* @returns
|
||||
*/
|
||||
export function checkPreRougeTech(techId: number, unlockedTech: number[]) {
|
||||
let dicTech = gameData.rougeTech.get(techId);
|
||||
let preTechId = dicTech?.preTechId||[];
|
||||
for(let techId of preTechId) {
|
||||
if(!unlockedTech.includes(techId)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取科技树带来的type加成
|
||||
* @param roleId
|
||||
* @returns [{ type: number, param: number[] }]
|
||||
*/
|
||||
export function getTechEffectIdsByData(techData: RougelikeTechType) {
|
||||
if(!techData) return [];
|
||||
return getTechEffectIds(techData.unlockedTech, techData.circles);
|
||||
}
|
||||
|
||||
export function getTechEffectIds(unlockedTech: number[], circles: Circle[]) {
|
||||
let result: number[] = [];
|
||||
let techMap = new Map<number, number>();
|
||||
for(let techId of unlockedTech) {
|
||||
techMap.set(techId, 0);
|
||||
}
|
||||
for(let { techId, ce } of circles) {
|
||||
let oldCe = techMap.get(techId)||0;
|
||||
techMap.set(techId, oldCe + ce);
|
||||
}
|
||||
for(let [techId, ce] of techMap) {
|
||||
let levelDatas = gameData.rougeTechLevel.get(techId)||[];
|
||||
let effectIds: number[] = [];
|
||||
for(let { techEffectIds, ce: targetCe } of levelDatas) {
|
||||
if(ce >= targetCe) effectIds = techEffectIds;
|
||||
}
|
||||
result.push(...effectIds);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -866,6 +866,167 @@ export function checkRouteParam(route: string, msg: any) {
|
||||
if (!checkNaturalNumbers(msg.id)) return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case "battle.rougeHandler.getData":
|
||||
break;
|
||||
case "battle.rougeHandler.getGame":
|
||||
break;
|
||||
|
||||
case "battle.rougeHandler.getInitCharaCard":
|
||||
{
|
||||
let { type, grade } = msg
|
||||
if (!checkNaturalNumbers(type, grade)) return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case "battle.rougeHandler.startGame":
|
||||
{
|
||||
let { gameCode, authorType } = msg;
|
||||
if (!checkNaturalStrings(gameCode)) return false;
|
||||
if (!checkNaturalNumbers(authorType)) return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case "battle.rougeHandler.gameEnd":
|
||||
{
|
||||
let { gameCode } = msg;
|
||||
if (!checkNaturalStrings(gameCode)) return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case "battle.rougeHandler.chooseNode":
|
||||
{
|
||||
let { gameCode, layer, detailCode } = msg;
|
||||
if (!checkNaturalStrings(gameCode, detailCode)) return false;
|
||||
if (!checkNaturalNumbers(layer)) return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case "battle.rougeHandler.checkBattle":
|
||||
{
|
||||
let { gameCode, detailCode, warId, charaCodes } = msg;
|
||||
if (!checkNaturalStrings(gameCode, detailCode)) return false;
|
||||
if (!checkNaturalNumbers(warId)) return false;
|
||||
if (!checkIsDuplicateStrings(charaCodes)) return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case "battle.rougeHandler.battleEnd":
|
||||
{
|
||||
let { gameCode, detailCode, battleCode, warId, status, round, rougeDamage, isAp, isRound } = msg;
|
||||
if (!checkNaturalStrings(gameCode, detailCode, battleCode)) return false;
|
||||
if (!checkNaturalNumbers(warId, round, status)) return false;
|
||||
if (!checkBooleanIfExist(isAp, isRound)) return false;
|
||||
if (!isArray(rougeDamage) || rougeDamage.length == 0) return false;
|
||||
let charaCodes: string[] = [];
|
||||
for (let { charaCode } of rougeDamage) {
|
||||
if (!charaCode) return false;
|
||||
charaCodes.push(charaCode);
|
||||
}
|
||||
if (!checkIsDuplicateStrings(charaCodes)) return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case "battle.rougeHandler.chooseReward":
|
||||
{
|
||||
let { gameCode, detailCode, groupIndex, optionIndexs } = msg;
|
||||
if (!checkNaturalStrings(gameCode, detailCode)) return false;
|
||||
if (!checkNaturalNumbers(groupIndex)) return false;
|
||||
if (!checkIsDuplicateNumbers(optionIndexs)) return false;
|
||||
break;
|
||||
}
|
||||
case "battle.rougeHandler.reRandomReward":
|
||||
{
|
||||
let { gameCode, detailCode, rewardType } = msg;
|
||||
if (!checkNaturalStrings(gameCode, detailCode)) return false;
|
||||
if (!checkNaturalNumbers(rewardType)) return false;
|
||||
break;
|
||||
}
|
||||
case "battle.rougeHandler.shopBuy":
|
||||
{
|
||||
let { gameCode, detailCode, optionIndex } = msg;
|
||||
if (!checkNaturalStrings(gameCode, detailCode)) return false;
|
||||
if (!checkNaturalNumbers(optionIndex)) return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case "battle.rougeHandler.chooseOption":
|
||||
{
|
||||
let { gameCode, detailCode, eventOptions } = msg;
|
||||
if (!checkNaturalStrings(gameCode, detailCode)) return false;
|
||||
if (!checkIsDuplicateNumbers(eventOptions)) return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case "battle.rougeHandler.recovery":
|
||||
{
|
||||
let { gameCode, detailCode } = msg;
|
||||
if (!checkNaturalStrings(gameCode, detailCode)) return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case "battle.rougeHandler.trainCard":
|
||||
{
|
||||
let { gameCode, detailCode, cardCode } = msg;
|
||||
if (!checkNaturalStrings(gameCode, detailCode, cardCode)) return false;
|
||||
break;
|
||||
}
|
||||
case "battle.rougeHandler.nodeEnd":
|
||||
{
|
||||
let { gameCode, detailCode, } = msg;
|
||||
if (!checkNaturalStrings(gameCode, detailCode)) return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case "battle.rougeHandler.putOnOrOffCard":
|
||||
{
|
||||
let { gameCode, charaCode, cards } = msg;
|
||||
if (!checkNaturalStrings(gameCode, charaCode)) return false;
|
||||
let cardCodes: string[] = [], indexs: number[] = [];
|
||||
for (let { index, cardCode } of cards) {
|
||||
indexs.push(index);
|
||||
if (cardCode) cardCodes.push(cardCode);
|
||||
}
|
||||
if (!checkIsDuplicateNumbers(indexs)) return false;
|
||||
if (!checkIsDuplicateStrings(cardCodes)) return false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "battle.rougeHandler.exchangeChara":
|
||||
{
|
||||
let { gameCode, oldCharaCode, newCharaCode } = msg;
|
||||
if (!checkNaturalStrings(gameCode, oldCharaCode, newCharaCode)) return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case "battle.rougeHandler.unlockTech":
|
||||
{
|
||||
if (!checkNaturalNumbers(msg.techId)) return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case "battle.rougeHandler.putOnCircle":
|
||||
{
|
||||
if (!checkNaturalNumbers(msg.circleId, msg.hid)) return false;
|
||||
break;
|
||||
}
|
||||
case "battle.rougeHandler.chooseSkillCard":
|
||||
{
|
||||
if (!checkNaturalStrings(msg.gameCode, msg.charaCode)) return false;
|
||||
if (!checkNaturalNumbers(msg.skillType, msg.id)) return false;
|
||||
break;
|
||||
}
|
||||
case "battle.rougeHandler.receiveCollectionReward":
|
||||
{
|
||||
if (!checkNaturalNumbers(msg.type, msg.id)) return false;
|
||||
break;
|
||||
}
|
||||
case "battle.rougeHandler.receiveScore":
|
||||
{
|
||||
if (!checkNaturalNumbers(msg.index)) return false;
|
||||
break;
|
||||
}
|
||||
case "chat.chatHandler.sendGroupMessage":
|
||||
{
|
||||
let { channel, type, content, targetRoleId, targetMsgCode } = msg;
|
||||
@@ -2223,11 +2384,17 @@ export function checkRouteParam(route: string, msg: any) {
|
||||
case "activity.bindPhoneHandler.debugSetGiftCodeStatus":
|
||||
case 'activity.rebateHandler.debugSetRebate':
|
||||
case 'activity.newHeroGKHandler.debugResetGK':
|
||||
|
||||
case 'battle.rougeHandler.debugClearTech':
|
||||
case "battle.rougeHandler.debugAddCard":
|
||||
case "battle.rougeHandler.debugAddScore":
|
||||
case "battle.rougeHandler.debugRepaireScoreReward":
|
||||
case "battle.rougeHandler.debugAddCollection":
|
||||
{
|
||||
if (msg.magicWord !== DEBUG_MAGIC_WORD || !isDevelopEnv()) return false;
|
||||
break;
|
||||
}
|
||||
case "battle.rougeHandler.debugAddLimitId":
|
||||
|
||||
case "comBattle.comBattleHandler.getTeams":
|
||||
case "comBattle.comBattleHandler.teammateReady":
|
||||
case "comBattle.comBattleHandler.battleEnd":
|
||||
@@ -2363,4 +2530,28 @@ function checkCombo(combo: { groupId: number, levelList: number[] }[]) {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkIsDuplicateNumbers(array: number[]) {
|
||||
const seen = new Set();
|
||||
for (const item of array) {
|
||||
if (!isNumber(item)) return false;
|
||||
if (seen.has(item)) {
|
||||
return false; // 发现重复元素
|
||||
}
|
||||
seen.add(item);
|
||||
}
|
||||
return true; // 没有重复元素
|
||||
}
|
||||
|
||||
function checkIsDuplicateStrings(array: string[]) {
|
||||
const seen = new Set();
|
||||
for (const item of array) {
|
||||
if (!isString(item)) return false;
|
||||
if (seen.has(item)) {
|
||||
return false; // 发现重复元素
|
||||
}
|
||||
seen.add(item);
|
||||
}
|
||||
return true; // 没有重复元素
|
||||
}
|
||||
@@ -54,6 +54,7 @@ import { LinkModel } from '../db/Link';
|
||||
import { getHiddenData } from './memoryCache/hiddenData';
|
||||
import { AuthorBookModel } from '../db/AuthorBook';
|
||||
import { gameData } from '../pubUtils/data';
|
||||
import { getRougeData } from './battle/rougeService';
|
||||
|
||||
/**
|
||||
* init: 初始的时候是否推送 true-推 false-不推
|
||||
@@ -89,6 +90,7 @@ const modules = [
|
||||
{ id: 26, type: 'survey', init: false, refresh: true, guild: false },
|
||||
{ id: 27, type: 'ladder', init: false, refresh: true, guild: false },
|
||||
{ id: 28, type: 'hiddenData', init: true, refresh: true, guild: false },
|
||||
{ id: 29, type: 'rouge', init: true, refresh: true, guild: false },
|
||||
]
|
||||
|
||||
export async function pushData(hasInit: boolean, role: RoleType, session: FrontendOrBackendSession, pushType: 'entry' | 'refresh' = 'entry') {
|
||||
@@ -229,6 +231,8 @@ export async function getModuleData(type: string, data: { role: RoleType, sessio
|
||||
return await getLadderData(role.roleId, false);
|
||||
case 'hiddenData':
|
||||
return getHiddenData();
|
||||
case 'rouge':
|
||||
return await getRougeData(role.roleId);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import { pick } from "underscore";
|
||||
import { memberJoinGuildToLeague } from "./gvg/gvgTeamService";
|
||||
import { isToday } from '../pubUtils/timeUtil';
|
||||
import moment = require("moment");
|
||||
import { repaireSendScoreReward } from "./battle/rougeService";
|
||||
|
||||
export async function getMyGuildInfo(roleId: string, sid: string, userGuild: UserGuildType, guild: GuildType, serverId: number, session: FrontendOrBackendSession) {
|
||||
|
||||
@@ -433,6 +434,10 @@ export async function settleGuildWeekly() {
|
||||
await initSingleRank(REDIS_KEY.GUILD_ACTIVE_RANK);
|
||||
await initSingleRank(REDIS_KEY.GUILD_LV_RANK);
|
||||
let curSeasonNum = await CounterModel.getCounter(COUNTER.PVP_SEASON_NUM);
|
||||
|
||||
// 发送肉鸽奖励
|
||||
await repaireSendScoreReward();
|
||||
|
||||
console.log('————— settleGuildWeekly结束 —————');
|
||||
}
|
||||
|
||||
|
||||
@@ -622,6 +622,10 @@ export function checkVoucherId(id: number) {
|
||||
return id == voucher || id == voucherCoin;
|
||||
}
|
||||
|
||||
export function getRougeTechScoreObject(count: number) {
|
||||
return { id: CURRENCY_BY_TYPE.get(CURRENCY_TYPE.ROUGE_TECH)||0, count };
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回 解锁头像/相框
|
||||
* @param conditions 解锁条件
|
||||
|
||||
178
game-server/test/rouge.test.ts
Normal file
178
game-server/test/rouge.test.ts
Normal file
@@ -0,0 +1,178 @@
|
||||
import { Client } from './Client';
|
||||
import 'mocha';
|
||||
import { PinusWSClient } from 'pinus-robot-plugin';
|
||||
import { expect } from 'chai';
|
||||
import { checkBattleGoods, checkDisplayItems, checkSuccessResponse, checkTimeStamp, checkWarJson } from './CheckPatten';
|
||||
import { DEBUG_MAGIC_WORD } from '../app/consts';
|
||||
import { getRandSingleEelm } from './pureUtil';
|
||||
import * as util from 'util';
|
||||
|
||||
|
||||
const NORMAIL_BATTLEID = 101;
|
||||
const DUNGEON_BATTLEID = 5001;
|
||||
|
||||
describe('稷下学宫测试', function () {
|
||||
let pinusClient: PinusWSClient;
|
||||
let roleInfo;
|
||||
|
||||
before(function (done) {
|
||||
const c = new Client();
|
||||
const timer = setInterval(() => {
|
||||
if (c.client) {
|
||||
pinusClient = c.client;
|
||||
roleInfo = c.roleInfo;
|
||||
clearInterval(timer);
|
||||
done();
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
|
||||
after(function (done) {
|
||||
pinusClient.disconnect();
|
||||
// disconnect 后等待 500ms,供服务器清理环境、退出频道等
|
||||
setTimeout(() => {
|
||||
done();
|
||||
}, 500);
|
||||
});
|
||||
|
||||
|
||||
|
||||
// it('getData', function (done) {
|
||||
|
||||
// pinusClient.request('battle.rougeHandler.getData', {}, (res) => {
|
||||
// console.log("res:", res)
|
||||
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
|
||||
// it('getGame', function (done) {
|
||||
|
||||
// pinusClient.request('battle.rougeHandler.getGame', {}, (res) => {
|
||||
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
|
||||
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
|
||||
it('getInitCharaCard', function (done) {
|
||||
|
||||
pinusClient.request('battle.rougeHandler.getInitCharaCard', { type: 2, grade: 1 }, (res) => {
|
||||
console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
|
||||
done();
|
||||
});
|
||||
});
|
||||
// it('startGame', function (done) {
|
||||
|
||||
// pinusClient.request('battle.rougeHandler.startGame', { gameCode: 'MkSLT1HY', authorType: 1 }, (res) => {
|
||||
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
|
||||
|
||||
// it('chooseNode', function (done) {
|
||||
|
||||
// pinusClient.request('battle.rougeHandler.chooseNode', { gameCode: '4EPoEyML', layer: 2, detailCode: 'gREeb6Ku' }, (res) => {
|
||||
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
|
||||
// it('gameEnd', function (done) {
|
||||
|
||||
// pinusClient.request('battle.rougeHandler.gameEnd', { gameCode: 'voe64495' }, (res) => {
|
||||
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
|
||||
// it('shopBuy', function (done) {
|
||||
|
||||
// pinusClient.request('battle.rougeHandler.shopBuy', { gameCode: '5b8ioYN3', detailCode: '6ZhZYDXk', optionIndex: 1 }, (res) => {
|
||||
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
|
||||
|
||||
// it('chooseReward', function (done) {
|
||||
|
||||
// pinusClient.request('battle.rougeHandler.chooseReward', { gameCode: '5b8ioYN3', detailCode: 'Jv5JEneT', groupIndex: 1, optionIndexs: [0] }, (res) => {
|
||||
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
|
||||
|
||||
// it('checkBattle', function (done) {
|
||||
|
||||
// pinusClient.request('battle.rougeHandler.checkBattle', { gameCode: '4EPoEyML', detailCode: 'gREeb6Ku' ,warId:107, charaCodes:['D41jpqe6']}, (res) => {
|
||||
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
|
||||
|
||||
// it('battleEnd', function (done) {
|
||||
// pinusClient.request('battle.rougeHandler.battleEnd', { gameCode: '5b8ioYN3', detailCode: 'pEu6Wetd', warId: 102, battleCode: 'R3FobvR2', status: 1, round: 5, rougeDamage: [{ charaCode: 'WaAhKQu6',hp:1, ap:1, shield:1 }] }, (res) => {
|
||||
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
|
||||
|
||||
// it('nodeEnd', function (done) {
|
||||
// pinusClient.request('battle.rougeHandler.nodeEnd', { gameCode: 'MkSLT1HY', detailCode: 'fve9s7ej' }, (res) => {
|
||||
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
|
||||
// done();``
|
||||
// });
|
||||
// });
|
||||
|
||||
|
||||
// it('chooseOption', function (done) {
|
||||
// pinusClient.request('battle.rougeHandler.chooseOption', { gameCode: '4EPoEyML', detailCode: 'gREeb6Ku', eventOptions:[1,4,10, 13] }, (res) => {
|
||||
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
|
||||
|
||||
// it('trainCard', function (done) {
|
||||
// pinusClient.request('battle.rougeHandler.trainCard', { gameCode: '4EPoEyML', detailCode: 'gREeb6Ku', cardCode:'GB4AtwlA' }, (res) => {
|
||||
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
|
||||
// it('recovery', function (done) {
|
||||
// pinusClient.request('battle.rougeHandler.recovery', { gameCode: '4EPoEyML', detailCode: 'gREeb6Ku' }, (res) => {
|
||||
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
|
||||
// index: NumberInt("0"),
|
||||
// cardCode: "ShNTcBGa",
|
||||
// cardId: NumberInt("10003")
|
||||
|
||||
// it('putOnOrOffCard', function (done) {
|
||||
// pinusClient.request('battle.rougeHandler.putOnOrOffCard', { gameCode: '4EPoEyML', charaCode: 'GLYk8Q1C', cards: [{ index: 0, cardCode: "", }] }, (res) => {
|
||||
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
|
||||
|
||||
|
||||
// for (let id = 20001; id <= 20034; id++) {
|
||||
// it('debugAddCard', function (done) {
|
||||
// pinusClient.request('battle.rougeHandler.debugAddCard', { tye: 3, id }, (res) => {
|
||||
// console.log('-x-x--x-x-x-x-x-x-x-x-x- res', util.inspect(res, { depth: null }));
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user